Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Easy way to keeping angles between -179 and 180 degrees

Tags:

java

math

Is there an easy way to convert an angle (in degrees) to be between -179 and 180? I'm sure I could use mod (%) and some if statements, but it gets ugly:


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

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

It just seems like there should be a simple math operation that will do both statements at the same time. I may just have to create a static method for the conversion for now.

like image 899
User1 Avatar asked Feb 23 '10 19:02

User1


People also ask

What is 180 degrees look like?

The 180-degree angle is known as a straight angle. The sides of the angle are opposite to each other and they make a straight angle on a straight line through the vertex. The appearance of a 180-degree angle is a straight line.

What do u call an angle between 180 and 360?

Angles that are 180 degrees (θ = 180°) are known as straight angles. Angles between 180 and 360 degrees (180°< θ < 360°) are called reflex angles.

What is angle wrap?

What is Wrap Angle? Wrap Angle is a measurement in degrees of the diameter of a sensor roller that the tensioned material contacts. Most tension sensing rollers have a minimum and maximum wrap angle they are compatible with.


6 Answers

// 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;  
like image 96
President James K. Polk Avatar answered Sep 25 '22 11:09

President James K. Polk


Try this instead!

atan2(sin(angle), cos(angle))

atan2 has a range of [-π, π). This takes advantage of the fact that tan θ = sin θ / cos θ, and that atan2 is smart enough to know which quadrant θ is in.

Since you want degrees, you will want to convert your angle to and from radians:

atan2(sin(angle * PI/180.0), cos(angle * PI/180.0)) * 180.0/PI

Update My previous example was perfectly legitimate, but restricted the range to ±90°. atan2's range is the desired value of -179° to 180°. Preserved below.


Try this:

asin(sin(angle)))

The domain of sin is the real line, the range is [-1, 1]. The domain of asin is [-1, 1], and the range is [-PI/2, PI/2]. Since asin is the inverse of sin, your input isn't changed (much, there's some drift because you're using floating point numbers). So you get your input value back, and you get the desired range as a side effect of the restricted range of the arcsine.

Since you want degrees, you will want to convert your angle to and from radians:

asin(sin(angle * PI/180.0)) * 180.0/PI

(Caveat: Trig functions are bazillions of times slower than simple divide and subtract operations, even if they are done in an FPU!)

like image 22
Seth Avatar answered Sep 26 '22 11:09

Seth


This works with both negative and decimal numbers and doesn't require loops, nor trigonometric functions:

angle -= Math.floor(angle / 360 + 0.5) * 360

The result is in the [-180, 180) interval. For (-180, 180] interval, you can use this instead:

angle -= Math.ceil(angle / 360 - 0.5) * 360

like image 23
Astronomino Avatar answered Sep 25 '22 11:09

Astronomino


I know that years have passed, but still.

This solution contains no loops, no subtracting, no modulo (allows to normalize to radians interval). Works for any input, including negative values, big values, edge cases.

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):
like image 28
alexburtnik Avatar answered Sep 24 '22 11:09

alexburtnik


Not that smart, too, but no if.

angle = (angle + 179) % 360 - 179;

But I am not sure how Java handles modulo for negative numbers. This works only if -1 modulo 360 equals 359.

UPDATE

Just checked the docs and a % b yields a value between -(|b| - 1) and +(|b| - 1) hence the code is broken. To account for negative values returned by the modulo operator one has to use the following.

angle = ((angle + 179) % 360 + 360) % 360 - 179;

But ... no ... never ... Use something similar to your initial solution, but fixed for values smaller then -179.

like image 21
Daniel Brückner Avatar answered Sep 27 '22 11:09

Daniel Brückner


I'm a little late to the party, I know, but...

Most of these answers are no good, because they try to be clever and concise and then don't take care of edge cases.

It's a little more verbose, but if you want to make it work, just put in the logic to make it work. Don't try to be clever.

int normalizeAngle(int angle)
{
    int newAngle = angle;
    while (newAngle <= -180) newAngle += 360;
    while (newAngle > 180) newAngle -= 360;
    return newAngle;
}

This works and is reasonably clean and simple, without trying to be fancy. Note that only zero or one of the while loops can ever be run.

like image 8
Platinum Azure Avatar answered Sep 25 '22 11:09

Platinum Azure