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


108

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-恢复莫妮卡

2
> [如何从2个位置获取角] [1] [1]:stackoverflow.com/questions/9457988/...
MANOJ Sarnaik

该功能效果很好,但是“ bearingDegrees”计算的角度被翻转了。例如,第一个象限通常为45度,但是在第四个象限则为45度。135度通常在第二象限,但是此函数将其返回到第三象限。我可以简单地使用函数返回值x并从360中取反,以获得正确的角度值,但是我很好奇为什么会首先发生这种情况?
goelv

Answers:


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

6
对于x = 0的情况,可能还希望x> = 0。
bpw1621

13
对于那些不喜欢这种表示法并且没有转换为内置度数的人:if(x> 0){radians = x;} else {radians = 2 * PI + x;}因此,如果它是小于0
大卫·多里亚

1
(x >= 0 ? x : (2*PI + x)) * 180/PI(x < 0 ? 2*PI + x : x) * 180/PI
user3342816 2014年

97

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


3
令人敬畏的解决方案:)
Qadir Hussain 2015年

5
我认为没有必要添加360。-1%360仍然是359 :)
pleasemorebacon

11
我认为并非所有语言都正确。使用Javascript-1 % 360 = -1
Startec

在Java中也不是一种可行的方法
Hulk

1
@pleasemorebacon错误。在某些语言中,-1%360是-1。
法拉普

40

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


6
这是一样的“只加2 * PI”如果你有一个那些日子。
克里斯·奥

33

或者,如果您不喜欢分支,只需将两个参数取反,然后将答案增加180°即可。

(将返回值增加180°可以将其很好地设置在0-360的范围内,但是会反转角度。两个输入参数都取反会使其反转。)


2
谢谢,这正是我想要的。
杰里米·赫尔曼

2
我宁愿修改我的代码以使用非规范化的角度(<0,> = 360),但似乎总是有人针对这种假的“优化”感觉。这就是为什么我要添加此内容。(或者是因为这是绕过我使用的一些临时调试代码的更快方法?hmm)
aib 2012年

1
绝对不是一件容易的事,因为我可以在2年后同意。因此:在返回值上加上180°会使它很好地位于0-360范围内,但是会翻转角度。取反两个输入参数将其翻转回去。
aib 2014年

当$ x = 0 $且$ y> 0 $ iirc时,这可能会遇到一些问题
特立尼达

22

@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度。


如果我在Fortran中正确地理解了您,则它是atan2(-y,-x)* 180 / PI +180。那是正确的吗?
gansub '16

对不起,我不认识FORTRAN。但是你的数学看起来不错。
詹森·S

11

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

先生,您是救生员。刚刚在Unity中使用了这种方法,就像一个魅力。
porfiriopartida

7

@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

但是,您的第三个建议是正确的。


5

这是我通常所做的:

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


2

一种替代解决方案是使用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);
    }

1

R包地理球将计算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)

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度


什么Math.PI啊 一样M_PI吗?

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

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


1

具有介于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)))

您能解释一下这与问题的关系吗?
克劳斯·古特(KlausGütter),

1

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

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.