2009-09-17 3 views
5

私は、3Dモデリングソフトウェアで窓の表面に垂直な一連のベクトルを持っています。 xy平面に投影、私はどの方向に、彼らは8コンパスに変換、直面している知っていただきたいと思い、東北東南東南の座標,南西,西および北西)。方位(2D)ベクトルをコンパス(N、NE、E、SE、S、SW、W、NW)に「スナップ」する方法は?

ベクトルは次のように動作します:

  • X軸は東西を表し
  • y軸は、このよう
  • (北朝鮮が正である)南北を表し(東が正です)
    • (0、1)==北
    • (1、0)==東
    • (0、-1)==南
    • (-1,0)==西
    • 私は8つのコンパス座標の最も近くを探していますベクトル(x、y)が与えられた

。どのようにこれをエレガントに行うためのアイデア?

+0

これを正しくタグ付けする方法はありますか?自由に感じてください... –

+1

私の答え(1、0)は東で、反時計回りです。ここで数学的にやっています。これは航行中の角度の標準的な使用とは異なる(0 =北、時計回り)。適切なオフセットを+8に追加し、atan2の前に - を使用すると、それを適応させることができます。 – starblue

+0

スターブルーを指摘してくれてありがとう、私はここに私のスケッチと自分自身を混乱させている - あなたの答えはスポットです! –

答えて

7

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

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 
6

atan2()を呼び出して見出しの角度(「ヨー」)を求め、次にif:sまたは数学のシーケンスを使用して、90度の倍数に「スナップ」します。

+0

ありがとう、有望に見える、昼食後にチェックアウトします! –

4

行う必要はありませんがatan関数。

:もしy/xなら、線の傾きが得られます。番号で判断すると、角度/八分円を決定できます。 => 90度(北)

  • 2.4>(Y/X)> 0.4 - - => 45度の正のx(x> 0)

    • (Y/X)> 2.4

      (北西)

    • 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八分円ではなく、正確な境界線上にあるように、それらを微調整)

    これは、次のような出力になります

  • +0

    r値が匿名の配列サイズを簡単に超えてしまう可能性があるため、最終的に最適化されたルーチンがどのように機能するか分かりません。 – GregM

    +0

    よく見つかるバグを修正しました – Toad

    3

    これはatan2を使用せず、最悪の場合4回の比較と1回の呼び出しにつき2回の処理を行います。 4つの内部ブロック(最初のブロックでのみ編集済み)のxとyを比較すると、1回の呼び出しで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; 
    } 
    
    関連する問題