I have some collision detection involving lines of arbitrary angles that I can't know ahead of time. I've set up my code to treat them as the form y = mx + b and whenever I create a horizontal line all of the fields come out as NaN. My question is: What operations in AS3 can cause NaN to be returned. The thing that comes to mind is that a perfectly vertical line will have a slope of Number.POSITIVE_INFINITY and I imagine that that could cause potential errors. It shouldn't be on a horizontal line, but logic problems happen. The point is, what causes NaN to be returned in AS3?
package {
import flash.display.Sprite
public class Line extends Sprite{
var x1:Number, x2:Number, y1:Number, y2:Number;
var m:Number, b:Number; //y = mx + b
public function Line(x1C:Number, y1C:Number, x2C:Number, y2C:Number){
x1 = x1C;
x2 = x2C;
y1 = y1C;
y2 = y2C;
if(x2 - x1 == 0)
m = Number.POSITIVE_INFINITY;
else if(y2 - y1 == 0)
m = 0;
else
m = (y2 - y1) / (x2 - x1); //these calculations could be off....
b = y1 - (m * x1);
this.graphics.moveTo(x1, y1);
}
}
}
Your code may produce a NaN right here:
b = y1 - (m * x1);
if m is an infinity, and x1 is 0, then multiplying it should result in NaN and this is true not only for AS3.
I would recommend you to never use a line equation in a slope-intercept form, that you're using (y = Ax + B), cause you cannot define a vertical line this way. Always use a general form: Ax + By + C = 0.
Do not compare floats with ==, always compare floating-point numbers with epsilon. might help. You can have problems in your code if x2 is almost equal to x1.
If you declare a Number and don't assign a value, it will be NaN.
for example :
var speed:Number;
trace(speed); // NaN
unlike and int which defaults to 0;
var speed:int;
trace(speed); // 0
The documentation of the global isNan() function gives some examples:
0 divided by 0: 0/0
Square root of a negative number: Math.sqrt(-1)
Arcsine of number greater than 1 or less than 0: Math.asin(2)
String that cannot be converted to Number "5a": [when parsing it]
Also 1 * someObject or 1 + someUndefinedNumber will evaluate to NaN
Related
function dy = g2(x, y)
dy = -0.1 * y;
ym = ode45('g2', 0, 5, 4)
end
I receive the following message:
g2(0.5,4)
Error using odearguments (line 83)
The last entry in tspan must be different from the first entry.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options,
varargin);
Error in g2 (line 9)
ym = ode45('g2', 0, 5, 4);
I might add that this one works well:
function dy = g1(x, y)
dy = 3 * x ^ 2;
ym = ode45('g1', 2, 4, 0.5)
end
I am not understanding what you are trying to do, however I will give you an example.
Usually your functions are defined at the bottom and you call ODE like that :
t=linspace(0,7,1000);
initial_value_for_y = 0;
[t,y] = ode45(#myfunction, t, initial_value_for_y);
function dy = myfunction(t, y)
dy = exp(-t);
end
so in the first line we define a vector for time using linspace.
at the second line we set the initial value of our integration
the third line calls ODE45 with a function handle, the time span and an initial value
the rest of the lines are for the definition of your function
My concern for now is that you question is not clear. Instead of asking "why isn't it working", tell us what you are trying to achieve.
Question
Trying to follow Gradients, Gradient Plots and Tangent Planes.
The gradient vectors of (X^2 + Y^2) do not show up correctly in Octave 4.2.0 on Windows. With the code, expected the gradients of a circle diverge from center outwards. However the actual is diagonal.
Please assist to understand what is wrong.
syms x y
f1 = x^2 + y^2;
gradf1 = jacobian(f1,[x,y]);
f1fun = function_handle(f1);
f1xfun = function_handle(gradf1(1));
f1yfun = function_handle(gradf1(2));
[xx, yy] = meshgrid(-1:.1:1,-1:.1:1);
hold on
contour(xx, yy, f1fun(xx, yy), 10)
quiver(xx, yy, f1xfun(xx, yy), f1yfun(xx, yy), 0.5)
axis equal tight
hold off
Expected
Actual
When you perform:
f1xfun = function_handle(gradf1(1));
f1yfun = function_handle(gradf1(2));
The output is:
f1xfun =
#(x) 2 * x % note: single-argument function
f1yfun =
#(y) 2 * y % note: single-argument function
that is AS OPPOSED TO
f1xfun =
#(x,y) 2 * x % two-argument function
f1yfun =
#(x,y) 2 * y % two-argument function
which is what you seem to think was happening. (i.e. the resulting functions actually only take a single input, not both x and y).
Therefore later on when you call f1yfun with two inputs, the second input (i.e. y) is simply silently discarded, and you are essentially calculating 2*x in both axes, hence the diagonal arrows.
tl;dr Your call to quiver should be:
quiver(xx, yy, f1xfun(xx), f1yfun(yy), 0.5);
I think you have a bug in your code and the call to quiver should be
quiver(xx, yy, f1xfun(xx), f1yfun(yy), 0.5)
which then gives (with colormap("jet"))
Suppose I generate a plot in the following way:
x=linspace(-2,2,50);
y=linspace(-2,2,50);
[xx,yy]=meshgrid(x,y);
mesh(xx,yy,4-(xx.^2+yy.^2))
Is there anyway to impose an inequality such that I only plot values where x < y?
One possible hack:
x = y = linspace(-2, 2, 50);
[xx, yy] = meshgrid(x, y);
cond = xx < yy;
xx = xx .* cond;
yy = yy .* cond;
mesh(xx, yy, 4-(xx.^2+yy.^2));
Strictly speaking, this will move all coordinate pairs (x,y) that do not meet the criterion x < y from their current location to the origin of the plot:
This is fairly similar to another answer already provided, but might help with the "strange aberration" you mention that answer caused in your data. Basically create a mask that is 1 where xx < yy, and 0 otherwise:
mask = xx < yy;
Then apply this mask to your xx and yy meshes:
xx_mask = xx.*mask;
yy_mask = yy.*mask;
And only then do you plot your results:
mesh(xx_mask, yy_mask, 4-(xx_mask.^2 + yy_mask.^2));
Basically the only difference is that this way you are setting the unwanted values in your xx and yy matrices to zero before you square them and plot them.
Note, this was tested with MATLAB instead of Octave, but they should give similar results.
Solutions above are only good if the point (0,0) is part of your chart. Otherwise it adds the point to the chart and then tries to plot, creating strange effect, like below.
[![x=linspace(1,3,50);
y=linspace(1,3,50);
\[xx,yy\]=meshgrid(x,y);
mask = xx < yy;
xx_mask = xx.*mask;
yy_mask = yy.*mask;
mesh(xx_mask, yy_mask, 4-(xx_mask.^2 + yy_mask.^2));][1]][1]
What can be alternatively be done is to leave x and y axes values as is and only convert z axis values to NA inthe range not satisfying the condition.
x=linspace(1,3,50);
y=linspace(1,3,50);
[xx,yy]=meshgrid(x,y);
mask = xx < yy;
function result = applyCondition(cond)
result = ifelse(cond, 0, NA);
endfunction
zz = 4-(xx.^2 + yy.^2);
mesh(xx, yy, zz + arrayfun(#applyCondition, mask));
This solution works in all cases, regardless of (0,0) being part of you chart of not.
When given 0,0 to 0,5, the y velocity becomes that number and breaks my code. I know I must have done something wrong as I just copy and pasted code (since I am horrible at maths)..
This is how I calculate the numbers:
var radian = Math.atan2(listOfNodes[j].y - listOfNodes[i].y,listOfNodes[j].x - listOfNodes[i].x);
var vy = Math.cos(radian);
var vx = Math.sin(radian);
Thanks
There i am assuming the velocity vector is FROM 0,0 TO 0,5. And 0,0 is i and 0,5 is j.
In that case the velocity vector is only along y and the y component should be 5 and x component 0. It is coming as opposite because,
cos(radian) whould be x velocity component and sin(radian) the y compunent.
And the number 6.123031769111886E-17 is actually returned in place of 0.
Look at the following figure:
Also as can be seen from the figure you do not need the trigonometric computations at all.
You can simply get the x and y components as follows:
// y2 - y1
var vy = listOfNodes[j].y - listOfNodes[i].y;
// x2 - x1
var vx = listOfNodes[j].x - listOfNodes[i].x;
This will avoid the floating point inaccuracy caused by the trig finctions due to which you are seeing 6.123031769111886E-17 instead of 0.
You only need to use atan2 if you actually need the angle θ in your code.
Update:
Well if you need only unit (normalized) vector's components you can divide the vx and vy with the length of the original vector. Like this:
// y2 - y1
var vy = listOfNodes[j].y - listOfNodes[i].y;
// x2 - x1
var vx = listOfNodes[j].x - listOfNodes[i].x;
// vector magnitude
var mag = Math.sqrt(vx * vx + vy * vy);
// get unit vector components
vy /= mag;
vx /= mag;
Using the above you will get the exactly the same results as you are getting from trig sin and cos functions.
But if you still need to use the original code and want to make 6.12...E-17 compare to 0, you can use the epsilon technique for comparing floats. So you can compare any value within epsilon's range from 0, using flllowing code:
function floatCompare(a:Number, b:Number, epsilon:Number):Boolean{
return (a >= (b - epsilon) && a <= (b + epsilon));
}
// To check for zero use this code, here i'm using 0.0001 as epsilon
if(floatCompare(vx, 0, 0.0001)){
// code here
}
So any deviation in the range of [b-epsilon, b+epsilon] would successfully compare to b. This is essential in case of floating point arithmetic.
I'm implementing the system in this paper and I've come a little unstuck correctly implementing the radial tensor field.
All tensors in this system are of the form given on page 3, section 4
R [ cos(2t), sin(2t); sin(2t), -cos(2t) ]
The radial tensor field is defined as:
R [ yy - xx, -2xy; -2xy, -(yy-xx) ]
In my system I'm only storing R and Theta, since I can calculate the tensor based off just that information. This means I need to calculate R and Theta for the radial tensor. Unfortunately, my attempts at this have failed. Although it looks correct, my solution fails in the top left and bottom right quadrants.
Addendum: Following on from discussion in the comments about the image of the system not working, I'll put some hard numbers here too.
The entire tensor field is 800x480, the center point is at { 400, 240 }, and we're using the standard graphics coordinate system with a negative y axis (ie. origin in the top left).
At { 400, 240 }, the tensor is R = 0, T = 0
At { 200, 120 }, the tensor is R = 2.95936E+9, T = 2.111216
At { 600, 120 }, the tensor is R = 2.95936E+9, T = 1.03037679
I can easily sample any more points which you think may help.
The code I'm using to calculate values is:
float x = i - center.X;
float xSqr = x * x;
float y = j - center.Y;
float ySqr = y * y;
float r = (float)Math.Pow(xSqr + ySqr, 2);
float theta = (float)Math.Atan2((-2 * x * y), (ySqr - xSqr)) / 2;
if (theta < 0)
theta += MathHelper.Pi;
Evidently you are comparing formulas (1) and (2) of the paper. Note the scalar multiple l = || (u_x,u_y) || in formula (1), and identify that with R early in the section. This factor is implicit in formula (2), so to make them match we have to factor R out.
Formula (2) works with an offset from the "center" (x0,y0) of the radial map:
x = xp - x0
y = yp - y0
to form the given 2x2 matrix:
y^2 - x^2 -2xy
-2xy -(y^2 - x^2)
We need to factor out a scalar R from this matrix to get a traceless orthogonal 2x2 matrix as in formula (1):
cos(2t) sin(2t)
sin(2t) -cos(2t)
Since cos^2(2t) + sin^2(2t) = 1 the factor R can be identified as:
R = (y^2 - x^2)^2 + (-2xy)^2 = (x^2 + y^2)^2
leaving a traceless orthogonal 2x2 matrix:
C S
S -C
from which the angle 'tan(2t) = S/C` can be extracted by an inverse trig function.
Well, almost. As belisarius warns, we need to check that angle t is in the correct quadrant. The authors of the paper write at the beginning of Sec. 4 that their "t" (which refers to the tensor) depends on R >= 0 and theta (your t) lying in [0,2pi) according to the formula R [ cos(2t), sin(2t); sin(2t) -cos(2t) ].
Since sine and cosine have period 2pi, t (theta) is only uniquely determined up to an interval of length pi. I suspect the authors meant to write either that 2t lies in [0,2pi) or more simply that t lies in [0,pi). belisarius suggestion to use "the atan2 equivalent" will avoid any division by zero. We may (if the function returns a negative value) need to add pi so that t >= 0. This amounts to adding 2pi to 2t, so it doesn't affect the signs of the entries in the traceless orthogonal matrix (since 'R >= 0` the pattern of signs should agree in formulas (1) and (2) ).