user6106573
user6106573

Reputation: 191

Bearing calculation in C#

I want to calculate bearing between 2 GPS positions, I foollowed this page recommandations for my algorythm:

    public static double Bearing(IPointGps pt1, IPointGps pt2)
    {
        double x = Math.Cos(pt1.Latitude) * Math.Sin(pt2.Latitude) - Math.Sin(pt1.Latitude) * Math.Cos(pt2.Latitude) * Math.Cos(pt2.Longitude - pt1.Longitude);
        double y = Math.Sin(pt2.Longitude - pt1.Longitude) * Math.Cos(pt2.Latitude);

        // Math.Atan2 can return negative value, 0 <= output value < 2*PI expected 
        return (Math.Atan2(y, x) + Math.PI * 2)%(Math.PI * 2);
    }

Then I transform my value in degrees using this method

    public static double RadiansToDegrees(double angle)
    {
        return (angle * 180.0) / Math.PI;
    }

I have the following test sample:

However, I obtain a bearing of 315.5° (5.5062235835910762 rad). If i calculate the expected radian value, i get 5.637413 which leaves no doubt that my problem lies in my bearing method.

I already implemented other computation methods using .Net Math package (including Cos, Sin, Tan and ATan methods) and my unit tests pass with 1e-12 precision. What am I missing?

PS: I also tryied to reimplement the Atan2 method in case there is a lack of precision in it. I obtain the very same result

edit: My Latitude and Longitude are double as per the following interface

public interface IPointGps
{
    double Latitude { get; }
    double Longitude { get; }
}

Upvotes: 3

Views: 4484

Answers (2)

Ňuf
Ňuf

Reputation: 6217

Math.Sin() and all similar methods expect argument in radians, but your latitudes and longitudes are in degrees. You have to convert IPointGps to radians before you calculate bearing, or modify Bearing calculation, e.g.:

public static double Bearing(IPointGps pt1, IPointGps pt2)
{
    double x = Math.Cos(DegreesToRadians(pt1.Latitude)) * Math.Sin(DegreesToRadians(pt2.Latitude)) - Math.Sin(DegreesToRadians(pt1.Latitude)) * Math.Cos(DegreesToRadians(pt2.Latitude)) * Math.Cos(DegreesToRadians(pt2.Longitude - pt1.Longitude));
    double y = Math.Sin(DegreesToRadians(pt2.Longitude - pt1.Longitude)) * Math.Cos(DegreesToRadians(pt2.Latitude));

    // Math.Atan2 can return negative value, 0 <= output value < 2*PI expected 
    return (Math.Atan2(y, x) + Math.PI * 2) % (Math.PI * 2);
}

public static double DegreesToRadians(double angle)
{
    return angle * Math.PI / 180.0d;
}

returns bearing 5.637716736134105.

Upvotes: 5

Sergio Monteleone
Sergio Monteleone

Reputation: 2886

It looks like your latitude and longitude variables are float (single precision). If that is the case, then your are facing a precision error.

Upvotes: 0

Related Questions