在同一平面内具有相同原点的两个3D矢量之间的有符号角度

时间:2011-03-04 01:07:33

标签: math vector 3d geometry

我需要的是两个矢量Va和Vb之间的有符号旋转角度,它们位于同一个3D平面内且具有相同的原点,知道:

  1. 两个矢量的平面是任意的,与XY或任何其他基本平面不平行
  2. Vn - 平面正常
  3. 两个向量与法线具有相同的原点O = {0,0,0}
  4. Va - 是在Vn
  5. 测量左旋转的参考

    角度应该以这样的方式测量,因此如果平面是XY平面,Va将代表它的X轴单位矢量。

    我想我应该通过使用Va作为X轴并将Vb和Vn的叉积作为Y轴来执行一种坐标空间变换,然后使用像atan2()之类的一些2d方法。有任何想法吗?公式?

9 个答案:

答案 0 :(得分:55)

使用两个向量的叉积来得到由两个向量形成的平面的法线。然后检查它与原始平面法线之间的点积,看它们是否面向同一方向。

angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
  angle = -angle;
}

答案 1 :(得分:31)

我目前使用的解决方案似乎在这里缺失。 假设平面法线标准化(|Vn| == 1),则有符号角度为:

atan2((Vb x Va) . Vn, Va . Vb)

返回[-PI,+ PI]范围内的角度(或任何可用的atan2实现返回的角度)。

.x分别是点和叉号。

不需要明确的分支,也不需要除法/向量长度计算。 使用Va x Vb进行右手旋转而不是左手旋转

解释为什么这样做:让alpha为矢量(0°到180°)之间的直接角度和beta我们正在寻找的角度(0°到360°)beta == alpha或{{1 }}

beta == 360° - alpha

最后

Va . Vb == |Va| * |Vb| * cos(alpha)    (by definition) 
        == |Va| * |Vb| * cos(beta)     (cos(alpha) == cos(-alpha) == cos(360° - alpha)


Va x Vb == |Va| * |Vb| * sin(alpha) * n1  
    (by definition; n1 is a unit vector perpendicular to Va and Vb with 
     orientation matching the right-hand rule)

Therefore (again assuming Vn is normalized):
   n1 . Vn == 1 when beta < 180
   n1 . Vn == -1 when beta > 180

==>  (Va x Vb) . Vn == |Va| * |Vb| * sin(beta)

答案 2 :(得分:13)

您可以分两步完成此操作:

  1. 确定两个矢量之间的角度

    theta = acos(Va,Vb的点积)。假设Va,Vb被归一化。这将给出两个矢量之间的最小角度

  2. 确定角度的符号

    查找向量V3 = Va,Vb的交叉乘积。 (顺序很重要)

    如果(V3,Vn的点积)为负,则θ为负。否则,theta是正面的。

答案 3 :(得分:7)

您可以使用dot product获取角度。要获得角度的符号,请使用Vn * (Va x Vb)的符号。在XY平面的特殊情况下,这将减少到Va_x*Vb_y - Va_y*Vb_x

答案 4 :(得分:2)

将一个向量交叉到另一个向量并进行标准化以获得单位向量。

两个向量之间角度的正弦值等于叉积的大小除以两个向量的大小:

http://mathworld.wolfram.com/CrossProduct.html

答案 5 :(得分:1)

设θ是矢量之间的角度。设C = Va交叉乘积Vb。然后

  

sin theta = length(C)/(length(Va)*   长度(Vb)中)

要确定θ是正还是负,请记住C垂直于Va,Vb指向right-hand rule确定的方向。所以特别是,C与Vn平行。在你的情况下,如果C指向与Vn相同的方向,那么theta是负的,因为你想要左手旋转。可能最简单的计算方法是快速检查Vn和C是否指向同一方向,只是采取他们的点积;如果它是积极的,他们指向同一个方向。

所有这些都来自cross product的基本属性。

答案 6 :(得分:1)

假设Vx是x轴,给定正常的Vn,你可以通过叉积获得y轴,你可以将矢量Vb投影到Vx和Vy(通过点积你可以得到投影的长度对于Vx和Vy上的Vb,给定平面上的(x,y)坐标,你可以使用atan2(y,x)来获得[-pi,+ pi]范围内的角度

答案 7 :(得分:1)

高级客户提供了以下解决方案(最初是对问题的编辑):

SOLUTION:

sina = |Va x Vb| / ( |Va| * |Vb| )
cosa = (Va . Vb) / ( |Va| * |Vb| )

angle = atan2( sina, cosa )

sign = Vn . ( Va x Vb )
if(sign<0)
{
    angle=-angle
}

答案 8 :(得分:0)

这是用于计算2D或3D中两个向量u,v之间的有符号角度的Matlab代码。代码是自我解释的。符号约定是在ix和iy([1,0,0],[0,1,0])或iy和iz([0,1,0],[0之间]输出正+ 90°。 0,1])

function thetaDEG = angDist2Vecs(u,v)

if length(u)==3
    %3D, can use cross to resolve sign
    uMod = sqrt(sum(u.^2));
    vMod = sqrt(sum(v.^2));
    uvPr = sum(u.*v);
    costheta = min(uvPr/uMod/vMod,1);

    thetaDEG = acos(costheta)*180/pi;

    %resolve sign
    cp=(cross(u,v));
    idxM=find(abs(cp)==max(abs(cp)));
    s=sign(cp(idxM(1)));
    if s < 0
        thetaDEG = -thetaDEG;
    end
elseif length(u)==2
    %2D use atan2
    thetaDEG = (atan2(v(2),v(1))-atan2(u(2),u(1)))*180/pi;
else
    error('u,v must be 2D or 3D vectors');
end