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

时间:2009-09-17 09:53:10

标签: algorithm math trigonometry vector

我在3D建模软件中有一堆垂直于窗口表面的矢量。投影到XY平面,我想知道它们面向哪个方向,转换为 8罗盘坐标东北 em>,东南西南 West 西北)。

载体的工作原理如下:

  • X轴代表东西方(东方为正)
  • y轴代表南北(北方为正)
  • 从而
    • (0,1)==北
    • (1,0)==东
    • (0,-1)==南
    • ( - 1,0)== West

给定一个向量(x,y),我正在寻找最近的8个罗盘坐标。关于如何优雅地做到这一点的任何想法?

4 个答案:

答案 0 :(得分:7)

这适用于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

答案 1 :(得分:6)

我可能只是打电话给atan2()找出标题角度(“偏航”),然后使用一系列if:s或一些数学来“捕捉”它到90度的倍数。

答案 2 :(得分:4)

无需执行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

(测试的矢量可能看起来很奇怪,但是我把它们调整得很清楚,只是在一个八分圆中,而不是在确切的边界上)

答案 3 :(得分:3)

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