3

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?

imekon
  • 1,501
  • 4
  • 22
  • 39
  • The don't subtract from Math.PI which is 180 degrees. Your results is 0 to 360 so when you subtract from 180 you get a results from +180 to -180. – jdweng Apr 19 '17 at 11:01
  • 2
    In 3D space, the angle between two vectors is defined only between 0 and 180 degrees. In what situation would you want an answer between 180 and 360 degrees? That is easy to define in 2D space as a directed or signed angle, but that does not extend to 3D space. – Rory Daulton Apr 19 '17 at 11:17

2 Answers2

4

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

Community
  • 1
  • 1
imekon
  • 1,501
  • 4
  • 22
  • 39
2

Are you looking for this ?

θ_radian = arccos ( (​P⋅Q) / ​(∣P∣∣Q∣)​ ​​) with vectors P and Q

θ_radian = θ_degree * π / 180

EDIT 0-360 range

angle = angle * 360 / (2*Math.PI);
if (angle < 0) angle = angle + 360;
Ythio Csi
  • 379
  • 2
  • 14
  • 2
    That was my first solution however it has the same issue. It has a limit on the angle of 0 - 180. – imekon Apr 19 '17 at 12:13
  • 1
    Well a radian angle is on the [-π;π] interval and a π radian angle is 180 degrees, so yeah, that's your limit of 0-180. But i showed you a formula to convert from radian to degrees. – Ythio Csi Apr 19 '17 at 12:28
  • 2
    arccos has a result range of 0 to PI (not PI * 2). Hence the limit I mentioned of 180. – imekon Apr 19 '17 at 13:19