rotating a vector?
BlitzMax Forums/BlitzMax Programming/rotating a vector?
| ||
Anyone know the math to rotate a 2d vector? |
| ||
sure. multiply the 2D vector by the rotation matrix for the given angle rotMat is [ cos(angle) -sin(angle) ] [ sin(angle) cos(angle) ] |
| ||
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:'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. |
| ||
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! |
| ||
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: 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): 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, ...) |
| ||
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. |
| ||
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? |
| ||
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. |
| ||
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. |
| ||
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. |