Finding the smallest arc of rotation for a vector

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Finding the smallest arc of rotation for a vector

Post by Baiame »

Hello. For a while now, I've been trying to figure out (with reference to a couple threads on the GameDev forums) how to rotate vectors. I can't get it right. I'm doing:

Code: Select all

 vector3df direction;
vector3df newDirection;
double product;

newDirection.X=mousePointAt.X-nodePos.X;
 newDirection.Y=mousePointAt.Y-nodePos.Y;
 newDirection.normalize();
 direction.normalize();
 product=(direction.dotProduct(newDirection));
 direction.rotateXYBy(acos(product)*delta*100.0, direction.crossProduct(newDirection));
Note that some of the code is probably unnecessary, due to the number of ways I've tried solving this problem, and the variables I've used for debugging, etc.

I found that the acos of product is always positive. I followed the advice of a thread on GD, and did the same but set the centre of rotation to the cross product of the two vectors, and got the same result. Also, I think that when product=0, acos(product) returns a non-number.

All I want to do is find out the shortest arc of rotation between one point and another point. Any help would be greatly appreciated.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

So you get the angle, but it's alway positive (0 to 359.99999) ???
Then you just need to check if the angle is more than 180°...
If it's over 180° than simply use angle-360 as angle...
Or did I misunderstand your question ???
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

I think what I said I needed was misleading. Basically, all I need to know is whether a clockwise or counterclockwise rotation is shortest (between 2 unit vectors). Becuase acos(product), the way it is now, returns absolute values, I don't think if(angle>180)angle-360 will help (even if I set up the code to work with angles, it'd still be the same for both directions of rotation).

EDIT- It's kinda hard to describe. I'm not really working with angles. When I did try to do so, I didn't seem to get any closer to a solution.

I have, by the way, read about dot products on Wikipedia. Apparently the dot product of two perpendicular vectors is 0. So to just rotate the vector by the dot product alone won't work; the scene node translated according to the vector will "orbit" the position it's supposed to reach. I need a bunch of functions that return 0 when the two vectors in question are parallel, not perpendicular.

EDIT2- I kinda know how I would do it. Find out the operation needed to map the to-vector onto vector(1.0, 0.0), perform the same operation on the from-vector (the node's orientation), then look at the x component of the returned vector: if it is positive, rotate clockwise, if negative, rotate counter-clockwise. Not sure how exactly at the moment (especially on the first part).
EDIT3- I tried to find the angle that one must rotate the to-vector by to get it to equal (0.0, 1.0), then rotate another temp-vector (set equal to the node's current orientation vector) by that angle, and finally do a check on the Y component of the resulting vector. I thought it was a sound concept, but it doesn't work at all.

Code: Select all

 tempVector1.X=newDirection.X;
 tempVector1.Y=newDirection.Y;
 tempVector2=direction;
 tempVector2.rotateXYBy(-tempVector1.getAngle(), vector3df(0.0,0.0,0.0));
 
 if (tempVector2.Y>=0.0)
 {
 direction.rotateXYBy(10.0*delta, vector3df(0.0, 0.0, 0.0));
 }
 else
 {
  direction.rotateXYBy(-10.0*delta, vector3df(0.0, 0.0, 0.0));
 }
Can someone please enlighten me?

EDIT4(haha, the edits are getting ridiculous) I actually got it working using that method (I should've used the angle that you rotate the to-vector to itself, not the negative of it). However, my solution is a bit hackish and presumably not very efficient. I'd still be grateful for input on a simpler method.
Gato
Posts: 1
Joined: Fri Mar 02, 2007 5:13 am
Location: Mexico

Post by Gato »

To find the signed angle between two (2D) vectors, you can do something like the following:

Code: Select all

// the angle will be in RADIANS, from -Pi to Pi
 core::vector3df perp(-tempVector1.Y,tempVector1.X, 0.0);
 angle = atan2(perp.dotProduct(tempVector2), tempVector1.dotProduct(tempVector2));

To rotate a 2D vector, you can do the following:

Code: Select all

// the angle in RADIANS
double s = sin(angle); 
double c = cos(angle);
core::vector3df vrot(v1.X * c -v1.Y * s, v1.X * s + v1.Y * c);
Or using the rotateXYBy method:

Code: Select all

// the angle is in DEGREES
vec.rotateXYBy(angle, core::vector3df(0,0,0));
I haven't tested these, but they should work.
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

Thanks Gato, but I revisited this problem a few days ago, and I think I found a faster solution. Something like this:

Code: Select all

 newDirection.X=target.X-nodePos.X;
 newDirection.Y=target.Y-nodePos.Y;
 
 newDirection.normalize();
 direction.normalize();
 
 toAngle=direction.getAngle()+(360.0-newDirection.getAngle());
 if (toAngle>360.0) toAngle-=360.0;
 if (toAngle>180.0) toAngle=-(360.0-toAngle);
It may (or may not, I don't know the workings of the Irrlicht functions you used) use more logical operators, but it certainly uses less assignment and function calls. I don't even know if the normalisation is necessary, I'll have to check.
Post Reply