3

How do I calculate the angle in degrees between the coordinates of two POIs (points of interest) on an iPhone map application?

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
mr.octobor
  • 191
  • 2
  • 4
  • 18

3 Answers3

13

I'm guessing you try to calculate the degrees between the coordinates of two points of interest (POI).

Calculating the arc of a great circle:

+(float) greatCircleFrom:(CLLocation*)first 
                      to:(CLLocation*)second {

    int radius = 6371; // 6371km is the radius of the earth
    float dLat = second.coordinate.latitude-first.coordinate.latitude;
    float dLon = second.coordinate.longitude-first.coordinate.longitude;
    float a = pow(sin(dLat/2),2) + cos(first.coordinate.latitude)*cos(second.coordinate.latitude) * pow(sin(dLon/2),2);
    float c = 2 * atan2(sqrt(a),sqrt(1-a));
    float d = radius * c;

    return d;
}

Another option is to pretend you are on cartesian coordinates (faster but not without error on long distances):

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

    float deltaLongitude = second.longitude - first.longitude;
    float deltaLatitude = second.latitude - first.latitude;
    float angle = (M_PI * .5f) - atan(deltaLatitude / deltaLongitude);

    if (deltaLongitude > 0)      return angle;
    else if (deltaLongitude < 0) return angle + M_PI;
    else if (deltaLatitude < 0)  return M_PI;

    return 0.0f;
}

If you want the result in degrees instead radians, you have to apply the following conversion:

#define RADIANS_TO_DEGREES(radians) ((radians) * 180.0 / M_PI)
Jano
  • 62,815
  • 21
  • 164
  • 192
2

You are calculating the 'Bearing' from one point to another here. There's a whole bunch of formula for that, and lots of other geographic quantities like distance and cross-track error, on this web page:

http://www.movable-type.co.uk/scripts/latlong.html

the formulae are in several formats so you can easily convert to whatever language you need for your iPhone. There's also javascript calculators so you can test your code gets the same answers as theirs.

Spacedman
  • 92,590
  • 12
  • 140
  • 224
  • Indeed Jano's stuff didnt work here, but the site you mention did help a lot. But take care: they forgot to mention that the lat/long have to be in radiant format in the bearing example for Javascript. – brainray Feb 11 '14 at 11:05
1

If the other solutions dont work for you try this:

- (int)getInitialBearingFrom:(CLLocation *)first
                        to:(CLLocation *)second
{
    float lat1 = [self degreesToRad:first.coordinate.latitude];
    float lat2 = [self degreesToRad:second.coordinate.latitude];
    float lon1 = [self degreesToRad:first.coordinate.longitude];
    float lon2 = [self degreesToRad:second.coordinate.longitude];
    float dLon = lon2 - lon1;
    float y = sin (dLon) * cos (lat2);
    float x1 = cos (lat1) * sin (lat2);
    float x2 = sin (lat1) * cos (lat2) * cos (dLon);
    float x = x1 - x2;
    float bearingRadRaw = atan2f (y, x);
    float bearingDegRaw = bearingRadRaw * 180 / M_PI;
    int bearing = ((int) bearingDegRaw + 360) % 360; // +- 180 deg to 360 deg

    return bearing;
}

For final bearing, simply take the initial bearing from the end point to the start point and reverse it (using θ = (θ+180) % 360).

You need these 2 helpers:

-(float)radToDegrees:(float)radians
{
    return radians * 180 / M_PI;
}
-(float)degreesToRad:(float)degrees
{
    return degrees * M_PI /180;
}
brainray
  • 12,512
  • 11
  • 67
  • 116