保持-179和180度之间角度的简便方法

时间:2010-02-23 19:16:16

标签: java math

是否有一种简单的方法可以将角度(以度为单位)转换为介于-179和180之间?我确信我可以使用mod(%)和一些if语句,但它变得丑陋:


//Make angle between 0 and 360
angle%=360;

//Make angle between -179 and 180
if (angle>180) angle-=360;

似乎应该有一个简单的数学运算,它将同时执行两个语句。我现在可能只需要为转换创建一个静态方法。

16 个答案:

答案 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]。由于asinsin的倒数,因此您的输入不会更改(很多,因为您使用的是浮点数,所以会有一些漂移)。因此,您可以获得输入值,并获得所需范围作为反正弦范围的副作用。

由于您需要度数,因此您需要将角度转换为弧度:

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