views:

833

answers:

4

Hi,

Say I have two 2D vectors, one for an objects current position and one for that objects previous position. How can I work out the direction of travel?

This image might help understand what I'm after:

alt text

Thanks

-James

+1  A: 

Still not sure what you mean by rotation matrices, but this is a simple case of getting an azimuth from a direction vector.

The complicated answer:

Normally you should pack a few conversion/utility functions with your 2D vectors: one to convert from X,Y (carthesian) to Theta,R (polar coordinates). You should also support basic vector operations like addition, substraction and dot product. Your answer in this case would be:

 double azimuth  =  (P2 - P1).ToPolarCoordinate().Azimuth;

Where ToPolarCoordinate() and ToCarhtesianCoordinate() are two reciprocal functions switching from one type of vector to another.

The simple one:

 double azimuth = acos ((x2-x1)/sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
 //then do a quadrant resolution based on the +/- sign of (y2-y1) and (x2-x1)
 if (x2-x1)>0 {
   if (y2-y1)<0 {  azimuth = Pi-azimuth; } //quadrant 2
 } else 
 { if (y2-y1)> 0 {  azimuth = 2*Pi-azimuth;} //quadrant 4
    else  { azimuth = Pi + azimuth;} //quadrant 3
 }
Radu094
Sorry, I updated the question but not the title regarding the matrix stuff...
ing0
+2  A: 

The direction vector of travel will be the difference of the two position vectors,

d = (x1, y1) - (x, y) = (x1 - x, y1 - y)

Now when you ask for the direction angle, that depends what direction you want to measure the angle against. Is it against the x axis? Go with Radu's answer. Against an arbitrary vector? See justjeff's answer.

Edit: To get the angle against the y-axis:

tan (theta) = (x1 -x)/(y1 - y)          

the tangent of the angle is the ratio of the x-coordinate of the difference vector to the y-coordinate of the difference vector.

So

theta = arctan[(x1 - x)/(y1 - y)]

Where arctan means inverse tangent. Not to be confused with the reciprocal of the tangent, which many people do, since they're both frequently denoted tan^-1. And make sure you know whether you're working in degrees or radians.

Rob Lachlan
Actually it's against the Y axis i'm looking for
ing0
@james.ingham: hope that helps.
Rob Lachlan
Thanks It was arctan I was looking for! :)
ing0
@james `arctan` has problems at some angles (i.e., if there is a divide by zero). That's why there is `atan2` which handles the tricky cases correctly.
Donal Fellows
This is true however running the atan2 in my code is proving too much for the device and is causing lots of slow behavior. I must thank you though as this is for my dissertation and I must talk about different methods of doing things!
ing0
+6  A: 

If you're in C (or other language that uses the same function set) then you're probably looking for the atan2() function. From your diagram:

double theta = atan2(x1-x, y1-y);

That angle will be from the vertical axis, as you marked, and will be measured in radians (God's own angle unit).

Donal Fellows
+1  A: 

Be careful to use atan2 to avoid quadrant issues and division by zero. That's what it's there for.

float getAngle(CGPoint ptA, CGPoint ptOrigin, CGPoint ptB)
{
    CGPoint A = makeVec(ptOrigin, ptA);
    CGPoint B = makeVec(ptOrigin, ptB);

    // angle with +ve x-axis, in the range (−π, π]
    float thetaA = atan2(A.x, A.y);  
    float thetaB = atan2(B.x, B.y);

    float thetaAB = thetaB - thetaA;

    // get in range (−π, π]
    while (thetaAB <= - M_PI)
        thetaAB += 2 * M_PI;

    while (thetaAB > M_PI)
        thetaAB -= 2 * M_PI;

    return thetaAB;
}

However, if you don't care about whether it's a +ve or -ve angle, just use the dot product rule (less CPU load):

float dotProduct(CGPoint p1, CGPoint p2) { return p1.x * p2.x + p1.y * p2.y; }

float getAngle(CGPoint A, CGPoint O, CGPoint B)
{
    CGPoint U = makeVec(O, A);
    CGPoint V = makeVec(O, B);

    float magU = vecGetMag(U);
    float magV = vecGetMag(V);
    float magUmagV = magU * magV;   assert (ABS(magUmagV) > 0.00001);

    // U.V = |U| |V| cos t
    float cosT = dotProduct(U, V) / magUmagV;
    float theta = acos(cosT);
    return theta;
}

Note that in either code section above, if one ( or both ) vectors are close to 0 length this is going to fail. So you might want to trap that somehow.

Ohmu