ゲームでカメラ アングルを取得するアプリケーションを開発しています。角度は 0 ~ 359 の範囲で指定できます。0 は北、90 は東、180 は南などです。Camera クラスに getAngle() メソッドを持つ API を使用しています。
異なるカメラ アングル間の平均をどのように見つけますか。0 と 359 の実際の平均は 179.5 です。カメラ アングルとしては南になりますが、明らかに 0 と 359 はどちらも北に非常に近いです。
ベクトルで考えることができます。とをラジアンで表した 2 つの角度とします。次に、これらの角度にある単位ベクトルの x 成分と y 成分を決定できます。θ1
θ2
x 1 = sin(θ 1 ) y 1 = cos(θ 1 ) x 2 = sin(θ 2 ) y 2 = cos(θ 2 )
次に、これら 2 つのベクトルを加算して、結果の x 成分と y 成分を決定できます。
x * = x 1 + x 2 y * = y 1 + y 2
最後に、この結果のベクトルの角度を決定できます。
θ avg = tan -1 (y * /x * )
または、さらに良いことに、atan2
(多くの言語でサポートされている関数) を使用します。
θ avg = atan2(y * , x * )
おそらく、 と のケースを別々に処理する必要があります。これは、2 つのベクトルが正反対の方向を指していることを意味するためです (したがって、「平均」はどうあるべきでしょうか?)。y* = 0
x* = 0
「平均」が何を意味するかによります。しかし、通常の定義は、含まれる鋭角の二等分線です。両方を 180 度以内に配置する必要があります。これを行うには多くの方法がありますが、簡単な方法は、角度の 1 つを増減することです。角度がa
との場合、次のb
ようになります。
if (a < b)
while (abs(a - b) > 180) a = a + 360
else
while (abs(a - b) > 180) a = a - 360
これで、単純平均を計算できます。
avg = (a + b) / 2
もちろん、もう一度正規化することもできます。
while (avg < 0) avg = avg + 360
while (avg >= 360) avg = avg - 360
あなたの例では、a=0、b=359 になります。最初のループは a を 360 に増やします。平均は 359.5 になります。もちろん、必要に応じてそれを整数に丸めることができます。360 に切り上げると、ループの最終セットは 0 に減少します。
角度が常に [0..360) に正規化されている場合、これらのループは 1 回しか実行されないことに注意してください。しかし、乱暴な引数によってコードが失敗しないようにするため、これらはおそらく良い習慣です。
角度を平均化するのではなく、角度を二分したいと考えています。最初にそれらの間の距離を取得し、最短距離を取り、それを半分に分割して角度の 1 つに追加します。例えば:
A = 355
B = 5
if (abs(A - B) < 180) {
Distance = abs(A - B)
if (A < B) {
Bisect = A + Distance / 2
}
else {
Bisect = B + Distance / 2
}
}
else {
Distance = 360 - abs(A - B)
if (A < B) {
Bisect = A - Distance / 2
}
else {
Bisect = B - Distance / 2
}
}
またはそのようなもの-「Bisect」は、指定された入力に対してゼロになるはずです。if および abs 演算を少なくして算術演算を実行する賢い方法がおそらくあるでしょう。