没有参考平面的两个矢量之间的有符号角度

met*_*rem 12 math 3d geometry vector

(三维)我正在寻找一种计算两个向量之间的有符号角度的方法,除了那些向量之外没有其他信息.正如在这个问题中所回答的那样,在给定矢量垂直的平面法线的情况下计算有符号角是很简单的.但是如果没有这个价值我就无法做到这一点.很明显,两个向量的交叉乘积产生了这样的正常,但是我使用上面的答案遇到了以下矛盾:

signed_angle(x_dir, y_dir) == 90
signed_angle(y_dir, x_dir) == 90
Run Code Online (Sandbox Code Playgroud)

我希望第二个结果是否定的.这是因为cross(x_dir, y_dir)cross(y_dir, x_dir)给定以下具有标准化输入的伪代码的情况下,叉积与反方向相反:

signed_angle(Va, Vb)
    magnitude = acos(dot(Va, Vb))
    axis = cross(Va, Vb)
    dir = dot(Vb, cross(axis, Va))
    if dir < 0 then
        magnitude = -magnitude
    endif
    return magnitude
Run Code Online (Sandbox Code Playgroud)

我不相信dir永远不会消极.

我已经看到了建议的atan2解决方案的相同问题.

我正在寻找一种方法:

signed_angle(a, b) == -signed_angle(b, a)
Run Code Online (Sandbox Code Playgroud)

com*_*orm 19

相关的数学公式:

  dot_product(a,b) == length(a) * length(b) * cos(angle)
  length(cross_product(a,b)) == length(a) * length(b) * sin(angle)
Run Code Online (Sandbox Code Playgroud)

对于三维向量之间的强大角度,您的实际计算应该是:

  s = length(cross_product(a,b))
  c = dot_product(a,b)
  angle = atan2(s, c)
Run Code Online (Sandbox Code Playgroud)

如果acos(c)单独使用,则角度较小时会出现严重的精度问题.计算s和使用atan2()可为所有可能的情况提供可靠的结果.

因为s总是非负的,所以得到的角度范围从0到pi.总会有一个等效的负角度(angle - 2*pi),但没有几何理由可以选择它.

  • 警告:该函数是可交换的,并且不应该是:从+x方向(1 0 0)到+y方向(0 1 0)的角度应该是+90°。反之亦然,从+y到+x,应该是-90°。但使用这个函数,`f(x, y) == f(y, x)`。它无法区分差异,因为“s”是非负数,而叉积是唯一可以告诉您两者之间方向的东西。 (3认同)

met*_*rem 2

谢谢大家。在查看了这里的评论并回顾了我想要做的事情之后,我意识到我可以使用给定的带符号角度的标准公式来完成我需要做的事情。我刚刚陷入了带符号角度函数的单元测试中。

作为参考,我将得到的角度反馈回旋转函数。我没有考虑到这样一个事实,即这自然会使用与signed_angle(输入向量的叉积)相同的轴,并且正确的旋转方向将遵循该轴所面向的任何方向。

更简单地说,这两者都应该“做正确的事”并朝不同的方向旋转:

rotate(cross(Va, Vb), signed_angle(Va, Vb), point)
rotate(cross(Vb, Va), signed_angle(Vb, Va), point)
Run Code Online (Sandbox Code Playgroud)

其中第一个参数是旋转轴,第二个参数是旋转量。

  • 您能分享您的“signed_angle”实现吗? (2认同)