Anyone know the math to rotate a 2d vector?
rotating a vector?
BlitzMax Forums/BlitzMax Programming/rotating a vector? There is no given angle. Sorry I'm not a math guy. It's just vector value I have to start with. Do I have the convert the vector to an angle first?
current_angle = atan2(endy-starty,endx-startx)
Here's the Vector2 rotate function I ported over from my XNA libraries:
I haven't tested it or anything, though, so no guarantees it works in this version. Remember that it rotates by a fraction of a circle, so the higher the number, the smaller the rotation (2 is 180 degrees).
'Return a vector rotated by amountToRotate (fraction of a circle) Function RotateVector:TVector2(vec:TVector2, amountToRotate) Local r:Float = (2 * Pi) / amountToRotate Local newVec:TVector2 = TVector2.Create() newVec.x = Cos(r) * vec.x - Sin(r) * vec.x; newVec.y = Cos(r) * vec.y + Sin(r) * vec.y; Return newVec; End Function
I haven't tested it or anything, though, so no guarantees it works in this version. Remember that it rotates by a fraction of a circle, so the higher the number, the smaller the rotation (2 is 180 degrees).
A vector is just another word for the coordinates of the endpoint of a ray that starts at 0,0. So all vectors have an angle.
Here is how you might rotate a vector:
Calculate the angle which the vector is at:
angle = atan2(vy,vx)
Then, if you wish to maintain the vector's magnitude, ie, it's length, calculate that:
magnitude = sqr(vx^2 + vy^2)
Then adjust that angle as desired:
angle = angle + 10
Then use polar coordinates to calculate the new endpoint of the vector:
vx = magnitude * cos(angle)
vy = magnitude * sin(angle)
If you don't care if your vector has a length/magnitude of 10 or a length of 1, then you can skip calculating the magnitude, which is good because you can avoid a square root and two multiplications.
Of course this is just a method I came up with off the top of my head. Orem's equations up there, if they work, would probably be faster. And I suspect they do work because I've seen methods for rotating stuff that don't involve sqare roots before that looked something like that.
Here is how you might rotate a vector:
Calculate the angle which the vector is at:
angle = atan2(vy,vx)
Then, if you wish to maintain the vector's magnitude, ie, it's length, calculate that:
magnitude = sqr(vx^2 + vy^2)
Then adjust that angle as desired:
angle = angle + 10
Then use polar coordinates to calculate the new endpoint of the vector:
vx = magnitude * cos(angle)
vy = magnitude * sin(angle)
If you don't care if your vector has a length/magnitude of 10 or a length of 1, then you can skip calculating the magnitude, which is good because you can avoid a square root and two multiplications.
Of course this is just a method I came up with off the top of my head. Orem's equations up there, if they work, would probably be faster. And I suspect they do work because I've seen methods for rotating stuff that don't involve sqare roots before that looked something like that.
I looked up matrix multiplication since I didn't remember how to do it and Dreamora's post is useless unless you know how, and this is what I think he's telling you to do:
[ cos(angle) -sin(angle) ]
[ sin(angle) cos(angle) ]
He tells you to multiply the vector by that.
Since I can only assume that you can only multiply one matrix by another, then I'll assume that the vector would be matrix [Vx, Vy].
Now, when you multiply two matrices, you end up with a new matrix which has the same number of rows as the first one, and the same number of columns as the second.
In this case, after multiplication you would end up with a matrix with 1 row, and 2 columns. Which is the same as the vector matrix there.
You can read up on matrix multiplication here. I'm not going to try to explain it because it would take too long to try to word it in a manner which is easy to understand:
http://en.wikipedia.org/wiki/Matrix_(mathematics)
But basically, Dreamora's telling you to do this:
[vx, vy]
*
[ cos(angle) -sin(angle) ]
[ sin(angle) cos(angle) ]
=
[vx*cos(angle)+vy*sin(angle), vx*-sin(angle)+vy*cos(angle)]
So:
NewVx = vx*cos(angle) + vy*sin(angle)
NewVy = vx*-sin(angle) + vy*cos(angle)
Where angle is the change in angle you want for the vector, not the angle at which you want the vector to be. Ie, if it is at 90 degrees and you want it at 100 degrees, then angle would be 10.
I think!
[ cos(angle) -sin(angle) ]
[ sin(angle) cos(angle) ]
He tells you to multiply the vector by that.
Since I can only assume that you can only multiply one matrix by another, then I'll assume that the vector would be matrix [Vx, Vy].
Now, when you multiply two matrices, you end up with a new matrix which has the same number of rows as the first one, and the same number of columns as the second.
In this case, after multiplication you would end up with a matrix with 1 row, and 2 columns. Which is the same as the vector matrix there.
You can read up on matrix multiplication here. I'm not going to try to explain it because it would take too long to try to word it in a manner which is easy to understand:
http://en.wikipedia.org/wiki/Matrix_(mathematics)
But basically, Dreamora's telling you to do this:
[vx, vy]
*
[ cos(angle) -sin(angle) ]
[ sin(angle) cos(angle) ]
=
[vx*cos(angle)+vy*sin(angle), vx*-sin(angle)+vy*cos(angle)]
So:
NewVx = vx*cos(angle) + vy*sin(angle)
NewVy = vx*-sin(angle) + vy*cos(angle)
Where angle is the change in angle you want for the vector, not the angle at which you want the vector to be. Ie, if it is at 90 degrees and you want it at 100 degrees, then angle would be 10.
I think!
What does the very loose term "multiply the matrix" actually entail, in detail? This is SO often glossed over assuming everyone knows how matrices work and because of that very fact I still have not grasped what that really means or how or why you do it.
It's complicated to explain, that's why I linked to the wikipedia article.
I think the way it works is you go down each column of the first matrix, and multiply each value with the value in the corresponding row of the second matrix. Then you add those together, and that is the first value in the first row of your destination matrix. Then you go down the next column and do the same to fill in the next element in the destination matrix and so on.
Here's some code I found to do it in another language:
And one more thing:
http://en.wikipedia.org/wiki/Matrix_multiplication
I think the way it works is you go down each column of the first matrix, and multiply each value with the value in the corresponding row of the second matrix. Then you add those together, and that is the first value in the first row of your destination matrix. Then you go down the next column and do the same to fill in the next element in the destination matrix and so on.
Here's some code I found to do it in another language:
for i = 1 to n for j = 1 to m for k = 1 to m C(i,j) = C(i,j) + A(i,k) * B(k,j) end end end
And one more thing:
http://en.wikipedia.org/wiki/Matrix_multiplication
Thanks, although that wiki page is far too complicated to understand.
Yeah I think the wiki page is not great. I did Matrix at school, then forgot it for a while, then looked it up again on the Internet :-)
Here's my rotate method (part of a TVector type which uses X and Y to specify the vector length (remember start and end points don't matter for rotation):
Here's my rotate method (part of a TVector type which uses X and Y to specify the vector length (remember start and end points don't matter for rotation):
Method Rotate(angle!) 'clockwise Local tx# = (x * Cos(angle)) - (y * Sin(angle)) Local ty# = (x * Sin(angle)) + (y * Cos(angle)) x=tx y=ty End Method
There is a great book if you are interested in math for gaming, its the 3D Math primer for 3d game programming
It has all math in you could need in an understandable way with nice examples.
It can be used for 2D and 3D usages and shows some of the common solutions for problems you will often meet in some way (parent - child transformations, reflections at an arbitary plane / line / vector, ...)
It has all math in you could need in an understandable way with nice examples.
It can be used for 2D and 3D usages and shows some of the common solutions for problems you will often meet in some way (parent - child transformations, reflections at an arbitary plane / line / vector, ...)
Here's a 2d vector graphics "engine" I whipped up some time ago as a quick test. It includes basic vector rotation methods which might help you out. It uses startpoint & endpoint logic to represent vectors rather than direction & lenght.
Use arrow keys to move and rotate the vector drawing around the screen. Z and X keys change the scale of the drawing on-the-fly.
Use arrow keys to move and rotate the vector drawing around the screen. Z and X keys change the scale of the drawing on-the-fly.
SuperStrict Graphics(600, 400) Local vDrawing:TDrawing = TDrawing.Create() vDrawing.AddVector(20, 0, - 20, 0) vDrawing.AddVector(20, 0, - 20, - 10) vDrawing.AddVector(20, 0, - 20, 10) Local x:Float = 50 Local y:Float = 50 Repeat If KeyDown(KEY_LEFT) Then vDrawing.Rotate(- 2) If KeyDown(KEY_RIGHT) Then vDrawing.Rotate(2) If KeyDown(KEY_UP) Then x = x + 2 * Cos(vDrawing.rot) y = y + 2 * Sin(vDrawing.rot) EndIf If KeyDown(KEY_Z) Then vDrawing.scale:+0.1 If KeyDown(KEY_X) Then vDrawing.scale:-0.1 vDrawing.Draw(x, y) Flip;Cls Until KeyDown(KEY_ESCAPE) Or AppTerminate() Type TDrawing Field vectors:TVector[] Field rot:Float Field scale:Float = 1 Method AddVector(sx:Double, sy:Double, ex:Double, ey:Double) Local vect:TVector = TVector.Create(sx, sy, ex, ey) vectors = vectors[..vectors.Length + 1] vectors[vectors.Length - 1] = vect End Method Method SetRot(r:Float) rot = r End Method Method Rotate(theta:Float) rot = rot + theta If rot <= 0 Then rot = 360 - rot ElseIf rot > 360 Then rot = rot - 360 EndIf End Method Method Draw(x:Double, y:Double) If Not vectors Then Return SetScale(1, 1) SetLineWidth(1 * scale) If GetLineWidth() < 1 Then SetLineWidth(1) For Local v:TVector = EachIn vectors DrawLine(v.s.GetRotatedX(rot, scale) + x, .. v.s.GetRotatedY(rot, scale) + y, .. v.e.GetRotatedX(rot, scale) + x, .. v.e.GetRotatedY(rot, scale) + y, .. False) Next End Method Function Create:TDrawing(_rot:Float = 0, _scale:Float = 1) Local d:TDrawing = New TDrawing d.rot = _rot d.scale = _scale Return d End Function End Type Type TVector Field s:TPoint Field e:TPoint Method GetLength:Float() Return Sqr((e.x - s.x) ^ 2 + (e.y - s.y) ^ 2) End Method ' returns a new copy of the vector rotated by theta Method GetRotatedVector:TVector(theta:Float, scale:Float = 1) If theta = 0 Then Return Self Local v:TVector = TVector.Create( .. s.GetRotatedX(theta, scale), .. s.GetRotatedY(theta, scale), .. e.GetRotatedX(theta, scale), .. e.GetRotatedY(theta, scale)) Return v End Method ' Rotates the vector around the origin permanently Method Rotate(theta:Float, scale:Float = 1) If theta = 0 Then Return s.Rotate(theta, scale) e.Rotate(theta, scale) End Method Function Create:TVector(sx:Double, sy:Double, ex:Double, ey:Double) Local v:TVector = New TVector v.s = TPoint.Create(sx, sy) v.e = TPoint.Create(ex, ey) Return v End Function End Type Type TPoint Field x:Double Field y:Double ' returns the x coordinate rotated around the origin by theta Method GetRotatedX:Double(theta:Float, scale:Float = 1) Return Cos(theta) * x * scale - Sin(theta) * y * scale End Method ' returns the y coordinate rotated around the origin by theta Method GetRotatedY:Double(theta:Float, scale:Float = 1) Return Sin(theta) * x * scale + Cos(theta) * y * scale End Method ' Rotates the point around the origin permanently Method Rotate(theta:Float, scale:Float = 1) x = GetRotatedX(theta) * scale y = GetRotatedY(theta) * scale End Method Function Create:TPoint(_x:Double, _y:Double) Local p:TPoint = New TPoint p.x = _x ; p.y = _y Return p End Function End Type
A vector is just another word for the coordinates of the endpoint of a ray that starts at 0,0.
A ray has infinite length and so doesn't have an end point. :P Let's face it a vector is just two coordinates relative to 0. ;-)
Thing is if you want to store your object positions/movements as a pair of coordinates and not as an angle/distance pair, you can't really easily use cos and sin like GreyAlien shows cus you have to convert from coords to angle and radius first and then back again which seems redundant.
So how does one go about doing rotation of a vector without converting it to angles?
Thing is if you want to store your object positions/movements as a pair of coordinates and not as an angle/distance pair, you can't really easily use cos and sin like GreyAlien shows cus you have to convert from coords to angle and radius first and then back again which seems redundant.
So how does one go about doing rotation of a vector without converting it to angles?
Eh? He is storing them as coords.
Yeah my method uses TVector which has simple X and Y fields which are the distance from 0,0. So you just call the Rotate method with an angle and it rotates it and stores the new x and y coords. Your game types would also have their own x and y coords and a vector field which determined their speed/direction. Makes sense?
When using vectors for a vector drawing, the origin offset for a every vector has to be stored somewhere - why not the vector type itself?
Imaginary:
There are two ways to store a vector.
You can store is as an X,Y pair, and you can store it as an Angle and a Magnitude.
You can convert between the two like so:
X = Magnitude * Cos(Angle)
Y = Magnitude * Sin(Angle)
Magnitude = Sqr(X^2 + Y^2)
Angle = Atan2(Y, X)
Storing them as an angle and a magnitude gives you the benefit of being able to keep track of which direction the entity was moving in even when it has stopped moving, whereas that information is destroyed when using X and Y. It also makes it easy to slow an entity down due to friction, and adjust its direction of travel.
However, when you start doing physics, you need the components to be in the X and Y format because you need to calculate what angle surfaces are at on the axes and how the velocity changes on those axes after the collision. And when you move into 3D, being able to easily adjust your angle loses its benefits because you now have two of them and generally don't want to move in a single plane.
So it turns out you have to convert between these two regardless of which format you use. So you might as well use the XY format which is used far more often. You won't even save on the square root if you use the angle magnitude method cause you'll have to convert to XY to do the physics and then do the square root to convert back for storage.
There are two ways to store a vector.
You can store is as an X,Y pair, and you can store it as an Angle and a Magnitude.
You can convert between the two like so:
X = Magnitude * Cos(Angle)
Y = Magnitude * Sin(Angle)
Magnitude = Sqr(X^2 + Y^2)
Angle = Atan2(Y, X)
Storing them as an angle and a magnitude gives you the benefit of being able to keep track of which direction the entity was moving in even when it has stopped moving, whereas that information is destroyed when using X and Y. It also makes it easy to slow an entity down due to friction, and adjust its direction of travel.
However, when you start doing physics, you need the components to be in the X and Y format because you need to calculate what angle surfaces are at on the axes and how the velocity changes on those axes after the collision. And when you move into 3D, being able to easily adjust your angle loses its benefits because you now have two of them and generally don't want to move in a single plane.
So it turns out you have to convert between these two regardless of which format you use. So you might as well use the XY format which is used far more often. You won't even save on the square root if you use the angle magnitude method cause you'll have to convert to XY to do the physics and then do the square root to convert back for storage.
When using vectors for a vector drawing, the origin offset for a every vector has to be stored somewhere - why not the vector type itself?
I have a TLine type for that :-) Storing them as an angle and a magnitude gives you the benefit of being able to keep track of which direction the entity was moving in even when it has stopped moving, whereas that information is destroyed when using X and Y. It also makes it easy to slow an entity down due to friction, and adjust its direction of travel.
Good point for a tank game or something similar. I was just testing to see if there was a faster way to calculate magnitude from X and Y instead of using a square root and I found out that Cos(A#) takes a little longer than Sqr(X#*X# + Y#*Y#)!
I also tried coding my own function to calculate Sin() and I only was able to get it to be twice as slow as the built in function. The built in function was also a lot more accurate.
I also tried coding my own function to calculate Sin() and I only was able to get it to be twice as slow as the built in function. The built in function was also a lot more accurate.
Actually, I was mistaken. The sin function I made, while less accurate, is actually slightly faster than the built in function. But only slightly. Like 17ms instead of 20.
It's most accurate from -90 to +90. It's less accurate from -180 to 180, but because the values are mirrored within those extended ranges, with a little clever coding you could get the same accuracy in those sections. But then you'd lose the speed increase. You can make it even faster and less accurate by like, removing "- R#*R#*R#*R#*R#*R#*R#/5040" from the calculation. That's an neverneding series. R^3/3! + R^5/5! -R^7/7! where 7! means (7*6*5*4*3*2*1). So if you extend that series you can make it more accurate.
I tried to reduce the number of times I multiply R by itself by storing it in a variable but that cost me a little speed rather than gaining anything.
T1 = MilliSecs() For A# = -90 To 90 R# = Sin(A#) - Sin2(A#) Print R# Next T2 = MilliSecs() 'For A# = 0 To 90 ' R# = Sin2(A#) ' Print R# 'Next T3 = MilliSecs() Print T2-T1 Print T3-T2 WaitKey() Function Sin2#(A#) Local R# = A# * Pi/180.0 'Return R# - R#^3.0/6 + R#^5.0/120 - R#^7.0/5040 + R#^9.0/362880 + R#^11.0/39916800 ' 310ms Return R# - R#*R#*R#/6 + R#*R#*R#*R#*R#/120 - R#*R#*R#*R#*R#*R#*R#/5040 ' 17ms End Function
It's most accurate from -90 to +90. It's less accurate from -180 to 180, but because the values are mirrored within those extended ranges, with a little clever coding you could get the same accuracy in those sections. But then you'd lose the speed increase. You can make it even faster and less accurate by like, removing "- R#*R#*R#*R#*R#*R#*R#/5040" from the calculation. That's an neverneding series. R^3/3! + R^5/5! -R^7/7! where 7! means (7*6*5*4*3*2*1). So if you extend that series you can make it more accurate.
I tried to reduce the number of times I multiply R by itself by storing it in a variable but that cost me a little speed rather than gaining anything.