- 包含两个向量的平面是任意的,不与XY或其他基本平面平行
- Vn-是一个平面法线
- 两个向量以及法线都具有相同的起点O = {0, 0, 0}
- Va-是在Vn处测量左手旋转的参考
该角度应该按照这样的方式测量,即如果平面是XY平面,则Va将代表其X轴单位向量。
我猜我应该使用Va作为X轴和Vb和Vn的叉积作为Y轴进行一种坐标空间转换,然后只需使用类似于atan2()的2d方法。 有什么想法?公式?
该角度应该按照这样的方式测量,即如果平面是XY平面,则Va将代表其X轴单位向量。
我猜我应该使用Va作为X轴和Vb和Vn的叉积作为Y轴进行一种坐标空间转换,然后只需使用类似于atan2()的2d方法。 有什么想法?公式?
我目前正在使用的解决方案似乎在此处缺失。
假设平面法线已经归一化(|Vn| == 1
),有向角度简单地表示为:
从Va到Vb的右手旋转:
atan2((Va x Vb) . Vn, Va . Vb)
从Va到Vb的左手旋转:
atan2((Vb x Va) . Vn, Va . Vb)
它返回一个范围为[-PI,+PI]的角度(或任何可用的atan2实现返回的角度)。
“.”
和"x"
分别表示点乘和叉乘。
不需要显式分支或除法/向量长度计算。
为什么这有效的解释:假设alpha是向量之间的直接角度(0°至180°),beta是我们要查找的角度(0°至360°),并且具有beta == alpha
或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)
最后
tan(beta) = sin(beta) / cos(beta) == ((Va x Vb) . Vn) / (Va . Vb)
beta < 180
时,sin(alpha) * n1 . Vn == sin(alpha) == sin(beta)
,否则 sin(alpha) * n1 . Vn == -sin(alpha) == sin(beta)
。 - Adrian Leonhardangle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
angle = -angle;
}
angle = angle*sgn(dotProduct(Vn,cross))
替代 if
语句。不确定其效率是否更高,但看起来更简洁美观。 - NauticalMile你可以分两步来完成这个操作:
计算出两个向量之间的夹角
theta = acos(Va和Vb的点积)。假设Va和Vb已经被标准化了,这将给出两个向量之间的最小夹角。
确定夹角的正负号
找到向量V3 = Va和Vb的叉积。(顺序很重要)
如果(V3和垂直于它们平面的单位法向量的点积)是负数,则theta是负的。否则,theta为正。
使用点积可以得到角度的正负。 要获取角度的符号,请使用Vn *(Va x Vb)
的符号。在XY平面的特殊情况下,这仅缩减为Va_x * Vb_y-Va_y * Vb_x
。
up to sign
)。我的意思是角度的符号取决于叉积
。 - JichaoVn * (Va x Vb)
来获取角度的符号,其中包含了点积和叉积。这两个句子是独立的。 - Stephen CanonSOLUTION:
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
}
设θ为向量之间的夹角。令C = Va叉乘Vb。则
sinθ = length(C) / (length(Va) * length(Vb))
要确定θ是正数还是负数,请记住C垂直于Va和Vb,指向由right-hand rule确定的方向。因此,特别地,C与Vn平行。在您的情况下,如果C指向与Vn相同的方向,则θ为负,因为您想要左旋转。可能最简单的计算方法是快速检查Vn和C是否指向相同的方向,只需取它们的点积;如果它是正的,则它们指向相同的方向。
所有这些都遵循cross product的基本属性。
Vector
class 的 angle_signed_3d
。>>> import numpy as np
>>> from skspatial.objects import Vector
>>> np.degrees(Vector([1, 0, 0]).angle_signed_3d([0, -1, 0], direction_positive=[0, 0, 2]))
-90.0
>>> np.degrees(Vector([1, 0, 0]).angle_signed_3d([0, -1, 0], direction_positive=[0, 0, -5]))
90.0
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
atan2
函数时,不需要除以(|Va||Vb|)
来计算sin
和cos
。因为atan2
函数的工作原理会消去分母。 - John Alexiou