6

3Dモデリングソフトウェアのウィンドウサーフェスに垂直なベクトルがたくさんあります。XY平面に投影され、 8つのコンパス座標北東、南東南西西北西)に変換されて、それらがどちらの方向を向いているかを知りたいです。。

ベクトルは次のように機能します。

  • X軸は東西を表します(東は正)
  • y軸は南北を表します(北は正)
  • したがって
    • (0、1)==北
    • (1、0)==東
    • (0、-1)==南
    • (-1,0)==西

ベクトル(x、y)が与えられた場合、8つのコンパス座標の中で最も近いものを探しています。これをエレガントに行う方法について何かアイデアはありますか?

4

4 に答える 4

9

これは Java で機能し、8 つの方向の値 0...7 を計算します。

import static java.lang.Math.*;    

int compass = (((int) round(atan2(y, x) / (2 * PI / 8))) + 8) % 8;

結果は次のようにコンパスにマップされます。

0 => E
1 => NE
2 => N
3 => NW
4 => W
5 => SW
6 => S
7 => SE
于 2009-09-17T10:22:48.823 に答える
6

おそらく、 atan2()を呼び出して進行方向の角度 (「ヨー」) を計算し、一連のif:s またはいくつかの計算を使用して、それを 90 度の倍数に「スナップ」します。

于 2009-09-17T09:56:38.737 に答える
5

atan 関数を実行する必要はありません。

y/x とすると、直線の傾きが得られます。取得した数値から判断すると、角度/八分円を決定できます。

正の x (x>0)

  • (y/x) > 2.4 -=> 90 度 (北)
  • 2.4 > (y/x) > 0.4 -=> 45 度 (北西)
  • 0.4 > (y/x) > -0.4 -=> 0 度 (西)
  • -0.4 > (y/x) > -2.4 -=> -45 度 (南西)
  • -2.4 > (y/x) -=> 90 度 (南)

負の x の同様のリスト

そして最後に例外ケース:

  • (x==0 && y>0) -=> -90 度 (南)
  • (x==0 && y<0) -=> 90 度 (南)

補遺: atan の計算がうまくいかない場合 (組み込みシステムなど) の場合にのみ、この方法を報告します)

少し掘る必要がありました。これは、私が使用する高度に最適化されたルーチンです (モバイル ゲームで使用されます)。

入力: x1,y1 = ベクトルの始点 x2,y2 = ベクトルの終点 出力 (0-7) = 0=北, 1=北西, 2=西,...など

 int CalcDir( int x1, int y1, int x2, int y2 )
 {
      int dx = x2 - x1, dy = y2 - y1;
      int adx = (dx<0)?-dx:dx, ady = (dy<0)?-dy:dy, r;
      r=(dy>0?4:0)+(dx>0?2:0)+(adx>ady?1:0);
      r=(int []){2,3,1,0,5,4,6,7}[r];
      return r;
 }

 void CalcDirTest(){
      int t = CalcDir(0, 0, 10, 1);
      printf("t = %d",t);
      t = CalcDir(0, 0, 9, 10);
      printf("t = %d",t);
      t = CalcDir(0, 0, -1, 10);
      printf("t = %d",t);
      t = CalcDir(0, 0, -10, 9);
      printf("t = %d",t);
      t = CalcDir(0, 0, -10, -1);
      printf("t = %d",t);
      t = CalcDir(0, 0, -9, -10);
      printf("t = %d",t);
      t = CalcDir(0, 0, 1, -10);
      printf("t = %d",t);
      t = CalcDir(0, 0, 10, -9);
      printf("t = %d",t);
 }

これにより、次の出力が得られます。

 t = 7
 t = 6
 t = 5
 t = 4
 t = 3
 t = 2
 t = 1
 t = 0

(テスト用のベクトルは奇妙に選択されているように見えるかもしれませんが、正確な境界線上ではなく、明確に 1 つの八分円内にあるように、それらすべてを微調整しました)

于 2009-09-17T10:31:44.000 に答える
4

これは atan2 を使用せず、呼び出しごとに最悪 4 つの比較と 2 つの製品を実行します。4 つの内側のブロックで x と y を比較すると (最初のブロックのみを編集しました)、正確に 4 つの比較と呼び出しごとに 1 つの製品に減らすことができます。

int compass(double x,double y)
{
  double t = 0.392699082; // tan(M_PI/8.0);

  if (x>=0)
  {
    if (y>=0)
    {
      if (x>y) { if (y<t*x) return E_COMPASS; }
      else { if (x<t*y) return N_COMPASS; }
      return NE_COMPASS;
    }
    else
    {
      if (-y<t*x) return E_COMPASS;
      if (x<-t*y) return S_COMPASS;
      return SE_COMPASS;
    }
  }
  else
  {
    if (y>=0)
    {
      if (y<-t*x) return W_COMPASS;
      if (-x<t*y) return N_COMPASS;
      return NW_COMPASS;
    }
    else
    {
      if (-y<-t*x) return W_COMPASS;
      if (-x<-t*y) return S_COMPASS;
      return SW_COMPASS;
    }
  }
  return E_COMPASS;
}
于 2009-09-17T10:48:52.390 に答える