平面的三维旋转

10

我正在做一件事情,其中有一个在坐标系A中的平面,上面已经有一些点。我还有一个在空间中的法向量N。如何旋转坐标系A上的点,使得底层的平面与N具有相同的法向量方向?

想知道是否有人有好的想法来完成这个问题。谢谢。

3个回答

24
如果您已经有了或可以轻松计算出当前点所在平面的法向量,我认为最简单的方法是绕两个平面共同的轴旋转。以下是我的步骤:
  1. M为您当前平面法向量,N为您想要旋转到的平面法向量。如果M == N,您可以立即停止并保留原始点。
  2. 计算旋转角度:

    costheta = dot(M,N)/(norm(M)*norm(N))
    
    axis = unitcross(M, N)
    

    其中unitcross是一个函数,它执行叉积并将其归一化为单位向量,即unitcross(a, b) = cross(a, b) / norm(cross(a, b))。正如user1318499在评论中指出的那样,如果M == N,这一步可能会导致错误,除非你的unitcross实现在a == b时返回(0,0,0)

  3. 根据轴和角度计算旋转矩阵:

  4. c = costheta
    s = sqrt(1-c*c)
    C = 1-c
    rmat = matrix([ x*x*C+c    x*y*C-z*s  x*z*C+y*s ],
                  [ y*x*C+z*s  y*y*C+c    y*z*C-x*s ]
                  [ z*x*C-y*s  z*y*C+x*s  z*z*C+c   ])
    

    其中xyzaxis的分量。该公式在维基百科上有描述(链接)

  5. 对于每个点,计算其在新平面上的相应点,如下:

  6. newpoint = dot(rmat, point)
    

    当然,这并不是唯一的解决方案;正如peterk的答案所提到的,你可以进行无数次可能的旋转,将垂直于M的平面变换为垂直于N的平面。这意味着,在你按照上述步骤进行操作之后,你可以围绕N旋转平面,而你的点将位于不同的位置,但仍在同一个平面内。(换句话说,每个满足你条件的旋转都对应于在N周围执行上述过程后再进行另一次旋转。)但如果你不在乎你的点最终位于平面中的哪个位置,我认为这种围绕共同轴的旋转是让点进入你想要的平面的最简单方法。


    如果你没有M,但你有起始平面上点的坐标(相对于该平面中的一个原点),你可以通过两个点的位置x1x2计算起始法向量:

    M = cross(x1, x2)
    

    (你也可以在这里使用unitcross,但这并没有任何区别)。如果你有点相对于不在平面上的原点的坐标,你仍然可以这样做,但你需要三个点的位置:

    M = cross(x3-x1, x3-x2)
    

1
+1好答案。 我唯一的抱怨(它是否达到了抱怨的程度还有待商榷)是你没有提到四元数旋转作为第4步和第5步的可能替代方案。它们在某种程度上更有效率。 - andand
你在哪里使用轴? - padawan
1
@cagirici axis 的组成部分是出现在旋转矩阵公式中的 xyz - David Z
1
@DavidZ 再问一个问题:如果我想相对于 d 分量移动平面,我该怎么做? - padawan
@user1318499,这可能是 unitcross 实现的一部分,但让我编辑一下关于它的注释。 - David Z
显示剩余3条评论

2

一个单一的向量(即你的法线 - N)是不够的。你需要另外两个向量来表示其他两个维度。(想象一下,你的三维空间仍然可以围绕着法线旋转/旋转,并且你需要另外两个向量来确定它)。一旦你有了法线和平面上的另一个向量,第三个向量应该很容易找到(根据你的系统是左手系还是右手系)。

确保这三个向量都被标准化(长度为1),并将它们放入矩阵中;使用该矩阵来转换你的三维空间中的任何点(使用矩阵乘法)。这应该会给你新的坐标。


明白了!我需要想办法获取另一个向量 :S 谢谢! - bendervader

0
我在考虑创建一个单位向量[0,0,1],并使用两个平面上的点积来找到差异角度,并通过这些角度移动所有点。这是假设您希望z轴与法向量对齐,否则只需分别使用[x,0,0]或[0,y,0]作为x和y即可。

这难道不只会对准Z轴吗?在X或Y轴上还会有更多的自由度。 - bendervader

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