I've been trying to find a way of finding the shortest distance between two angles. The angles are in the interval -360 < 360 and are given in degrees.
In short, i need a simple way (the simpler the better) to find the shortest distance between two angles, let's call them angle1 and angle2. Angle1 is the angle i want to get to, angle 2 is the angle i am at. After this i want to use an if function to determine the rotation direction of an entity.
Pseudocode:
CloseDistance = (Find shortest distance between angle1 (where i want to go) and angle2 (where i am))
if (CloseDistance > Something)
{Rotate to the right} else {Rotate to the left}
public static double AngleDifference( double angle1, double angle2 )
{
double diff = ( angle2 - angle1 + 180 ) % 360 - 180;
return diff < -180 ? diff + 360 : diff;
}
This works by noticing that we want to take the difference between the two angles, angle1
and angle2
and wrap that result to the range [-180, 179). The mod operator allows us to wrap something to the range [0, n). I.e. x % n
"wraps" (with a caveat for x < 0
) x to the range [0, n).
Our range starts at -180 rather than 0, so we shift it over by adding 180. Then we wrap to 360, then we shift back. That's what the first line of the method does.
The second line takes care of that little wrinkle with negative numbers. If angle2 - angle1 + 180
happened to be less than 0, then diff
will be less than -180. In that case we just wrap it back into range by adding 360 to it. Otherwise we do nothing.
As an added bonus, the input angles are completely unconstrained. They need not be between -360 and 360. They can be anything.
It seems you need result angle in interval -180..+179. Negative signs means right rotation, positive means left (or vice versa).
Ergo, you need the modular arithmetic with modulo 360.
In C# remaidner operator does what you need:
var distance = (destinationAngle - sourceAngle) % 360;
Unfortunately it gives result in interval -359..+359. To correct this you can transform too large values to interval -180..+179:
var distance = (destinationAngle - sourceAngle) % 360;
if (distance < -180)
distance += 360;
else if (distance > 179)
distance -= 360;
Asymmetric ends of interval (-180 and +179) have appeared because -180 and +180 both are the same angle, so you should choose one of them to avoid ambiguity.
F.e.
Destination | Source | Result
45 | 30 | 15
30 | 45 | -15
-45 | -30 | -15
-30 | -45 | 15
360 + 45 = 405 | 30 | 15
-405 | -30 | -15
As I can see it what you need. If your angles are doubles, use Math.IEEERemainder method.
The Simplest way I found is
double closedistance = (destangle - startangle) % 360
abs(closedistance)
gives you the required distance.
sign of closedistance (= closedistance/abs(closedistance)
) gives the direction of rotation (+ anticlockwise, - clockwise) or just check it like this
if (closedistance > 0) {} // anticlockwise
else {} // clockwise
This works for any value of angles.
Here's my Python version which I find easier to explain:
def smallestAngle(currentAngle, targetAngle) -> int:
# Subtract the angles, constraining the value to [0, 360)
diff = ( targetAngle - currentAngle) % 360
# If we are more than 180 we're taking the long way around.
# Let's instead go in the shorter, negative direction
if diff > 180 :
diff = -(360 - diff)
return diff
Beware that some systems' modulo functions return negative values and will not work! If you are using Javascript, here is a modulo function you seek:
// Javascript always-positive modulo function
const mod = (n, m) => ((n % m) + m) % m
I was asked to show this in C# so here you go...
public static double smallestAngle(double currentAngle, double targetAngle)
{
double diff = (targetAngle - currentAngle) % 360;
return diff <= 180 ? diff : -(360 - diff);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With