必要なのは、同じ3D平面内にあり、同じOriginを持つ2つのベクトルVaとVb間の符号付き回転角です。
角度は、平面がXY平面の場合、VaはそのX軸単位ベクトルを表すように測定する必要があります。
VaをX軸として使用し、VbとVnの外積をY軸として使用し、atan2()などの2dメソッドを使用して、一種の座標空間変換を実行する必要があると思います。何か案は?フォーミュラ?
2つのベクトルの外積を使用して、2つのベクトルによって形成される平面の法線を取得します。次に、その方向と元の平面法線との間の内積をチェックして、同じ方向を向いているかどうかを確認します。
angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
angle = -angle;
}
私が現在使用しているソリューションは、ここにはありません。平面の法線が正規化されていると仮定すると(_|Vn| == 1
_)、符号付き角度は次のようになります。
atan2((Vb x Va) . Vn, Va . Vb)
範囲[-PI、+ PI](または利用可能なatan2実装が返すもの)の角度を返します。
_.
_とx
はそれぞれドットとクロス積です。
明示的な分岐および除算/ベクトル長の計算は必要ありません。右回転には左回転ではなく_Va x Vb
_を使用します
これが機能する理由の説明:_beta == alpha
_または_beta == 360° - alpha
_を使用して、アルファをベクトル間の直接の角度(0°から180°)、ベータを探している角度(0°から360°)にします
_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)
_
これは2つの手順で実行できます。
2つのベクトル間の角度を決定する
theta = acos(Va、Vbのドット積)。 Vaと仮定すると、Vbは正規化されます。これにより、2つのベクトル間の最小角度が得られます
角度の符号を決定する
ベクトルV3 = Va、Vbの外積を求めます。 (順序は重要です)
(V3の内積、Vn)が負の場合、シータは負です。それ以外の場合、シータは正です。
ドット積 を使用して、サインアップする角度を取得できます。角度の符号を取得するには、Vn * (Va x Vb)
の符号を取ります。 XY平面の特殊なケースでは、これはただVa_x*Vb_y - Va_y*Vb_x
。
1つのベクトルを他のベクトルに交差させ、正規化して単位ベクトルを取得します。
2つのベクトル間の角度のサインは、2つのベクトルの大きさで割った外積の大きさに等しくなります。
Thetaをベクトル間の角度とします。 C = Vaとクロス積Vbとします。それから
sin theta = length(C)/(length(Va)* length(Vb))
シータが正か負かを判断するには、CがVaとVbに垂直であり、 右手の法則 によって決定される方向を指していることに注意してください。したがって、特にCはVnと平行です。あなたの場合、CがVnと同じ方向を指している場合、左回転が必要なため、シータは負になります。おそらく、VnとCが同じ方向を向いているかどうかをすばやくチェックする最も簡単な計算方法は、ドット積を取得することです。正の場合、それらは同じ方向を指します。
これはすべて、 外積 の基本プロパティから得られます。
アドバンストカスタマーは次のソリューションを提供しました(元は質問の編集)。
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
}
Vxがx軸であり、法線Vnが与えられた場合、クロス積でy軸を取得でき、ベクトルVbをVxおよびVyに投影できます(ドット積により、Vbの投影の長さを取得できます) VxおよびVy)、平面上の(x、y)座標が与えられると、atan2(y、x)を使用して範囲[-pi、+ pi]の角度を取得できます。
これは、2Dまたは3Dの2つのベクトルu、v間の符号付き角度を計算するMatlabコードです。コードは自明です。符号の規則により、ixとiy([1,0,0]、[0,1,0])またはiyとiz([0,1,0]、[0、 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