Using atan2 to find angle between two vectors

131,342

Solution 1

 atan2(vector1.y - vector2.y, vector1.x - vector2.x)

is the angle between the difference vector (connecting vector2 and vector1) and the x-axis, which is problably not what you meant.

The (directed) angle from vector1 to vector2 can be computed as

angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x);

and you may want to normalize it to the range [0, 2 π):

if (angle < 0) { angle += 2 * M_PI; }

or to the range (-π, π]:

if (angle > M_PI)        { angle -= 2 * M_PI; }
else if (angle <= -M_PI) { angle += 2 * M_PI; }

Solution 2

A robust way to do it is by finding the sine of the angle using the cross product, and the cosine of the angle using the dot product and combine the two with the Atan2() function.

In C# this is

public struct Vector2
{
    public double X, Y;

    /// <summary>
    /// Returns the angle between two vectos
    /// </summary>
    public static double GetAngle(Vector2 A, Vector2 B)
    {
        // |A·B| = |A| |B| COS(θ)
        // |A×B| = |A| |B| SIN(θ)

        return Math.Atan2(Cross(A,B), Dot(A,B));
    }

    public double Magnitude { get { return Math.Sqrt(Dot(this,this)); } }

    public static double Dot(Vector2 A, Vector2 B)
    {
        return A.X*B.X+A.Y*B.Y;
    }
    public static double Cross(Vector2 A, Vector2 B)
    {
        return A.X*B.Y-A.Y*B.X;
    }
}
class Program
{
    static void Main(string[] args)
    {
        Vector2 A=new Vector2() { X=5.45, Y=1.12};
        Vector2 B=new Vector2() { X=-3.86, Y=4.32 };

        double angle=Vector2.GetAngle(A, B) * 180/Math.PI;
        // angle = 120.16850967865749
    }
}

See test case above in GeoGebra.

GeoGebra

Solution 3

I think a better formula was posted here: http://www.mathworks.com/matlabcentral/answers/16243-angle-between-two-vectors-in-3d

angle = atan2(norm(cross(a,b)), dot(a,b))

So this formula works in 2 or 3 dimensions. For 2 dimensions this formula simplifies to the one stated above.

Solution 4

Nobody pointed out that if you have a single vector, and want to find the angle of the vector from the X axis, you can take advantage of the fact that the argument to atan2() is actually the slope of the line, or (delta Y / delta X). So if you know the slope, you can do the following:

given:

A = angle of the vector/line you wish to determine (from the X axis).

m = signed slope of the vector/line.

then:

A = atan2(m, 1)

Very useful!

Solution 5

If you care about accuracy for small angles, you want to use this:

angle = 2*atan2(|| ||b||a - ||a||b ||, || ||b||a + ||a||b ||)

Where "||" means absolute value, AKA "length of the vector". See https://math.stackexchange.com/questions/1143354/numerically-stable-method-for-angle-between-3d-vectors/1782769

However, that has the downside that in two dimensions, it loses the sign of the angle.

Share:
131,342
user3150201
Author by

user3150201

Updated on August 03, 2021

Comments

  • user3150201
    user3150201 almost 3 years

    I understand that:

    atan2(vector.y, vector.x) = the angle between the vector and the X axis.

    But I wanted to know how to get the angle between two vectors using atan2. So I came across this solution:

    atan2(vector1.y - vector2.y, vector1.x - vector2.x)
    

    My question is very simple:

    Will the two following formulas produce the same number?

    • atan2(vector1.y - vector2.y, vector1.x - vector2.x)

    • atan2(vector2.y - vector1.y, vector2.x - vector1.x)

    If not: How do I know what vector comes first in the subtractions?

  • user3150201
    user3150201 over 10 years
    Thanks for the help. So what you suggest, is getting the angle between vector2 and the x axis (let's call it angle1), getting the angle between vector1 and the x axis (lets call it angle2), and then subtracting the two. Correct? If so: What would be the difference between angle1 and angle2? Would angle1 be x and angle2 be -x? More importantly, how do I choose which angle comes first in the subtraction?
  • Martin R
    Martin R over 10 years
    @user3150201: It depends on what you want, because there are two angles between the vectors. - The above method gives an angle a such that if you turn vector1 counter-clockwise by this angle, then the result is vector2.
  • Martin R
    Martin R over 10 years
    @user3150201: Or do you want the smaller of the two possible angles between the vectors, i.e. a result in the range 0 .. Pi ?
  • John Alexiou
    John Alexiou over 10 years
    I added a graphical test case for illustration.
  • Martin R
    Martin R over 10 years
    I am always reluctant to call something the proper method, but yes, this is fine. Note that you don't have to divide by (A.Magnitude*B.Magnitude) (and therefore don't need to calculate the magnitude at all).
  • John Alexiou
    John Alexiou over 10 years
    Yes, I will edit the answer. It is the proper way in a mathematical way becasue it can works in both 2D and 3D.
  • andand
    andand over 10 years
    That's a very non-standard definition of cross product. The more traditional definition of the cross product is given at en.wikipedia.org/wiki/Cross_product.
  • Martin R
    Martin R over 10 years
    @andand: See (8), (9) in mathworld.wolfram.com/CrossProduct.html. As far as I know, it is often called cross-product of two vectors in the plane.
  • John Alexiou
    John Alexiou over 10 years
    Just expand out [ax,ay,0]×[bx,by,0] = ax*by-ay*bx. You can always go from 3D to 2D by setting the z as zero.
  • andand
    andand over 10 years
    @MartinR Right, the definition above is for the determinant, not the cross product... the cross product returns a vector orthogonal to the other two.
  • John Alexiou
    John Alexiou over 10 years
    @andand 2D × results in an orhogonal vector [0,0,ax*by-ay*bx] and above I have only z component returned in Cross(A,B).
  • Martin R
    Martin R over 8 years
    That is what @ja72 suggested in his/her answer stackoverflow.com/a/21486462/1187415.
  • Shan Carter
    Shan Carter over 7 years
  • Dima
    Dima about 7 years
    took me a while to realize that norm is not normalize, but it is a vector length
  • StayOnTarget
    StayOnTarget over 6 years
    Thanks for mentioning GeoGebra, an awesome tool!
  • Blue
    Blue over 5 years
    Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
  • ChronoTrigger
    ChronoTrigger over 5 years
    Actually, A·B = |A| |B| COS(θ) and |A×B| = |A| |B| SIN(θ), since A·B returns a scalar and A×B a vector. That means that if you want to get the angle in [0, pi) you have to do Math.Atan2(Math.Abs(Cross(A,B)), Dot(A,B));
  • John Alexiou
    John Alexiou over 5 years
    @ChronoTrigger - I make a distinction between clockwise and counterclockwise rotations based on the order of the operands.
  • Admin
    Admin over 5 years
    You should combine the answers to one. Otherwise people might not really accept the answers
  • Camille Goudeseune
    Camille Goudeseune almost 4 years
    This formula discards the sense of the angle (+ or -, clockwise or counterclockwise). You can see this because swapping v1 and v2 doesn't change the answer.
  • R2RT
    R2RT about 3 years
    This formula discards sign of y component, since norm(cross(a,b)) will be always positive.
  • ead
    ead over 2 years
    This solution needs 2 calls of atan2, which are costly, while this answer stackoverflow.com/a/21486462/5769463 needs only one.
  • Martin R
    Martin R over 2 years
    @ead: That is correct, the difference is measurable but not dramatic. With a simple C program computing the angles between 1,000,000 random vectors I got 97 milliseconds vs 73 milliseconds. That may or many not be relevant in a real-world application.
  • John Alexiou
    John Alexiou over 2 years
    Note that I read somewhere recently that a bit more robust is not consider only the dot product and use angle = Math.Acos(Dot(A,B));
  • Elaskanator
    Elaskanator over 2 years
    It is not robust, because the cross product does not exist in higher dimensions (see this answer). Unfortunately the standard inner product method (see here) only returns up to Pi radians (180°).
  • John Alexiou
    John Alexiou over 2 years
    @Elaskanator - what is the meaning of an angle in higher dimensions (beyond 3?) I guess you can always do in the inner product and use acos(x) to get this "angle".