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;
}
答案 0 :(得分:81)
捕获所有案例的简单解决方案。
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)))