是否有一种简单的方法可以将角度(以度为单位)转换为介于-179和180之间?我确信我可以使用mod(%)和一些if语句,但它变得丑陋:
//Make angle between 0 and 360
angle%=360;
//Make angle between -179 and 180
if (angle>180) angle-=360;
似乎应该有一个简单的数学运算,它将同时执行两个语句。我现在可能只需要为转换创建一个静态方法。
答案 0 :(得分:79)
// reduce the angle
angle = angle % 360;
// force it to be the positive remainder, so that 0 <= angle < 360
angle = (angle + 360) % 360;
// force into the minimum absolute value residue class, so that -180 < angle <= 180
if (angle > 180)
angle -= 360;
答案 1 :(得分:16)
试试吧!
atan2(sin(angle), cos(angle))
atan2
的范围为 [ - π,π)。这利用了tanθ=sinθ/cosθ这一事实,并且atan2
足够聪明,可以知道哪个象限θ。
由于您需要度数,因此您需要将角度转换为弧度:
atan2(sin(angle * PI/180.0), cos(angle * PI/180.0)) * 180.0/PI
<强>更新强>
我之前的例子是完全合法的,但将范围限制在±90°。 atan2
的范围是-179°至180°的期望值。保存在下面。
试试这个:
asin(sin(angle)))
sin
的域是实线,范围是[-1, 1]
。 asin
的域名为[-1, 1]
,范围为[-PI/2, PI/2]
。由于asin
是sin
的倒数,因此您的输入不会更改(很多,因为您使用的是浮点数,所以会有一些漂移)。因此,您可以获得输入值,并获得所需范围作为反正弦范围的副作用。
由于您需要度数,因此您需要将角度转换为弧度:
asin(sin(angle * PI/180.0)) * 180.0/PI
(警告:Trig功能比简单的分频和减法操作慢了几倍,即使它们是在FPU中完成的!)
答案 2 :(得分:15)
我知道,我迟到了,但是......
这些答案中的大多数都不好,因为它们试图变得聪明和简洁,然后不处理边缘情况。
它有点冗长,但是如果你想让它工作,只需加入逻辑以使其工作。不要试图变得聪明。
int normalizeAngle(int angle) { int newAngle = angle; while (newAngle <= -180) newAngle += 360; while (newAngle > 180) newAngle -= 360; return newAngle; }
这很有效,而且相当干净简洁,而不是想要花哨。请注意,只能运行零个或一个while循环。
答案 3 :(得分:9)
也不那么聪明,但如果没有。
angle =(angle + 179)%360 - 179;
但我不确定Java如何处理负数的模数。仅当-1模360等于359时才有效。
<强>更新强>
只需检查文档,a % b
会产生-(|b| - 1)
和+(|b| - 1)
之间的值,因此代码已被破坏。要考虑模运算符返回的负值,必须使用以下内容。
angle = ((angle + 179) % 360 + 360) % 360 - 179;
但是......不......永远......使用与初始解决方案类似的东西,但修复的值小于-179。
答案 4 :(得分:8)
这适用于负数和十进制数,不需要循环,也不需要三角函数:
angle - = Math.floor(angle / 360 + 0.5)* 360
结果在[-180,180]间隔内。对于(-180,180)间隔,您可以改为使用它:
角度 - = Math.ceil(角度/ 360 - 0.5)* 360
答案 5 :(得分:3)
也许没用,但我总是喜欢使用非度数角度。
0到255之间的角度范围可以使用按位运算保留在边界内,或者对于单字节变量,简单允许溢出。
对于按位运算,-128到127的角度范围并不那么容易,但对于单字节变量,您可以让它溢出。
我认为这对于游戏很多年来都是个好主意,你可能会使用角度查找表。这些天,不太好 - 角度的使用方式不同,无论如何都是浮动的。
仍然 - 也许值得一提。
答案 6 :(得分:3)
处理负数的简短方法是
double mod = x - Math.floor((x + 179.0) / 360) * 360;
铸就味道。
BTW:似乎未定义(180.0,181.0)之间的角度。该范围不应该是(-180,180)(不包括在内)
答案 7 :(得分:3)
我知道那些年过去了,但仍然存在。
此解决方案不包含循环,不减去,没有模数(允许归一化到弧度间隔)。适用于任何输入,包括负值,大值,边缘情况。
double normalizedAngle = angle - (ceil((angle + M_PI)/(2*M_PI))-1)*2*M_PI; // (-Pi;Pi]:
double normalizedAngle = angle - (ceil((angle + 180)/360)-1)*360; // (-180;180]:
double normalizedAngle = angle - (floor((angle + M_PI)/(2*M_PI)))*2*M_PI; // [-Pi;Pi):
double normalizedAngle = angle - (floor((angle + 180)/360))*360; // [-180;180):
答案 8 :(得分:3)
以下是仅限整数的解决方案:
int normalize(int angle)
{
angle %= 360;
int fix = angle / 180; // Integer division!!
return (fix) ? angle - (360 * (fix)) : angle;
}
有时候聪明才会更有趣,Platinum Azure。
答案 9 :(得分:2)
嗯,还有一个解决方案,这个只有一个分区,没有循环。
static double normalizeAngle(double angle)
{
angle %= 360.0; // [0..360) if angle is positive, (-360..0] if negative
if (angle > 180.0) // was positive
return angle - 360.0; // was (180..360) => returning (-180..0)
if (angle <= -180.0) // was negative
return angle + 360.0; // was (-360..180] => returning (0..180]
return angle; // (-180..180]
}
答案 10 :(得分:2)
我已经制定了循环值方向的公式
保持0到359之间的角度是:
angle + Math.ceil( -angle / 360 ) * 360
但要保持-179到180之间的公式可以是:
angle + Math.ceil( (-angle-179) / 360 ) * 360
这将使其方向偏移约-179,保持实际角度不变
偏移角度方向的广义公式可以是:
angle + Math.ceil( (-angle+shift) / 360 ) * 360
答案 11 :(得分:1)
int angle = -394;
// shortest
angle %= 360;
angle = angle < -170 ? angle + 360 : (angle > 180 ? angle - 380 : angle);
// cleanest
angle %= 360;
if (angle < -179) angle += 360;
else if (angle > 180) angle -= 360;
答案 12 :(得分:0)
怎么样
(angle % 360) - 179
这实际上将返回与问题中提出的朴素方法不同的结果,但它将保持指定边界之间的角度。 (我想这可能会使这个答案错误,但我会把它留在这里以防它解决另一个人类似的问题)。
答案 13 :(得分:0)
这是我的贡献。它似乎适用于所有角度,没有边缘问题。它很快。几乎可以瞬间完成n180 [360000359] = -1。注意Sign函数如何帮助选择正确的逻辑路径,并允许相同的代码用于不同的角度。
隔距
n180[a_] :=
If[Abs[Mod[a, If[Sign[a] == 0, 360, Sign[a] 360]]] <= 180,
Mod[a, If[Sign[a] == 0, 360, Sign[a] 360]],
Mod[a, If[Sign[a] == 0, 360, -Sign[a] 360]]]
答案 14 :(得分:0)
我不太了解Java,但是在Python中遇到了同样的问题。这里的大多数答案都是针对整数,因此我认为我会添加一个允许浮点数的答案。
def half_angle(degree):
return -((180 - degree) % 360) + 180
基于其他答案,我猜该函数在Java中看起来像这样(随时可以纠正我)
int halfAngle(int degree) {
return -Math.floorMod(180 - degree, 360) + 180
}
double halfAngle(double degree) {
// Java doesn't have a built-in modulus operator
// And Math.floorMod only works on integers and longs
// But we can use ((x%n) + n)%n to obtain the modulus for float
return -(((180 - degree) % 360 + 360) % 360) + 180
}
根据自己的喜好将int
替换为float
。
这适用于任何程度,包括正数和负数以及浮点数和整数:
half_angle(180) == 180
half_angle(180.1) == -179.9 // actually -179.89999999999998
half_angle(-179.9) == -179.9
half_angle(-180) = 180
half_angle(1) = 1
half_angle(0) = 0
half_angle(-1) = -1
数学解释:
由于模运算符在上端是开放的,因此值x % 360
在[0, 360)
范围内,因此使用负角,上端变为下端。因此-(-x%360)
在(-360, 0]
中,而-(-x%360)+360
在(0, 360]
中。
将其移动180度即可得到答案。
答案 15 :(得分:-2)
最好使用库函数。他们处理特殊情况,如NaN和无穷大。
topology:
- name: teststormsignals
jar: storm-signals-0.2.1-SNAPSHOT.jar
topologyclass: backtype.storm.contrib.signals.test.SignalTopology
packaging: mvn package
repository: https://github.com/ptgoetz/storm-signals.git