AS3 - Y Velocity 6.123031769111886E-17 - actionscript-3

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.

Related

how do you reflect a vector over another vector?

I'm using AS3 to program some collision detection for a flash game and am having trouble figuring out how to bounce a ball off of a line. I keep track of a vector that represents the ball's 2D velocity and I'm trying to reflect it over the vector that is perpendicular to the line that the ball's colliding with (aka the normal). My problem is that I don't know how to figure out the new vector (that's reflected over the normal). I figured that you can use Math.atan2 to find the difference between the normal and the ball's vector but I'm not sure how to expand that to solve my problem.
Vector algebra - You want the "bounce" vector:
vec1 is the ball's motion vector and vec2 is the surface/line vector:
// 1. Find the dot product of vec1 and vec2
// Note: dx and dy are vx and vy divided over the length of the vector (magnitude)
var dpA:Number = vec1.vx * vec2.dx + vec1.vy * vec2.dy;
// 2. Project vec1 over vec2
var prA_vx:Number = dpA * vec2.dx;
var prA_vy:Number = dpA * vec2.dy;
// 3. Find the dot product of vec1 and vec2's normal
// (left or right normal depending on line's direction, let's say left)
var dpB:Number = vec1.vx * vec2.leftNormal.dx + vec1.vy * vec2.leftNormal.dy;
// 4. Project vec1 over vec2's left normal
var prB_vx:Number = dpB * vec2.leftNormal.dx;
var prB_vy:Number = dpB * vec2.leftNormal.dy;
// 5. Add the first projection prA to the reverse of the second -prB
var new_vx:Number = prA_vx - prB_vx;
var new_vy:Number = prA_vy - prB_vy;
Assign those velocities to your ball's motion vector and let it bounce.
PS:
vec.leftNormal --> vx = vec.vy; vy = -vec.vx;
vec.rightNormal --> vx = -vec.vy; vy = vec.vx;
The mirror reflection of any vector v from a line/(hyper-)surface with normal n in any dimension can be computed using projection tensors. The parallel projection of v on n is: v|| = (v . n) n = v . nn. Here nn is the outer (or tensor) product of the normal with itself. In Cartesian coordinates it is a matrix with elements: nn[i,j] = n[i]*n[j]. The perpendicular projection is just the difference between the original vector and its parallel projection: v - v||. When the vector is reflected, its parallel projection is reversed while the perpendicular projection is retained. So the reflected vector is:
v' = -v|| + (v - v||) = v - 2 v|| = v . (I - 2 nn) = v . R( n ), where
R( n ) = I - 2 nn
(I is the identity tensor which in Cartesian coordinates is simply the diagonal identity matrix diag(1))
R is called the reflection tensor. In Cartesian coordinates it is a real symmetric matrix with components R[i,j] = delta[i,j] - 2*n[i]*n[j], where delta[i,j] = 1 if i == j and 0 otherwise. It is also symmetric with respect to n:
R( -n ) = I - 2(-n)(-n) = I - 2 nn = R( n )
Hence it doesn't matter if one uses the outward facing or the inward facing normal n - the result would be the same.
In two dimensions and Cartesian coordinates, R (the matrix representation of R) becomes:
[ R00 R01 ] [ 1.0-2.0*n.x*n.x -2.0*n.x*n.y ]
R = [ ] = [ ]
[ R10 R11 ] [ -2.0*n.x*n.y 1.0-2.0*n.y*n.y ]
The components of the reflected vector are then computed as a row-vector-matrix product:
v1.x = v.x*R00 + v.y*R10
v1.y = v.x*R01 + v.y*R11
or after expansion:
k = 2.0*(v.x*n.x + v.y*n.y)
v1.x = v.x - k*n.x
v1.y = v.y - k*n.y
In three dimensions:
k = 2.0*(v.x*n.x + v.y*n.y + v.z*n.z)
v1.x = v.x - k*n.x
v1.y = v.y - k*n.y
v1.z = v.z - k*n.z
Finding the exact point where the ball will hit the line/wall is more involved - see here.
Calculate two components of the vector.
One component will be the projection of your vector onto the reflecting surface the other component will be the projection on to the surface's normal (which you say you already have). Use dot products to get the projections. Add these two components together by summing the two vectors. You'll have your answer.
You can even calculate the second component A2 as being the original vector minus the first component, so: A2 = A - A1. And then the vector you want is A1 plus the reflected A2 (which is simply -A2 since its perpendicular to your surface) or:
Ar = A1-A2
or
Ar = 2A1 - A which is the same as Ar = -(2A2 - A)
If [Ax,Bx] is your balls velocity and [Wx,Wy] is a unit vector representing the wall:
A1x = (Ax*Wx+Ay*Wy)*Wx;
A1y = (Ax*Wx+Ay*Wy)*Wy;
Arx = 2*A1x - Ax;
Ary = 2*A1y - Ay;

AS3: diagonal movement

I'm programming a flash game, I made an array of points (x and y positions) that some movieclips must follow. Those movieclips have a certain speed (they make steps of 5 pixels for now). When I want to move them horizontally or vertically, everything's fine, I have to add or remove 5 pixels of those clips' x or y. But sometimes they have to move diagonally and now that's complicated.
What I'm doing:
var angle:Number = Math.atan2(nextPoint.y - this.y, nextPoint.x - this.x) * 180 / Math.PI;
var xstep:Number = Math.cos(angle) * this.speed;
var ystep:Number = Math.sqrt(Math.pow(this.speed, 2) - Math.pow(xstep, 2));
this.x += xstep;
this.y += ystep;
It's only a fraction of the code, but I think it's all you need.
Basically, this makes my movieclip do a little step (of this.speed (currently set to 5) pixels).
If the current point and the next point have the same y position, it works fine. When they don't, it doesn't work. The angle is right at first but it slowly decreases (while it should stay the same). I don't know if it's the angle that isn't computed the right way or if it's the x and y steps, but it's one of those, I'm sure.
Try this instead:
var angle:Number = Math.atan2(nextPoint.y - this.y, nextPoint.x - this.x);
var xstep:Number = Math.cos(angle) * this.speed;
var ystep:Number = Math.sin(angle) * this.speed;
Because cos operates on angles in radians, you don't need to convert to degrees. Computing the y component of an angle uses sin, so it should be similar to x. I'm not able to test this, but it's possible that ystep will be backwards and may need to be multiplied by -1.

Bezier Curve always the same length

I'm working on a game in HTML5 canvas.
I want is draw an S-shaped cubic bezier curve between two points, but I'm looking for a way to calculate the coordinates of the control points so that the curve itself is always the same length no matter how close those points are, until it reaches the point where the curve becomes a straight line.
This is solvable numerically. I assume you have a cubic bezier with 4 control points.
at each step you have the first (P0) and last (P3) points, and you want to calculate P1 and P2 such that the total length is constant.
Adding this constraint removes one degree of freedom so we have 1 left (started with 4, determined the end points (-2) and the constant length is another -1). So you need to decide about that.
The bezier curve is a polynomial defined between 0 and 1, you need to integrate on the square root of the sum of elements (2d?). for a cubic bezier, this means a sqrt of a 6 degree polynomial, which wolfram doesn't know how to solve. But if you have all your other control points known (or known up to a dependency on some other constraint) you can have a save table of precalculated values for that constraint.
Is it really necessary that the curve is a bezier curve? Fitting two circular arcs whose total length is constant is much easier. And you will always get an S-shape.
Fitting of two circular arcs:
Let D be the euclidean distance between the endpoints. Let C be the constant length that we want. I got the following expression for b (drawn in the image):
b = sqrt(D*sin(C/4)/4 - (D^2)/16)
I haven't checked if it is correct so if someone gets something different, leave a comment.
EDIT: You should consider the negative solution too that I obtain when solving the equation and check which one is correct.
b = -sqrt(D*sin(C/4)/4 - (D^2)/16)
Here's a working example in SVG that's close to correct:
http://phrogz.net/svg/constant-length-bezier.xhtml
I experimentally determined that when the endpoints are on top of one another the handles should be
desiredLength × cos(30°)
away from the handles; and (of course) when the end points are at their greatest distance the handles should be on top of one another. Plotting all ideal points looks sort of like an ellipse:
The blue line is the actual ideal equation, while the red line above is an ellipse approximating the ideal. Using the equation for the ellipse (as my example above does) allows the line to get about 9% too long in the middle.
Here's the relevant JavaScript code:
// M is the MoveTo command in SVG (the first point on the path)
// C is the CurveTo command in SVG:
// C.x is the end point of the path
// C.x1 is the first control point
// C.x2 is the second control point
function makeFixedLengthSCurve(path,length){
var dx = C.x - M.x, dy = C.y - M.y;
var len = Math.sqrt(dx*dx+dy*dy);
var angle = Math.atan2(dy,dx);
if (len >= length){
C.x = M.x + 100 * Math.cos(angle);
C.y = M.y + 100 * Math.sin(angle);
C.x1 = M.x; C.y1 = M.y;
C.x2 = C.x; C.y2 = C.y;
}else{
// Ellipse of major axis length and minor axis length*cos(30°)
var a = length, b = length*Math.cos(30*Math.PI/180);
var handleDistance = Math.sqrt( b*b * ( 1 - len*len / (a*a) ) );
C.x1 = M.x + handleDistance * Math.sin(angle);
C.y1 = M.y - handleDistance * Math.cos(angle);
C.x2 = C.x - handleDistance * Math.sin(angle);
C.y2 = C.y + handleDistance * Math.cos(angle);
}
}

Find the last co-ordinate of isosceles triangle given coordinates of base and altitude

I have no clue about trigonometry, despite learning it in school way back when, and I figure this should be pretty straightforward, but trawling through tons of trig stuff on the web makes my head hurt :) So maybe someone could help me...
The title explains exactly what I want to do, I have a line:
x1,y1 and x2,y2
and want a function to find x3,y3 to complete an isosceles triangle, given the altitude.
Just to be clear, the line x1,y2 -> x2,y2 will be the base, and it will not be aligned any axis (it will be at a random angle..)
Does anyone have a simple function for this??
construct a normal to the vector (x1,y1)->(x2,y2). place it at the midpoint ((x1+x2)/2,(y1+y2)/2) and go out a distance h.
the normal will look like (-(y2-y1),x2-x1). make this a unit vector (http://en.wikipedia.org/wiki/Unit_vector).
add h times this unit vector to the midpoint.
The third point is on the perpendicular bisector of your base, and is altitude units away from the line.
Calculate the midpoint of the base by averaging the x and y coordinates.
Calculate the slope of your altitude: -dx/dy (perpendicular to dy/dx). You now have your line (point and slope).
y - my = -dx/dy * (x - mx)
Substitute your variables in the distance formula: d = sqrt(dx^2 + dy^2)
d = sqrt((x - mx)^2 + (y - my)^2)
d = sqrt((x - mx)^2 + (-dx/dy * (x - mx))^2)
d^2 = (x - mx)^2 + (-dx/dy * (x - mx))^2
d^2 - (x - mx)^2 = (-dx/dy * (x - mx))^2
±sqrt(d^2 - (x - mx)^2) = -dx/dy * (x - mx)
±sqrt(d^2 - (x - mx)^2) * dy/dx = x - mx
±sqrt(d^2 - (x - mx)^2) * dy/dx + mx = x
x = ±sqrt(d^2 - (x - mx)^2) * dy/dx + mx
Calculate the other variable (y here) using your line equation (from #2).
You now have two points; pick whichever you want...
In pseudocode:
dx = x1 - x2
midpoint = ((x1 + x2) / 2, (y1 + y2) / 2)
slope = -dx / (y1 - y2)
x = sqrt(altitude*altitude - dx*dx) / slope + midpoint.x
y = slope * (x - midpoint.x) + midpoint.y
This is probably not the most optimal method. Not sure if it even works. xD
Al I can remember is that an isosceles triangle will have sides of equal length, and equal angles at the base. If you have the height, then you have the final coordinate because this will be the point of intersection, right?

Triangle Trigonometry (ActionScript 3)

I am trying to write a formula in ActionScript 3 that will give me var "z" (please see image below) in degrees, which I will then convert to radians.
I will already know the value of vars "x" and "y". Using trigonometry, how can I calculate the length of the hypotenuse and therefore the variable angle of var z? A solution in either AS3 or psuedocode would be very helpful. Thanks.
What you need is this:
var h:Number = Math.sqrt(x*x + y*y);
var z:Number = Math.atan2(y, x);
That should give you the angle in radians, you might need to swap x/y and possibly add or remove 90 degrees but it should do the trick! (Note that you don't even need h to get z when you're using atan2)
I use multiplication instead of Math.pow() just because Math is pretty slow, you can do:
var h:Number = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
And it should be exactly the same.
z is equivalent to 180 - angle of yH. Or:
180 - arctan(x/y) //Degrees
pi - arctan(x/y) //radians
Also, if actionscript's math libraries have it, use arctan2, which takes both the x and y and deals with signs correctly.
The angle you want is the same as the angle opposed to the one wetween y and h.
Let's call a the angle between y and h, the angle you want is actually 180 - a or PI - a depending on your unit (degrees or radians).
Now geometry tells us that:
cos(a) = y/h
sin(a) = x/h
tan(a) = x/y
Using tan(), we get:
a = arctan(x/y)
As we are looking for 180 - a, you should compute:
180 - arctan(x/y)
What #Patrick said, also the hypotenuse is sqrt(x^2 + y^2).