Search code examples
c#math3d

The angle between two 3D vectors with a result range 0 - 360


I'm looking for a way to calculate the angle between three points considered as two vectors (see below):

using System.Windows.Media.Media3D;

public static float AngleBetweenThreePoints(Point3D[] points)
{
    var v1 = points[1] - points[0];
    var v2 = points[2] - points[1];

    var cross = Vector3D.CrossProduct(v1, v2);
    var dot = Vector3D.DotProduct(v1, v2);

    var angle = Math.PI - Math.Atan2(cross.Length, dot);
    return (float) angle;
}

If you give this the following points:

var points = new[]
{
    new Point3D(90, 100, 300),
    new Point3D(100, 200, 300),
    new Point3D(100, 300, 300)
};

or the following:

var points = new[]
{
    new Point3D(110, 100, 300),
    new Point3D(100, 200, 300),
    new Point3D(100, 300, 300)
};

You get the same result. I can see the cross product in the function returns (0, 0, 10000) in the first case, and (0, 0, -10000) in the second but this information gets lost with cross.Length which could never return a -ve result.

What I'm looking for is a result range 0 - 360 not limited to 0 - 180. How do I achieve that?


Solution

  • The answer is to provide a reference UP vector:

    public static float AngleBetweenThreePoints(Point3D[] points, Vector3D up)
    {
        var v1 = points[1] - points[0];
        var v2 = points[2] - points[1];
    
        var cross = Vector3D.CrossProduct(v1, v2);
        var dot = Vector3D.DotProduct(v1, v2);
    
        var angle = Math.Atan2(cross.Length, dot);
    
        var test = Vector3D.DotProduct(up, cross);
        if (test < 0.0) angle = -angle;
        return (float) angle;
    }
    

    This came from here: https://stackoverflow.com/a/5190354/181622