Search code examples
androidiphonegeolocationaugmented-reality

Calculate bearing between two locations (lat, long)


I'm trying to develop my own augmented reality engine.

Searching on internet, I've found this useful tutorial. Reading it I see that the important thing is bearing between user location, point location and north.

The following picture is from that tutorial.

enter image description here

Following it, I wrote an Objective-C method to obtain beta:

+ (float) calculateBetaFrom:(CLLocationCoordinate2D)user to:(CLLocationCoordinate2D)destination
{
    double beta = 0;
    double a, b = 0;

    a = destination.latitude - user.latitude;
    b = destination.longitude - user.longitude;

    beta = atan2(a, b) * 180.0 / M_PI;
    if (beta < 0.0)
        beta += 360.0;
    else if (beta > 360.0)
        beta -= 360;

    return beta;
}

But, when I try it, it doesn't work very well.

So, I checked iPhone AR Toolkit, to see how it works (I've been working with this toolkit, but it is so big for me).

And, in ARGeoCoordinate.m there is another implementation of how to obtain beta:

- (float)angleFromCoordinate:(CLLocationCoordinate2D)first toCoordinate:(CLLocationCoordinate2D)second {

    float longitudinalDifference    = second.longitude - first.longitude;
    float latitudinalDifference     = second.latitude  - first.latitude;
    float possibleAzimuth           = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);

    if (longitudinalDifference > 0) 
        return possibleAzimuth;
    else if (longitudinalDifference < 0) 
        return possibleAzimuth + M_PI;
    else if (latitudinalDifference < 0) 
        return M_PI;

    return 0.0f;
}

It uses this formula:

float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);

Why is (M_PI * .5f) in this formula? I don't understand it.

And continue searching, I've found another page talking about how to calculate distance and bearing of 2 locations. In this page there is another implementation:

/**
 * Returns the (initial) bearing from this point to the supplied point, in degrees
 *   see http://williams.best.vwh.net/avform.htm#Crs
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {Number} Initial bearing in degrees from North
 */
LatLon.prototype.bearingTo = function(point) {
  var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
  var dLon = (point._lon-this._lon).toRad();

  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1)*Math.sin(lat2) -
          Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  var brng = Math.atan2(y, x);

  return (brng.toDeg()+360) % 360;
}

Which one is the right one?


Solution

  • Calculate bearing

    //Source
    JSONObject source = step.getJSONObject("start_location");
    double lat1 = Double.parseDouble(source.getString("lat"));
    double lng1 = Double.parseDouble(source.getString("lng"));
    
    // destination
    JSONObject destination = step.getJSONObject("end_location");
    double lat2 = Double.parseDouble(destination.getString("lat"));
    double lng2 = Double.parseDouble(destination.getString("lng"));
    
    double dLon = (lng2-lng1);
    double y = Math.sin(dLon) * Math.cos(lat2);
    double x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
    double brng = Math.toDegrees((Math.atan2(y, x)));
    brng = (360 - ((brng + 360) % 360));
    

    Convert Degrees into Radians

    Radians = Degrees * PI / 180
    

    Convert Radians into Degrees

    Degrees = Radians * 180 / PI