Angle Between Two Vectors?
Mr. Big

How do I get the angle between two vectors with the same origin?
The two ways I know (using 'acos' and 'atan2') return some confusing results.
How do I convert those results to the range of 0 - 2 pi (or 0 - 360 degrees, or whatever)?

Thanks.

Thomas Harte

Are you working out the individual angles of the lines from their origin, then trying to do some arithmetic on those values? If so then that would explain your issues. An easier solution is the dot product.

For two vectors, A and B:

A . B = |A||B|cos(angle between A and B)

|A| is the length of A, so you can find that with Pythagoras.

So, if you have A = (ax, ay) and B = (bx, by) then:

angle between = acos( ((ax * bx) + (ay * by)) / (sqrt(ax*ax + ay*ay) * sqrt(bx*bx + by*by))

If you use the acos from math.h then the result will be in the range -pi/2 to pi/2. Be careful though — it'll always give you the smallest angle between the vectors, so if two vectors start with the same orientation and then one stays still and the other rotates then the angle between them will go up from 0 to pi/2, then down again from pi/2 to -pi/2, then up from -pi/2 to 0.

If you want a full -pi to pi then you need to do a further check to decide if the two vectors are both pointing "the same way". Imagine one vector is lying exactly on the x-axis pointing right. Then you want to decide whether the other is pointing right or left.

You can do that using the dot product too — check whether ((ax * bx) + (ay * by)) is negative or positive and add or subtract pi from your result depending on its sign and which angle you want to measure.

E.g. (untested, written adhoc)

1float get_angle_between_in_radians(float ax, float ay, float bx, float by)
2{
3 float dotproduct, lengtha, lengthb, result;
4 
5 dotproduct = (ax * bx) + (ay * by);
6 lengtha = sqrt(ax * ax + ay * ay);
7 lengthb = sqrt(bx * bx + by * by);
8 
9 result = acos( dotproduct / (lengtha * lengthb) );
10 
11 if(dotproduct < 0)
12 {
13 if(result > 0)
14 result += M_PI;
15 else
16 result -= M_PI;
17 }
18 return result;
19}

There's lots on the web about the dot product, and it's something that's very easy to understand the properties of, even if it takes you a while to really see why it all works...

Mr. Big

Oh! Should have thought about it myself!
I'm stupid.
Thanks, Thomas. ;D

[EDIT]

Your code doesn't actually work because 'atan' returns values in range of 0 - pi, but thanks for the idea with the dot product and angle signs.

This works like it should:

float angle_between_vectors(VECTOR o, VECTOR a, VECTOR b)
{
 VECTOR t1 = VECTOR_DIFF(a, o), t2 = VECTOR_DIFF(b, o);
 float result;

 result = (atan2(t1.y, t1.x) - atan2(t2.y, t2.x)) * 180.0 * M_1_PI;

 if(result < 0)
  result += 360.0;

 return result;
}

Paul Rowan

Hi,

I'm not that mathematical, but I have a full code list for finding the angle between 2 points, don't know if this is the same as vectors :-/ but I'll post it here just in case it is for you to use if you want it :)

1#include <allegro.h>
2#include <math.h>
3 
4#define PI 3.1415926535
5 
6#define WHITE makecol(255,255,255)
7 
8//define function prototype
9double get_angle(int x1,int y1,int x2, int y2);
10 
11int main()
12{
13 allegro_init();
14 
15 set_gfx_mode(GFX_SAFE, 640, 480, 0, 0);
16 
17 install_keyboard();
18 
19 //variables for calculating angle
20 double ang1;
21 double ang2;
22 
23 //first x,y co-ords
24 int x1=150;
25 int y1=150;
26 
27 //second x,y co-ords
28 int x2=100;
29 int y2=100;
30
31 ang1=get_angle(x1,y1,x2,y2);
32
33 //Add or subtract 180 degrees to ang1 to get the angle for ang2
34 if(ang1<=180) ang2=ang1+180;
35 else ang2=ang1-180;
36
37 textprintf(screen,font,10,10,WHITE,"Point 1 = %d , %d (x: horizontal [+ = right], y: vertical [+ = up])",x1,y1);
38 textprintf(screen,font,10,25,WHITE,"Point 2 = %d , %d",x2,y2);
39
40 if(ang1==-1)
41 {
42 textprintf(screen,font,10,40,WHITE,"%s","The Points are the same!");
43 }
44 else
45 {
46 textprintf(screen,font,10,40,WHITE,"The Angle from Point 2 to Point 1 is %f degrees",ang1);
47 textprintf(screen,font,10,55,WHITE,"The Angle from Point 1 to Point 2 is %f degrees",ang2);
48 }
49
50 while(! key[KEY_ESC]);
51 allegro_exit();
52 return 0;
53}
54 
55END_OF_MAIN();
56 
57 
58double get_angle(int x1,int y1,int x2, int y2)
59{
60 double opp;
61 double adj;
62 double ang1;
63
64 //calculate vector differences
65 opp=y1-y2;
66 adj=x1-x2;
67 
68 if(x1==x2 && y1==y2) return(-1);
69 
70 //trig function to calculate angle
71 if(adj==0) // to catch vertical co-ord to prevent division by 0
72 {
73 if(opp>=0)
74 {
75 return(0);
76 }
77 else
78 {
79 return(180);
80 }
81 }
82 else
83 {
84 ang1=(atan(opp/adj))*180/PI;
85 //the angle calculated will range from +90 degrees to -90 degrees
86 //so the angle needs to be adjusted if point x1 is less or greater then x2
87 if(x1>=x2)
88 {
89 ang1=90-ang1;
90 }
91 else
92 {
93 ang1=270-ang1;
94 }
95 }
96 return(ang1);
97}

Thread #591460. Printed from Allegro.cc