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

问题描述 投票:87回答:14

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);

在给定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;
}
math quartz-2d atan2
14个回答
53
投票
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

1
投票

另一种解决方案是使用定义为的mod()函数:

function mod(a, b) {return a - Math.floor (a / b) * b;}

然后,利用以下函数,获得ini(x,y)和end(x,y)点之间的角度。该角度以标准化为[0,360]度的度数表示。和北参考360度。

    function angleInDegrees(ini, end) {
        var radian = Math.atan2((end.y - ini.y), (end.x - ini.x));//radian [-PI,PI]
        return mod(radian * 180 / Math.PI + 90, 360);
    }

0
投票

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)

0
投票
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度


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

这将从0°-360°逆时针返回度,0°在3点钟返回。


0
投票

一个公式,其值范围为0到360度。

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

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

82
投票

使用Modulo的解决方案

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

degrees = (degrees + 360) % 360;  // +360 for implementations where mod returns negative numbers

说明

正面:1到180

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

负数:-180到-1

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

特殊情况:0和360

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


34
投票

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


30
投票

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

(向返回值添加180°会很好地在0-360范围内,但会翻转角度。否定两个输入参数都会将其翻转。)


20
投票

@erikkallen很接近但不太对劲。

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

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

theta_deg = fmod(atan2(y,x)/M_PI*180,360);

或者你可以这样做:

theta_deg = atan2(-y,-x)/M_PI*180 + 180;

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


8
投票

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

1)滥用atan2()

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

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

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

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

6
投票

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

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

从而,

fmod(atan2(y,x)/M_PI*180,360)

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

atan2(y,x)/M_PI*180

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


2
投票

这就是我通常做的事情:

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

1
投票
angle = Math.atan2(x,y)*180/Math.PI;

我制作了一个将角度定向为0到360的公式

angle + Math.ceil( -angle / 360 ) * 360;
© www.soinside.com 2019 - 2024. All rights reserved.