rotating a vector?

BlitzMax Forums/BlitzMax Programming/rotating a vector?

Craig H. Nisbet(Posted 2008) [#1]
Anyone know the math to rotate a 2d vector?


Dreamora(Posted 2008) [#2]
sure.
multiply the 2D vector by the rotation matrix for the given angle

rotMat is
[ cos(angle)   -sin(angle) ]
[ sin(angle)   cos(angle) ]



Craig H. Nisbet(Posted 2008) [#3]
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?


Jesse(Posted 2008) [#4]
current_angle = atan2(endy-starty,endx-startx)


OremLK(Posted 2008) [#5]
Here's the Vector2 rotate function I ported over from my XNA libraries:

	'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).


sswift(Posted 2008) [#6]
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.


sswift(Posted 2008) [#7]
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!


ImaginaryHuman(Posted 2008) [#8]
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.


sswift(Posted 2008) [#9]
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:

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


ImaginaryHuman(Posted 2008) [#10]
Thanks, although that wiki page is far too complicated to understand.


Grey Alien(Posted 2008) [#11]
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):

	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



Dreamora(Posted 2008) [#12]
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, ...)


Vilu(Posted 2008) [#13]
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.




big10p(Posted 2008) [#14]
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


ImaginaryHuman(Posted 2008) [#15]
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?


big10p(Posted 2008) [#16]
Eh? He is storing them as coords.


Grey Alien(Posted 2008) [#17]
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?


Vilu(Posted 2008) [#18]
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?


sswift(Posted 2008) [#19]
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.


Grey Alien(Posted 2008) [#20]
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.


sswift(Posted 2008) [#21]
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.


sswift(Posted 2008) [#22]
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.

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.