Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding the shortest distance between two angles

Tags:

c#

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}
like image 215
Captain Avatar asked Jan 20 '15 02:01

Captain


4 Answers

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.

like image 98
Kyle Avatar answered Oct 25 '22 22:10

Kyle


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.

like image 41
Mark Shevchenko Avatar answered Oct 26 '22 00:10

Mark Shevchenko


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.

like image 37
Bhaskar Avatar answered Oct 25 '22 23:10

Bhaskar


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);
}
like image 44
2-sticks Avatar answered Oct 26 '22 00:10

2-sticks