29

I know that the common approach in order to find an angle is to calculate the dot product between 2 vectors and then calculate arcus cos of it. But in this solution I can get an angle only in the range(0, 180) degrees. What would be the proper way to get an angle in range of (0, 360)?

Savail
  • 445
  • 1
    Do you means you are looking for mathematical formula for something akin to the "atan2" function in C++? – Gina Jul 26 '14 at 15:20
  • 8
    Two vectors form two angles that add up to $360^\circ$. The "angle between vectors" is defined to be the smaller of those two, hence no greater than $180^\circ$. Apparently, you sometimes want the bigger one instead. You'll have to clarify your definition of "angle between vectors". – Karolis Juodelė Jul 26 '14 at 15:25
  • 2
    You could check which quadrants your original vectors were in to see if you need to add the 180. – user2154420 Jul 26 '14 at 15:25

3 Answers3

44

I'm adapting my answer on Stack Overflow.

2D case

Just like the dot product is proportional to the cosine of the angle, the determinant is proprortional to its sine. And if you know the cosine and the sine, then you can compute the angle. Many programming languages provide a function atan2 for this purpose, e.g.:

dot = x1*x2 + y1*y2      # dot product
det = x1*y2 - y1*x2      # determinant
angle = atan2(det, dot)  # atan2(y, x) or atan2(sin, cos)

3D case

In 3D, two arbitrarily placed vectors define their own axis of rotation, perpendicular to both. That axis of rotation does not come with a fixed orientation, which means that you cannot uniquely fix the direction of the angle of rotation either. One common convention is to let angles be always positive, and to orient the axis in such a way that it fits a positive angle. In this case, the dot product of the normalized vectors is enough to compute angles.

Plane embedded in 3D

One special case is the case where your vectors are not placed arbitrarily, but lie within a plane with a known normal vector $n$. Then the axis of rotation will be in direction $n$ as well, and the orientation of $n$ will fix an orientation for that axis. In this case, you can adapt the 2D computation above, including $n$ into the determinant to make its size $3\times3$. One condition for this to work is that the normal vector $n$ has unit length. If not, you'll have to normalize it. The determinant could also be expressed as the triple product:

$$\det(v_1,v_2,n) = n \cdot (v_1 \times v_2)$$

This might be easier to implement in some APIs, and gives a different perspective on what's going on here: The cross product is proportional to the sine of the angle, and will lie perpendicular to the plane, hence be a multiple of $n$. The dot product will therefore basically measure the length of that vector, but with the correct sign attached to it.

MvG
  • 42,596
  • 2
    This won't work if you have any zeros. – Oliver Dixon Apr 02 '16 at 10:16
  • 2
    @iLoveUnicorns: A single zero coordinate won't be a problem, and a full zero vector will have undefined angle no matter the method. What kind of problem do you have in mind? – MvG Apr 02 '16 at 16:04
  • 2
    Worth adding that the angle that is obtained if the angle of the vector $(x2,y2)$ with respect to $(x1,y1)$ -- as if $(x1,y1)$ is your axis of reference for the rotation. – Arturo Jan 24 '18 at 18:35
  • @OliverDixon: So if there is a 0 for one of the coordinates I might end up calculation the same angle for two different points? – stephanmg Nov 08 '19 at 15:55
0

Before reading this answer - Imagine your angle in a 3D space - you can look at it from the "front" and from the "back" (front and back are defined by you). The angle from the front will be the opposite of the angle that you see from the back. So there is no real sense in a value in a range larger than $[0,180]$.

If you still want to read more, enjoy

In the 3D case, your two vectors would be on some plane (the plane that you can get its normal from the cross-product of the two vectors). Getting a $[0,180]$ degrees angle is of course possible by computing $arccos(\frac{\vec{a}*\vec{b}}{|\vec{a}| *|\vec{b}|})$.

I think that what you can do, is to fix the Z axis, such that the two vectors will only differ in X and Y. Then you solve a 2D geometry problem. You should be able to fix the Z axis by dividing the two vectors by their Z component. Since the Z component is just a scalar, the vector directions will remain the same (the trend might change though, if this scalar is negative). You should remember whether these two scalars were both positive, both negative or one positive and one negative. In the last case, you're final results will be flipped!

If the Z component of the two vectors is $0$, then this step can (and actually must) be skipped. However, if only one of them has $0$ in its Z component, then it is probably impossible to compute the very precise angle, but you can still compute an approximation, by dividing the other vector by a very large number.

Having that, you can reduce vector $\vec{a}$ from both vectors $\vec{a}$ and $\vec{b}$ and then add the vector $(1, 0, 0)$ to both. Thus, vector $\vec{a}$ will be $(1, 0, 0)$, while vector $\vec{b}$ will be $(b_x, b_y, 0)$.

Now, if $b_y$ is positive, than your angle is $arccos(\frac{\vec{a}*\vec{b}}{|\vec{a}| *|\vec{b}|})$. Else, it is $360 - arccos(\frac{\vec{a}*\vec{b}}{|\vec{a}| *|\vec{b}|})$. Remember to use the opposite result if only one of the original Z values was negative, as described above!

  • This seems to be taking the difference vector in the z=1 plane then commuting the angle of that vector against the y=0 plane. Except there is this added vector (1,0,0) so it's not really the difference vector either. The relationship to the angle between the original lines appears quite slim to me, since individual steps don't preserve it. Voting down, sorry. First paragraph is good though. – MvG Aug 07 '19 at 06:53
-3

I write the formula like I wrote in excel . (xa,ya,xb,yb put in the cells a2,b2,c2,d2).

angle(vector.a,vector.b)

=(180/pi())* abs(pi()/2*((1+sign(a2))* (1-sign(b2^2))-(1+sign(c2))* (1-sign(d2^2)))

+pi()/4*((2+sign(a2))*sign(b2)-(2+sign(c2))*sign(d2))

+sign(a2*b2)*atan((abs(a2)-abs(b2))/(abs(a2)+abs(b2)))

-sign(c2*d2)*atan((abs(c2)-abs(d2))/(abs(c2)+abs(d2))))

The formula is giving the angle of two vectors a and b from 0 to 360 degrees,

in left wise direction for any value of the vectors coordinates.

For xa=ya=0 and or xb=yb=0 the result is undefined.