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

wil*_*lc2 91 math atan2 quartz-2d

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);
Run Code Online (Sandbox Code Playgroud)

在给定startPoint和endPoint两个XY点结构的情况下,我正在计算滑动触摸事件的方向.该代码适用于iPhone,但任何支持atan2f()的语言都可以.

感谢您的帮助,包括一般解决方案和代码.

更新:我将erikkallen的答案变成了一个具有漂亮的长变量名的函数,所以我将在6个月后理解它.也许它会帮助其他一些iPhone noob.

float PointPairToBearingDegrees(CGPoint startingPoint, CGPoint endingPoint)
{
    CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
    float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
    float bearingDegrees = bearingRadians * (180.0 / M_PI); // convert to degrees
    bearingDegrees = (bearingDegrees > 0.0 ? bearingDegrees : (360.0 + bearingDegrees)); // correct discontinuity
    return bearingDegrees;
}
Run Code Online (Sandbox Code Playgroud)

Lia*_*rth 85

使用Modulo的解决方案

一个捕获所有案例的简单解决方案.

degrees = (degrees + 360) % 360;  // +360 for implementations where mod returns negative numbers
Run Code Online (Sandbox Code Playgroud)

说明

正面:1到180

如果您修改1到180之间的任何正数360,您将得到完全相同的数字.这里的Mod只是确保这些正数返回相同的值.

负数:-180到-1

在这里使用mod将返回180和359度范围内的值.

特殊情况:0和360

使用mod意味着返回0,使其成为一个安全的0-359度解决方案.

  • 我不认为这在所有语言中都是正确的.在Javascript中`-1%360 = -1` (10认同)
  • 我不相信有必要添加360. -1%360仍然是359 :) (5认同)
  • 很棒的解决方案:) (3认同)
  • @pleasemorebacon 不正确。在某些语言中 -1 % 360 是 -1。 (3认同)

eri*_*len 55

(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
Run Code Online (Sandbox Code Playgroud)

  • 对于那些不熟悉这种表示法的人,并且没有内置度数的转换:if(x> 0){radians = x;} else {radians = 2*PI + x;}所以我们只是在结果中添加2PI它小于0. (11认同)
  • 对于x = 0的情况,可能还需要x> = 0. (4认同)
  • 那是错的,x的符号应该是正的. (2认同)
  • 或者 `(x >= 0 ? x : (2*PI + x)) * 180/PI` 如在 `(x < 0 ? 2*PI + x : x) * 180/PI` (2认同)

dav*_*420 36

如果atan2的答案小于0°,只需添加360°.

  • 如果你有*那些*天之一,那就和"只添加2*PI"相同. (3认同)

aib*_*aib 31

或者,如果您不喜欢分支,只需取消两个参数并将180°添加到答案中.

  • 谢谢,这正是我想要的. (2认同)
  • +1表示简单代码,但不是很容易理解. (2认同)
  • 我宁愿修改我的代码以使用非规范化角度(<0,>=360),但似乎总有人在追求那种虚假的“优化”感觉;这就是为什么我想添加这个。(或者是因为这是我使用的一些临时调试代码的更快方法?嗯) (2认同)
  • 绝对不是很容易理解,因为我可以在 2 年后同意。所以:将 180° 添加到返回值可以很好地将其置于 0-360 范围内,但会翻转角度。否定两个输入参数会将其翻转回来。 (2认同)

Jas*_*n S 20

@erikkallen很接近但不太对劲.

theta_rad = atan2(y,x);
theta_deg = (theta_rad/M_PI*180) + (theta_rad > 0 ? 0 : 360);
Run Code Online (Sandbox Code Playgroud)

这应该适用于C++ :(取决于fmod的实现方式,它可能比条件表达式更快或更慢)

theta_deg = fmod(atan2(y,x)/M_PI*180,360);
Run Code Online (Sandbox Code Playgroud)

或者你可以这样做:

theta_deg = atan2(-y,-x)/M_PI*180 + 180;
Run Code Online (Sandbox Code Playgroud)

因为(x,y)和(-x,-y)的角度相差180度.

  • 注意:刚刚意识到我的第三个eqn是@aib所说的. (2认同)

小智 10

这是一些 JavaScript。只需输入 x 和 y 值。

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Run Code Online (Sandbox Code Playgroud)


Fib*_*les 8

我有两个解决方案似乎适用于正负x和y的所有组合.

1)滥用atan2()

根据文档,atan2按顺序获取参数y和x.但是,如果您反转它们,则可以执行以下操作:

double radians = std::atan2(x, y);
double degrees = radians * 180 / M_PI;
if (radians < 0)
{
    degrees += 360; 
}
Run Code Online (Sandbox Code Playgroud)

2)正确使用atan2()并在之后进行转换

double degrees = std::atan2(y, x) * 180 / M_PI;
if (degrees > 90)
{
    degrees = 450 - degrees;
}
else
{
    degrees = 90 - degrees;
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*non 6

@Jason S:您的"fmod"变体不适用于符合标准的实现.C标准明确而清晰(7.12.10.1,"fmod函数"):

如果y非零,则结果与x具有相同的符号

从而,

fmod(atan2(y,x)/M_PI*180,360)
Run Code Online (Sandbox Code Playgroud)

实际上只是一个冗长的重写:

atan2(y,x)/M_PI*180
Run Code Online (Sandbox Code Playgroud)

然而,你的第三个建议是现场.


and*_*rés 5

这是我通常的做法:

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;
Run Code Online (Sandbox Code Playgroud)