两个三维向量之间的夹角,结果范围为0到360

3
我正在寻找一种计算三个点之间角度的方法,这三个点被视为两个向量(见下文):
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;
}

如果您给出以下几点:
var points = new[]
{
    new Point3D(90, 100, 300),
    new Point3D(100, 200, 300),
    new Point3D(100, 300, 300)
};

或以下内容:
var points = new[]
{
    new Point3D(110, 100, 300),
    new Point3D(100, 200, 300),
    new Point3D(100, 300, 300)
};

你将得到相同的结果。我可以在函数返回中看到叉积的结果,第一种情况下是(0, 0, 10000),第二种情况下是(0, 0, -10000),但这个信息会因为cross.Length而丢失,它永远不会返回负数.
我想要的是一个结果范围在0-360之间,而不是仅限于0-180。我该如何实现这一点?

不要从Math.PI中减去180度。你的结果是0到360,所以当你从180中减去时,你会得到一个从+180到-180的结果。 - jdweng
2
在三维空间中,两个向量之间的角度仅定义在0到180度之间。在什么情况下您需要一个介于180到360度之间的答案?在二维空间中,有一个有向或带符号角度的简单定义,但这并不适用于三维空间。 - Rory Daulton
3个回答

4
答案是提供一个参考的UP向量:
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;
}

该内容来源于这里:https://dev59.com/rG435IYBdhLWcg3w1juV#5190354

该链接无法翻译。

2

您是否在寻找这个?

θ弧度 = arccos((P·Q) / (∣P∣∣Q∣)),其中P和Q是向量

θ弧度 = θ度数 * π / 180

编辑0-360范围

angle = angle * 360 / (2*Math.PI);
if (angle < 0) angle = angle + 360;

2
那是我的第一个解决方案,但它有相同的问题。它在0-180度角上有限制。 - imekon
1
一个弧度角在[-π;π]区间内,而一个π弧度角是180度,所以是的,这就是你0-180的限制。但是我向你展示了一个从弧度转换为度数的公式。 - Ythio Csi
2
arccos 的结果范围是 0 到 PI(而不是 PI * 2)。因此,我提到了 180 的限制。 - imekon

1
你已经拥有了所有你需要的信息。如果叉乘是正的,角度在0到180之间;如果是负的,角度在0到-180之间(或者在180到360之间)。 可以使用一个简单的if语句来改变角度的符号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接