6

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

向量的工作方式如下:

  • X 轴代表东西(东为正)
  • y 轴代表南北(北为正)
  • 因此
    • (0, 1) == 北
    • (1, 0) == 东
    • (0,-1) == 南
    • (-1,0) == 西

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

4

4 回答 4

9

这在 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
于 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=north, 1=northwest, 2=west,...等

 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

(测试的向量可能看起来很奇怪,但我稍微调整了一下,使其清楚地在一个八分圆中,而不是在确切的边界上)

于 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 回答