如何将atan2()映射到0-360度?

134

atan2(y, x)在180°处有不连续点,当逆时针旋转时变为-180°..0°。

我如何将值范围映射到0°..360°?

这是我的代码:

CGSize deltaPoint = CGSizeMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
float swipeBearing = atan2f(deltaPoint.height, deltaPoint.width);

我正在计算滑动触摸事件的方向,给定startPointendPoint,它们都是XY点结构体。这段代码用于iPhone,但支持atan2f()的任何语言都可以。


注意:发布的更新方法不会返回零度,而是从略高于0到360.0的值。 - chux - Reinstate Monica
2
如何从两个位置获取角度 - MAnoj Sarnaik
这个函数运行得很好,但是“bearingDegrees”计算的角度是反转的。例如,45度通常应该在第一象限,但是在第四象限。135度通常应该在第二象限,但是这个函数返回它在第三象限。我可以简单地取函数返回值x并将其从360中否定以获得正确的角度值,但我很想知道为什么会发生这种情况? - goelv
16个回答

3
angle = Math.atan2(x,y)*180/Math.PI;

我已经制定了一种公式,将角度定向为0到360度

angle + Math.ceil( -angle / 360 ) * 360;

2
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

这将返回从0°到360°逆时针的角度,0°位于3点钟位置。


2

一个计算从0度到360度值范围的公式。

f(x,y)=180-90*(1+sign(x))* (1-sign(y^2))-45*(2+sign(x))*sign(y)

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))

1
请问您能否解释一下这与问题的关系? - Klaus Gütter

1

针对您的应用程序,我猜测您不需要精确的度数,而更倾向于近似的罗盘角度,例如16个方向中的1个?如果是这样,那么此代码避免了atan问题,并且完全避免了浮点数。它是为一款视频游戏编写的,因此使用8位和16位整数:

/*

                                           349.75d         11.25d, tan=0.2034523
                                              \             /
                                               \   Sector  /      
                                                \    0    /  22.5d tan = ?2 - 1
                                             15      |      1   33.75
                                                     |         /   45d, tan = 1
                                        14           |            2 _56.25
                                                     |             /  67.5d, tan = 1 + ?2
                                     13              |               3
                                                     |                __ 78.75
                                                     |                
                                    12---------------+----------------4 90d tan = infty
                                                     |                __ 101.25
                                                     |                
                                     11              |               5
                                                     |               
                                        10           |            6
                                                     |          
                                             9       |      7
                                                     8



*/

// use signs to map sectors:
static const int8_t map[4][5] = {  /* +n means n >= 0, -n means n < 0 */
  /* 0: +x +y */ {0, 1, 2, 3, 4},
  /* 1: +x -y */ {8, 7, 6, 5, 4},
  /* 2: -x +y */ {0, 15, 14, 13, 12},
  /* 3: -x -y */ {8, 9, 10, 11, 12}
};

int8_t sector(int8_t x, int8_t y) { // x,y signed in range -128:127, result 0:15 from north, clockwise.
  int16_t tangent; // 16 bits
  int8_t quadrant = 0;
  if (x > 0) x = -x; else quadrant |= 2; // make both negative avoids issue with negating -128 
  if (y > 0) y = -y; else quadrant |= 1;
  if (y != 0) {
    // The primary cost of this algorithm is five 16-bit multiplies.
    tangent = (int16_t)x*32;   // worst case y = 1, tangent = 255*32 so fits in 2 bytes.
    /*
       determine base sector using abs(x)/abs(y).
       in segment:
           0 if         0 <= x/y < tan 11.25   -- centered around 0     N
           1 if tan 11.25 <= x/y < tan 33.75   --                 22.5  NxNE
           2 if tan 33.75 <= x/y < tan 56.25   --                 45    NE
           3 if tan 56.25 <= x/y < tan 78.75   --                 67.5  ExNE
           4 if tan 78.75 <= x/y < tan 90      --                 90    E
    */
    if (tangent > y*6  ) return map[quadrant][0]; // tan(11.25)*32
    if (tangent > y*21 ) return map[quadrant][1]; // tan(33.75)*32
    if (tangent > y*47 ) return map[quadrant][2]; // tan(56.25)*32
    if (tangent > y*160) return map[quadrant][3]; // tan(78.75)*32
    // last case is the potentially infinite tan(90) but we don't need to check that limit.
  }
  return map[quadrant][4];
}

1
theta_rad = Math.Atan2(y,x);
if(theta_rad < 0)
  theta_rad = theta_rad + 2 * Math.PI;    //if neg., add 2 PI to it
theta_deg = (theta_rad/M_PI*180) ;        //convert from radian to degree

//or
theta_rad = Math.Atan2(y,x);
theta_rad = (theta_rad < 0) ? theta_rad + 2 * Math.PI : theta_rad;
theta_deg = (theta_rad/M_PI*180) ;

-1度变为(-1 + 360) = 359度
-179度变为(-179 + 360) = 181度


1
Math.PI是什么?它和M_PI一样吗? - Pang

1

R软件包geosphere可以计算bearingRhumb,即给定原点和东/北的常数方位线。东部和北部必须在矩阵或向量中。风玫瑰的原点是0,0。下面的代码似乎可以轻松解决问题:

windE<-wind$uasE
windN<-wind$vasN
wind_matrix<-cbind(windE, windN)
wind$wind_dir<-bearingRhumb(c(0,0), wind_matrix)
wind$wind_dir<-round(wind$wind_dir, 0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接