web-dev-qa-db-ja.com

角度が2つの角度の間にあるかどうかの計算

だから私は、AがBの特定の距離内にあり、A度の方向が+/- 45度である場合に、キャラクターAがキャラクターBを見ることができる、キャラクターが別のキャラクターを「見る」ことができるかどうかをチェックする小さなゲームを作っています。角度Bが向いています。

現在、私は私がチェックしているところに少し計算をします

(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45)

これは、360度の線を越える場合を除いて正常に機能します。

まあ言ってみれば facingAngle = 359, angleOfTarget = 5。この状況では、ターゲットは中心からわずか6度ずれているので、関数をtrueに戻したいと思います。残念ながら、5は314と404の間にありません。

21
user1641573

ちょうど試して

anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180

if (anglediff <= 45 && anglediff>=-45) ....

その理由は、角度の違いがfacingAngle - angleOfTargetラッピング効果によるものですが、360度ずれている場合があります。

180 + 360を加算し、次に360を法として、180を減算すると、事実上、すべてが-180〜180度の範囲に変換されます(360度を加算または減算することにより)。

そうすれば、角度差が-45〜45度以内かどうかを簡単に確認できます。

23
ronalchn

これは私がオンラインで見つけて変更した簡単な関数です。 どの角度でも正しく機能します(0-360の外側でもかまいません)。 (この関数はcで動作するように作成されており、Xcodeで動作します。)

角度Aから角度BまでCOUNTER-CLOCKWISEをチェックすることを忘れないでください。角度が:)の間にある場合は、[〜#〜] yes [〜#〜](true)を返します。

まず、すべての角度を1〜360にする簡単な変換関数

//function to convert angle to 1-360 degrees
 static inline double angle_1to360(double angle){
 angle=((int)angle % 360) + (angle-trunc(angle)); //converts angle to range -360 + 360
 if(angle>0.0)
 return angle;
 else
 return angle + 360.0;
 }

角度が間にあるかどうかを確認してください:)

//check if angle is between angles
 static inline BOOL angle_is_between_angles(float N,float a,float b) {
 N = angle_1to360(N); //normalize angles to be 1-360 degrees
 a = angle_1to360(a);
 b = angle_1to360(b);

 if (a < b)
 return a <= N && N <= b;
 return a <= N || N <= b;
 }

enter image description here

例えば。角度300が180度から10度の間であるかどうかを確認するには:

BOOL isBetween=angle_is_between_angles( 300, 180,10);

//はいを返します

8
Stan Tatarnykov

Alnitakの答えを別の方法で言い換えると、360度での角度の折り返しを回避する解決策は、角度が常に小さい別の座標系で問題を言い換えることです。コードは次のとおりです。

def inside_angle(facing, target):
    dot = cos(facing)*cos(target) + sin(facing)*sin(target)
    angle = acos(dot)

    return angle <= pi/4

これは、ベクトル射影を使用して行われます。ベクトル|直面している> = [cos(直面している)sin(直面している)]および| target> = [cos(target)sin(target)]と仮定すると、ターゲットを直面しているベクトルに投影するとき、角度はゼロからの範囲になります。ターゲットは正確に向きのベクトルにあるか、どちらかの側に増加します。このようにして、それをpi/4(45度)と比較することができます。角度の式は次のとおりです。

cos(angle) = <facing|target> / <target|target> <facing|facing>

つまり、角度の余弦は、モジュールを分割したベクトル| faceing>と| target>の間の内積であり、この場合は1であり、次のようになります。

angle = acos(<facing|target>)

参照: https://en.wikipedia.org/wiki/Vector_projection

0
hdante

常に最小の正の差を使用し、しきい値と比較する別の方法:

anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)
0
DFE

ローエンド(負の値への)での折り返しを処理する簡単な解決策は、すべての値に360を追加することです。

(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405)

そうすれば、45の減算は、もはや発生しないため、負になることはありません。

上端での折り返しを処理するには、angleOfTarget値にanother 360を追加して、もう一度確認する必要があります。

canSee  = (facingAngle + 315 <= angleOfTarget + 360) &&
          (angleOfTarget + 360 <= facingAngle + 405);
canSee |= (facingAngle + 315 <= angleOfTarget + 720) &&
          (angleOfTarget + 720 <= facingAngle + 405);
0
paxdiablo