我需要的是两个矢量Va和Vb之间的有符号旋转角度,它们位于同一个3D平面内且具有相同的原点,知道:
角度应该以这样的方式测量,因此如果平面是XY平面,Va将代表它的X轴单位矢量。
我想我应该通过使用Va作为X轴并将Vb和Vn的叉积作为Y轴来执行一种坐标空间变换,然后使用像atan2()之类的一些2d方法。有任何想法吗?公式?
答案 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)
您可以分两步完成此操作:
确定两个矢量之间的角度
theta = acos(Va,Vb的点积)。假设Va,Vb被归一化。这将给出两个矢量之间的最小角度
确定角度的符号
查找向量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)
将一个向量交叉到另一个向量并进行标准化以获得单位向量。
两个向量之间角度的正弦值等于叉积的大小除以两个向量的大小:
答案 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