怎么计算两个向量间的夹角呢?

这里主要分两种情况,对于二维向量和三维向量来分别讨论。

1. 二维向量

二维向量的情况相对简单,根据向量间的点乘关系

v1v2=||v1||||v2||cosθ
<script type="math/tex; mode=display" id="MathJax-Element-1"> v_1 \cdot v_2 = ||v_1||||v_2||cos\theta</script>
可以得到:
θ=acos(v1v2/||v1||||v2||)
<script type="math/tex; mode=display" id="MathJax-Element-2"> \theta = acos(v_1\cdot v_2/||v_1||||v_2||)</script>
如果调用C/C++数学库函数acos,计算得到的结果的取值范围在 [0,π] <script type="math/tex" id="MathJax-Element-3">[0,\pi]</script>。

这里得到的夹角并不在0到360度之间(或者-180到180度),也就是说得到的结果并不能告诉我们 v1 <script type="math/tex" id="MathJax-Element-4">v_1</script>在 v2 <script type="math/tex" id="MathJax-Element-5">v_2</script>前面或者 v1 <script type="math/tex" id="MathJax-Element-6">v_1</script>在 v2 <script type="math/tex" id="MathJax-Element-7">v_2</script>后面,考虑到atan2函数可以用来计算出角度准确处于哪一个象限,可以用atan2来计算夹角。
计算从v2到v1的夹角公式:

θ=atan2(v2.y,v2.x)atan2(v1.y,v1.x)
<script type="math/tex; mode=display" id="MathJax-Element-8">\theta = atan2(v_2.y, v_2.x) - atan2(v_1.y, v_1.x) </script>

需要注意的是:atan2的取值范围是 [π,π] <script type="math/tex" id="MathJax-Element-9">[-\pi, \pi]</script>,在进行相减之后得到的夹角是在 [2π,2π] <script type="math/tex" id="MathJax-Element-10">[-2\pi, 2\pi]</script>,因此当得到的结果大于 π <script type="math/tex" id="MathJax-Element-11">\pi</script>时,对结果减去 2π <script type="math/tex" id="MathJax-Element-12">2\pi</script>,当结果小于 π <script type="math/tex" id="MathJax-Element-13">-\pi</script>时,对结果加上 2π <script type="math/tex" id="MathJax-Element-14">2\pi</script>

2. 三维向量

2.1 使用旋转轴和旋转角的方式

旋转角可以使用上面讨论的方式得到:

θ=acos(v1v2/||v1||||v2||)
<script type="math/tex; mode=display" id="MathJax-Element-21"> \theta = acos(v_1\cdot v_2/||v_1||||v_2||)</script>
旋转轴是两个向量的叉乘向量,长度是 ||v1||||v2||sin(θ) <script type="math/tex" id="MathJax-Element-22">||v_1||||v_2||sin(\theta)</script>
需要注意的是在acos取值在0度和180度这两个特殊值的时候,要注意一下,当两个向量夹角是0度或者180度的时候,它们是平行的关系(同向或者反向),当夹角是0度时,旋转轴可以是任意轴,因为根本就没有旋转。当夹角是180度的时候,旋转轴只要和向量呈90度夹角即可,可以有无穷多个可能的选择轴。

2.2 使用四元数的方式

使用四元数来旋转一个向量,使用下面的方式:
p2 = q * p1 * conj(q)
其中:
p2 是旋转之后的向量
p1是旋转之前的向量
q是用来旋转的四元数
在这里知道p2和p1,用来求解四元数还是相当麻烦的。因此一个比较好的思路仍然是使用上面旋转轴和旋转角的方式,不过将结论转换成四元数罢了。
关于转换的方式,可以参考我写的另外一篇文章《旋转变换(三)四元数》

参考文献:

  1. Maths - Angle between vectors
  2. Maths - Trigonometry - Inverse trig functions
  3. Maths - Issues with Relative Angles
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐