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

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()的语言都可以。

感谢您的帮助,通用的解决scheme和代码。

更新 :我把erikkallen的答案变成了一个很好的长variables名,所以我从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; } 
 (x > 0 ? x : (2*PI + x)) * 360 / (2*PI) 

编辑:哎呀,错误的标志。

使用Modulo的解决scheme

捕捉所有情况的简单解决scheme。

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

说明

正面:1至180

如果你用360代替1到180之间的正数,你将得到与你input的完全相同的数字。这里的Mod只是确保这些正数返回为相同的值。

负数:-180至-1

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

特殊情况:0和360

使用mod意味着返回0,这是一个安全的0-359度的解决scheme。

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

或者如果你不喜欢分支,只需否定这两个参数,并将180°添加到答案。

@erikkallen是接近但不完全正确。

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

这应该在C ++中工作:(取决于fmod如何实现,它可能比条件expression式更快或更慢)

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

或者你可以这样做:

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

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

@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 

然而,你的第三个build议是现实的。

我有2个解决scheme似乎适用于所有正负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; } 

另一种解决scheme是使用定义如下的mod ()函数:

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

然后,用下面的函数,得到ini(x,y)end(x,y)点之间的angular度。 angular度以归一化为[0,360]度的angular度表示。 和北参考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); } 
 angle = Math.atan2(x,y)*180/Math.PI; 

我制定了一个方位angular为0到360的公式

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

R包地圈将计算轴承的垂直度,这是一个给定起点和东/北的恒定轴承线。 东向和北向必须在matrix或向量中。 风玫瑰的起点是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) 
 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度

这是我通常做的事情:

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

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

    Interesting Posts