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;
}
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
另一种解决方案是使用定义为的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);
}
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)
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度
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);
这将从0°-360°逆时针返回度,0°在3点钟返回。
一个公式,其值范围为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)))
一个捕获所有案例的简单解决方案。
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度解决方案。
如果atan2的答案小于0°,只需添加360°。
或者,如果您不喜欢分支,只需取消两个参数并将180°添加到答案中。
(向返回值添加180°会很好地在0-360范围内,但会翻转角度。否定两个输入参数都会将其翻转。)
@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度。
我有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;
}
@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
然而,你的第三个建议是现场。
这就是我通常做的事情:
float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;
angle = Math.atan2(x,y)*180/Math.PI;
我制作了一个将角度定向为0到360的公式
angle + Math.ceil( -angle / 360 ) * 360;