代码之家  ›  专栏  ›  技术社区  ›  Daren Thomas

如何将方向(2D)矢量“捕捉”到指南针(N、NE、E、SE、S、SW、W、NW)?

  •  6
  • Daren Thomas  · 技术社区  · 16 年前

    ( , , , , , 西南部 , ).

    • y轴表示南北(北为正)
      • (1,0)==东

    4 回复  |  直到 16 年前
        1
  •  9
  •   starblue    16 年前

    这在Java中工作,计算八个方向的值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
    
        2
  •  6
  •   unwind    16 年前

    atan2() 计算航向角(“偏航”),然后使用以下序列之一 if

        3
  •  5
  •   Toad    10 年前

    无需执行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度(南)

    我不得不挖掘一下。这是我使用的一个高度优化的例程(用于手机游戏)。

    输入:x1,y1=向量的起点 输出(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
    

    (测试的向量可能看起来选择得很奇怪,但我对它们进行了一些调整,使其在一个八分位数中清晰可见,而不是在精确的边界上)

        4
  •  4
  •   Eric Bainville    16 年前

    这个不使用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;
    }