1. ホーム
  2. c++

[解決済み】2つのベクトル間の時計回りの角度を直接計算する方法

2022-03-17 19:16:49

質問

2つのベクトル(2D, 3D)の間の時計回りの角度を求めたい。

内角(0-180度)を求めるには、ドットプロダクトを使うのが一般的ですが、結果が必要な角度かその補数かを判断するには、いくつかの if ステートメントを使う必要があります。

時計回りの角度を直接計算する方法をご存じですか?

どのように解決するのですか?

2Dケース

と同じように ドットプロダクト は角度の余弦に比例するので 行列式 はその正弦に比例する。ですから、このように角度を計算することができます。

dot = x1*x2 + y1*y2      # dot product between [x1, y1] and [x2, y2]
det = x1*y2 - y1*x2      # determinant
angle = atan2(det, dot)  # atan2(y, x) or atan2(sin, cos)

この角度の向きは、座標系の向きと一致する。において 左利き座標系 すなわち x 右向きで y コンピュータグラフィックスで一般的なように、時計回りの角度を正の符号で表すことになる。座標系の向きが数学的に y を上にすると、数学の慣習に従って反時計回りの角度になります。入力の順番を変えると符号が変わるので、符号に不満がある場合は入力を入れ替えればよい。

3Dの場合

3Dでは、任意に配置された2つのベクトルが、両者に垂直な独自の回転軸を定義します。その回転軸の向きは固定されていないので、回転角の向きも一意には決められないことになります。よくある慣習として、角度を常に正とし、正の角度に合うような軸の向きにすることがある。この場合、角度の計算は正規化されたベクトルの内積で十分である。

dot = x1*x2 + y1*y2 + z1*z2    #between [x1, y1, z1] and [x2, y2, z2]
lenSq1 = x1*x1 + y1*y1 + z1*z1
lenSq2 = x2*x2 + y2*y2 + z2*z2
angle = acos(dot/sqrt(lenSq1 * lenSq2))

3Dに埋め込まれた平面

特殊なケースとして、ベクトルが任意に配置されるのではなく、既知の法線ベクトルを持つ平面内に存在する場合があります。 n . このとき、回転軸の方向は n の方向も同じであり n は、その軸の向きを固定します。この場合、上記の2次元の計算を適応させることができ、その中には n 行列式 を使い、3×3の大きさにします。

dot = x1*x2 + y1*y2 + z1*z2
det = x1*y2*zn + x2*yn*z1 + xn*y1*z2 - z1*y2*xn - z2*yn*x1 - zn*y1*x2
angle = atan2(det, dot)

これが機能するための一つの条件は、法線ベクトルが n は単位長さを持っています。そうでない場合は、正規化する必要があります。

トリプルプロダクトとして

この行列式は、次のように表すこともできる。 三重積 というように エクスキューブレン が編集案で指摘されました。

det = n · (v1 × v2)

これは、ある種のAPIでは実装しやすいかもしれませんし、ここで起こっていることを別の観点から見ることができます。角度の正弦に比例し、平面に対して垂直になるため、積は n . したがって、内積は基本的にそのベクトルの長さを測りますが、正しい符号が付加されたものになります。