Angle between two vectors

Given two 2D vectors a=(a.x,a.y) and b=(b.x,b.y)

How to compute the angle (THETA) between these vectors?

I was always a little bit confused about the different approaches.

Different approaches

One approach says:

cos(THETA_1) = a*b / (||a|| ||b||)

where * is the dot product (other term: scalar product). Thus:

THETA_1 = acos(a*b / ||a|| ||b||)

Another approach says:

THETA_2 = atan2(b.y,b.x) - atan2(a.y,a.x)

Is there a difference?

Yes! Read e.g. here or watch the demo and demo code below.

Difference between the two angles THETA_1 and THETA_2

Conclusion

THETA_1: gives us just the relative angle between a and b. It's in [0,PI].

THETA_2: gives us the relative angle between a and b with a sign that indicates which vector is “ahead”. It's in [-PI,PI].

Note that THETA_1 = |THETA_2|

Demo code

int w = 600;
int h = 600;
float vec1Len = 100;
float vec2Len = 200;
 
float middlex = w/2;
float middley = h/2;
 
int counter = 0;
for (float angle_is=0.0; angle_is<=4*M_PI; angle_is+=0.05)    
{
    // Create empty image
    Mat img(h,w, CV_8UC3);
    img = 0;
 
    // Create 1st vector a (changing angle)
    float ax = cos(angle_is) * vec1Len;
    float ay = sin(angle_is) * vec1Len;
 
    // Create 2nd vector b (fixed angle)
    float PredefinedAngle = -M_PI/4;
    float bx = cos(PredefinedAngle) * vec2Len;
    float by = sin(PredefinedAngle) * vec2Len;
 
    // Compute angle between vector a and vector b
    // See: http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
 
    // 1st method: cos(THETA) = a*b / (||a|| ||b||);
    // This gives us just the relative angle between a and b
    float dotProduct = ax*bx + ay*by;
    float theta_1 = acos( dotProduct / (vec1Len*vec2Len) );
 
    // 2nd method: THETA = atan2(v2.y,v2.x) - atan2(v1.y,v1.x)
    // This gives us the relative angle between a and b with a sign
    // that indicates which vector is "ahead"
    float theta_2 = atan2(by,bx) - atan2(ay,ax);
 
 
    // Show vectors a and b
    line(img, Point(middlex,middley), Point(middlex+ax,middley+ay), CV_RGB(255,255,0) );
    line(img, Point(middlex,middley), Point(middlex+bx,middley+by), CV_RGB(0,0,255)   );
 
    // Show is- and computed angles
    char txt[500];
 
    sprintf_s(txt, "image #%4d", counter );
    putText( img, txt, Point(5,10), CV_FONT_HERSHEY_SIMPLEX, .4, CV_RGB(255,0,0) );
 
    sprintf_s(txt, "angle between yellow vec and x-axis: %.2f radians (%.2f degree)", angle_is, MathHelper::RadiansToDegree(angle_is) );
    putText( img, txt, Point(5,25), CV_FONT_HERSHEY_SIMPLEX, .4, CV_RGB(255,0,0) );
 
    sprintf_s(txt, "angle between yellow + blue vec (theta_1): %.2f radians (%.2f degree)", theta_1, MathHelper::RadiansToDegree(theta_1) );
    putText( img, txt, Point(5,65), CV_FONT_HERSHEY_SIMPLEX, .4, CV_RGB(255,0,0) );
 
    sprintf_s(txt, "angle between yellow + blue vec (theta_2): %.2f radians (%.2f degree)", theta_2, MathHelper::RadiansToDegree(theta_2) );
    putText( img, txt, Point(5,85), CV_FONT_HERSHEY_SIMPLEX, .4, CV_RGB(255,0,0) );
 
 
    // Save image
    char fname[500];
    sprintf_s(fname, "W:\\tmp\\%04d.png", counter);
    imwrite(fname, img);
 
    counter++; 
}

Videos

Presenting the formula + showing a computation example

Example of how to compute the angle between two 3D vectors

Short proof of the formula

cos(THETA) = a*b / (||a|| ||b||)

Getting a signed angle between two 3D vectors

Read here:

“Use cross product of the two vectors to get the normal of the plane formed by the two vectors. Then check the dotproduct between that and the original plane normal to see if they are facing the same direction.”

angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
  angle = -angle;
}

Here they suggest:

The relevant mathematical formulas:

  dot_product(a,b) == length(a) * length(b) * cos(angle)
  length(cross_product(a,b)) == length(a) * length(b) * sin(angle)

For a robust angle between 3-D vectors, your actual computation should be:

  s = length(cross_product(a,b))
  c = dot_product(a,b)
  angle = atan2(s, c)

If you use acos(c) alone, you will get severe precision problems for cases
when the angle is small. Computing s and using atan2() gives you a robust
result for all possible cases.

Since s is always nonnegative, the resulting angle will range from 0 to pi.
There will always be an equivalent negative angle (angle - 2*pi), but there is
no geometric reason to prefer it.
 
public/angle_between_two_vectors.txt · Last modified: 2014/01/04 13:11 (external edit) · []
Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki