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

时间:2009-08-21 09:57:53

标签: math quartz-2d atan2

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

15 个答案:

答案 0 :(得分:81)

使用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度解决方案。

答案 1 :(得分:53)

(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

答案 2 :(得分:34)

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

答案 3 :(得分:30)

或者如果您不喜欢分支,只需取消这两个参数并在答案上加180°。

(在返回值上加180°可以很好地在0-360范围内,但会翻转角度。取消两个输入参数会将其翻转。)

答案 4 :(得分: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度。

答案 5 :(得分:7)

我有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 :(得分: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

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

答案 7 :(得分:2)

这就是我通常做的事情:

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

答案 8 :(得分:1)

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

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

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

答案 9 :(得分: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);
    }

答案 10 :(得分:1)

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

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;

答案 11 :(得分: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)

答案 12 :(得分:0)

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

逆时针方向返回0°-360°,3°方向返回0°。

答案 13 :(得分:0)

   update phrase set english = replace(english, ';to ', '; ') 

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

答案 14 :(得分:0)

公式的取值范围是0到360度。

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

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