Getting the difference between two headings
Asked Answered
C

5

11

I have this method for figuring out the difference between 2 0-360 compass headings.

Although this works for figuring out how far absolutely (as in, always positive output) off I am, I am having trouble figuring out what needs to be done to introduce the sign into the output.

Ideally, if the shortest distance from the initial heading to the final heading is by going around clockwise, I'd like the error to have a positive sign, if the shortest distance between the headings involves going around counterclock-wise, I'd like the error to have a negative sign.

A few examples of desired inputs/outputs

initial -- final -- error

0 .................... 30 .......... 30

30 .................... 0 .......... -30

360 .................... 1 .......... 1

1 .................... 360 .......... -1

Code:

    /// <summary>
    /// Calculate the error from a given initial heading to a final heading
    /// </summary>
    /// <param name="inital"></param>
    /// <param name="final"></param>
    /// <returns></returns>
    private double GetHeadingError(double initial, double final)
    {
        double directionA = final - initial;
        double directionB = 360 - (final + initial);
        double error = 0;

        if (Math.Abs(directionA) < Math.Abs(directionB))
        {
            error = directionA;
        }
        else
        {
            error = directionB;
        }

        return error;
    }
Chryselephantine answered 17/2, 2011 at 2:11 Comment(0)
R
16

Edit: added check for when the difference is exactly 180 degrees. previously this was returning either 180 or -180 depending on whether final was greater or lower than initial. I've modified it so that it returns positive 180 in both cases.


So here's my attempt...

private static double GetHeadingError(double initial, double final)
        {
            if (initial > 360 || initial < 0 || final > 360 || final < 0)
            {
                //throw some error
            }

            var diff = final - initial;
            var absDiff = Math.Abs(diff);

            if (absDiff <= 180)
            {
                //Edit 1:27pm
                return absDiff == 180 ? absDiff : diff;
            }

            else if (final > initial)
            {
                return absDiff - 360;
            }

            else
            {
                return 360 - absDiff;
            }
        }
Refrigeration answered 17/2, 2011 at 3:7 Comment(2)
Really useful: I have struggled with this for a while.Jennings
This didn't work for me when the headings were close to 0. See my solution below, which is based on this avionics answer.Subtract
S
9

Here's a straightforward solution, albeit named a bit differently and in Dart. Based on this avionics answer.

/// The difference of two headings in degrees such that it is always in the range
/// (-180, 180]. A negative number indicates [h2] is to the left of [h1].
double headingDiff(double h1, double h2) {
  double left = h1 - h2;
  double right = h2 - h1;
  if (left < 0) left += 360;
  if (right < 0) right += 360;
  return left < right ? -left : right;
}

Edit: There's an even more concise answer here, but I haven't tried it myself:

double headingDiff(double h1, double h2) => (h2 - h1 + 540) % 360 - 180;
Subtract answered 22/2, 2019 at 4:55 Comment(1)
I tested and used the short form (concise version) and worked. Even adapted to store in a byte (mapped 360 -> 256 and adjusted formula accordingly)Purpleness
P
2

If I understand the question correctly, I think the following code should work:

private double GetHeadingError(double initial, double final)
{
            if(initial == 360) initial = 0;
            if(final == 360) final = 0;
            double clockWise = (final - initial);
            double counterClockWise = (360 - final + initial);
            return (Math.Abs(clockWise) <= Math.Abs(counterClockWise)) ? clockWise : -counterClockWise;
}

Basically I'm treating 360 degrees the same as 0, which I believe is ok. This code will produce the same results as listed in the table above. Code does not do bounds checking, it is expecting values between 0 and 360.

Phonetician answered 17/2, 2011 at 3:13 Comment(0)
E
1

I think your table of desired results is incorrect. Here's my klunky way:

private double MyGetHeadingError(double initial, double final)
{
    initial += 1000;
    final += 1000;

    bool flipped = false;
    if (initial > final)
    {
        double temp;
        temp = final;
        final = initial;
        initial = temp;
        flipped = true;
    }
    double error;
    if (final - initial > 180)
        final = final - 360;

    error = final - initial;

    if (flipped == true)
        error = -error;
    return error;
}
Electroacoustics answered 17/2, 2011 at 2:39 Comment(0)
L
0
Degree_Diff = (MIN(ABS(ENDCOMPASS-STARTCOMPASS),ABS(360-ENDCOMPASS+STARTCOMPASS),ABS(360-STARTCOMPASS+ENDCOMPASS))) 
Lazarolazaruk answered 28/2, 2012 at 3:13 Comment(1)
Welcome to stackoverflow! It's always better to provide a short description for a sample code to improve the post accuracy :)Ides

© 2022 - 2024 — McMap. All rights reserved.