Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 364
VansFannel Avatar asked Nov 14 '11 14:11

VansFannel


People also ask

How do you find the distance between two latitude longitude points?

For this divide the values of longitude and latitude of both the points by 180/pi. The value of pi is 22/7. The value of 180/pi is approximately 57.29577951. If we want to calculate the distance between two places in miles, use the value 3, 963, which is the radius of Earth.


3 Answers

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 
like image 80
Kirit Vaghela Avatar answered Sep 19 '22 03:09

Kirit Vaghela


I know this question is old, but here is an easier solution:

float bearing = loc1.bearingTo(loc2);

like image 24
Jeremie D Avatar answered Sep 21 '22 03:09

Jeremie D


Try this for accurate result:

private static double degreeToRadians(double latLong) {
    return (Math.PI * latLong / 180.0);
}

private static double radiansToDegree(double latLong) {
    return (latLong * 180.0 / Math.PI);
}

public static double getBearing() {

//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 fLat = degreeToRadians(lat1);
    double fLong = degreeToRadians(lng1);
    double tLat = degreeToRadians(lat2);
    double tLong = degreeToRadians(lng2);

    double dLon = (tLong - fLong);

    double degree = radiansToDegree(Math.atan2(sin(dLon) * cos(tLat),
            cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(dLon)));

    if (degree >= 0) {
        return degree;
    } else {
        return 360 + degree;
    }
}

You can test bearing result on http://www.sunearthtools.com/tools/distance.php .

like image 38
Vishal Jadav Avatar answered Sep 19 '22 03:09

Vishal Jadav