直接计算2个向量之间的顺时针角度的方法

Mir*_*pas 64 c++ math angle

我想找出2个矢量(2D,3D)之间的顺时针角度.

使用点积的clasic方式给出了内角(0-180度),我需要使用一些if语句来确定结果是否是我需要的角度或其补码.

你知道计算顺时针角度的直接方法吗?

MvG*_*MvG 156

2D案例

就像点积与角的余弦成正比一样,行列式与其正弦成正比.所以你可以像这样计算角度:

dot = x1*x2 + y1*y2      # dot product between [x1, y1] and [x2, y2]
det = x1*y2 - y1*x2      # determinant
angle = atan2(det, dot)  # atan2(y, x) or atan2(sin, cos)
Run Code Online (Sandbox Code Playgroud)

该角度的方向与坐标系的方向匹配.在左手坐标系中,即x指向右和y向下,这是计算机图形常见的,这意味着你得到顺时针角度的正号.如果坐标系的方向是数学的y向上,则得到逆时针角度,就像数学中的惯例一样.更改输入的顺序将改变符号,因此如果您对符号不满意,只需交换输入.

3D案例

在3D中,两个任意放置的矢量定义它们自己的旋转轴,垂直于两者.该旋转轴没有固定的方向,这意味着您无法唯一地固定旋转角度的方向.一个常见的惯例是让角度始终为正,并使轴线定向成适合正角度的方向.在这种情况下,归一化矢量的点积足以计算角度.

dot = x1*x2 + y1*y2 + z1*z2    #between [x1, y1, z1] and [x2, y2, z2]
lenSq1 = x1*x1 + y1*y1 + z1*z1
lenSq2 = x2*x2 + y2*y2 + z2*z2
angle = acos(dot/sqrt(lenSq1 * lenSq2))
Run Code Online (Sandbox Code Playgroud)

平面嵌入3D

一种特殊情况是您的矢量不是任意放置,而是位于具有已知法向量n的平面内.然后,旋转轴也将在方向n上,并且n的方向将固定该轴的方向.在这种情况下,您可以调整上面的2D计算,包括n进入行列式,使其大小为3×3.

dot = x1*x2 + y1*y2 + z1*z2
det = x1*y2*zn + x2*yn*z1 + xn*y1*z2 - z1*y2*xn - z2*yn*x1 - zn*y1*x2
angle = atan2(det, dot)
Run Code Online (Sandbox Code Playgroud)

使其工作的一个条件是法向量n具有单位长度.如果没有,你必须将其标准化.

作为三重产品

该决定因素也可以表示为三元产品,如建议编辑中指出的@Excrubulent.

det = n · (v1 × v2)
Run Code Online (Sandbox Code Playgroud)

这在某些API中可能更容易实现,并且对这里发生的事情提供了不同的视角:交叉积与角度的正弦成正比,并且将垂直于平面,因此是n的倍数.因此,点积基本上将测量该矢量的长度,但附加了正确的符号.

  • @rbaleksandar:`atan2`通常在[-180°,180°]范围内.为了得到[0°,360°]而不区分大小写,可以用`atan2(-y,-x)+ 180°`替换`atan2(y,x)`. (5认同)
  • 有一个upvote - 我不能打扰弄清楚其他答案是否正确,你的是最清晰,最可读的,所以它是帮助我的人. (3认同)
  • Noooooo 永远不要使用点积的 acos!这在数学上是正确的,但在实践中非常不准确。你可以用另一个 atan2(det,dot); 替换你的 3d 方法;在这种情况下, det 将是叉积的长度。 (3认同)
  • 对于2D我得到(0,180)和(-180,0).可以检查结果何时为负,并添加360以获得一个漂亮的顺时针角度(例如,如果它是-180,将360结果添加到180,对于-90添加360结果为270等).不知道这只是我的计算还是`qAtan2(y,x)`(来自Qt框架)的实现,但如果有人遇到与我相同的问题,这可能会有所帮助. (2认同)
  • @N4ppeL 有关点积 acos 不良行为的更多信息,请尝试此(在 2 个不同站点上提出的问题,具有不同的答案和参考):https://math.stackexchange.com/questions/1143354/numerically-stable-method -for-angle- Between-3d-vectors/1782769 https://scicomp.stackexchange.com/questions/27689/numerically-stable-way-of-computing-angles- Between-vectors (2认同)

sir*_*ton 6

这个答案与MvG 的相同,但解释不同(这是我努力理解 MvG 解决方案为何有效的结果)。

\n

相对于给定法线( ) 的视点,thetax到 的逆时针角度由下式给出yn||n|| = 1

\n
\n

atan2( 点(n, 交叉(x,y)), 点(x,y) )

\n

(1) = atan2( ||x|| ||y|| sin(theta), \xc2\xa0||x|| ||y|| cos(theta) )

\n

(2) = atan2( sin(theta), cos(theta) )

\n

(3) = x 轴与向量之间的逆时针角度 (cos(theta), sin(theta))

\n

(4) = θ

\n
\n

其中||x||表示 的大小x

\n

步骤(1)之后注意到

\n
\n

交叉(x,y)= ||x|| ||y|| 正弦(θ)n,

\n
\n

所以

\n
\n

点(n,交叉(x,y))

\n

= 点(n, ||x|| ||y|| sin(theta) n)

\n

= ||x|| ||y|| 正弦(θ) 点(n, n)

\n
\n

这等于

\n
\n

||x|| ||y|| 罪(θ)

\n
\n

如果||n|| = 1

\n

步骤 (2) 由 的定义得出atan2,注意到atan2(cy, cx) = atan2(y,x),其中c是标量。步骤(3)由 的定义得出atan2cos步骤 (4) 由和的几何定义得出sin

\n


kas*_*sak 5

要计算角度,您只需要调用atan2(v1.s_cross(v2), v1.dot(v2))2D情况.s_cross交叉生产的标量模拟在哪里(平行四边形的符号区域).对于2D楔形生产的情况.对于3D情况,您需要定义顺时针旋转,因为从平面的一侧顺时针是一个方向,从平面的另一侧是另一个方向=)

编辑:这是逆时针角度,顺时针角度恰好相反

  • @Felics 在 2D 交叉生产中通常意味着楔形生产 http://en.wikipedia.org/wiki/Wedge_product 这是平行四边形的有符号区域。对于 2D 情况,该公式绝对正确,因为它 dot = |v1||v2|*cos 和 cross = |v1||v2|sin。这就是为什么atan2 在整个圆范围内给出正确的角度。正如我所说,对于 3d 情况,您需要做出一些假设才能对顺时针方向进行一些扩展 (2认同)

Car*_*rau 5

由于最简单和最优雅的解决方案之一隐藏在评论之一中,我认为将其作为单独的答案发布可能会很有用。

\n

acos可能会导致非常小的角度不准确,因此atan2通常是首选。对于三维情况:

\n
dot = x1*x2 + y1*y2 + z1*z2\ncross_x = (y1*z2 \xe2\x80\x93 z1*y2)\ncross_y = (z1*x2 \xe2\x80\x93 x1*z2) \ncross_z = (x1*y2 \xe2\x80\x93 y1*x2)\ndet = sqrt(cross_x*cross_x + cross_y*cross_y + cross_z*cross_z)\nangle = atan2(det, dot)\n
Run Code Online (Sandbox Code Playgroud)\n

  • 谢谢。添加链接到相应的答案或至少引用用户将是一件好事 (2认同)