There is a standard "heading" or "bearing" equation that you can use - if you are at lat1,lon1, and the point you are interested in is at lat2,lon2, then the equation is:

heading = atan2( sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1))

This gives you a bearing in radians, which you can convert to degrees by multiplying by 180/π. The value is then between -180 and 180 degrees, so to get a standard compass bearing add 360 to any negative answers.

atan2 is a standard function related to arctan, that does the right thing for the four possible quadrants that your destination point could be in compared to where you are.


1) Get your current location (from the GPS)

2) Get the differences in latitude and longitude

3) use the atan2 method to get the angle

i.e. (WARNING: untested code)

CLLocation *targetLocation = [CLLocation alloc] initWithLatitude:1 longitude:2];
CLLocation *sourceLocation = <get from GPS>

double dx = [targetLocation coordinate].latitude - [sourceLocation coordinate].latitude;
double dy = [targetLocation coordinate].longitude - [sourceLocation coordinate].longitude;

double angle = atan2(dx, dy);

You might have to tweak that to get it to compile but the idea is there!


I did this some time ago, here are two different implementations. The first is similar to your approach, the second is without the trig math. The first is what I used in my app, but the second seemed to work as well, though doesn't appear to be as clean. You will need to also remember to offset this bearing based on north in your UI.

- (double) toRadian: (double) val
{
    return val * (M_PI / 180);
}

// Convert to degrees from radians
- (double) toDegrees: (double) val
{
    return val * 180 / M_PI;
}

// convert from a radian to a 360 degree format.
- (double) toBearing: (double) val
{
    return ( (int)([self toDegrees: val]) + 360 ) % 360;        // use mod to get the degrees
}

// Calculate the bearing based off of the passed coordinates and destination.  
//
- (double) calcBearingWithLatitude:(CLLocationDegrees)latSource 
                             latitude:(CLLocationDegrees)latDest 
                            longitude:(CLLocationDegrees)lonSrc 
                            longitude:(CLLocationDegrees)lonDest
{
    double lat1 = [self toRadian:latSource];
    double lat2 = [self toRadian:latDest];
    double dLon = [self toRadian:(lonDest - lonSrc)];

    double y = sin(dLon) * cos(lat2);
    double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
    return [self toBearing:atan2(y, x)];
}

And the second.

// got this code from some forums and modified it, thanks for posting it coullis!  Mostly here for reference on how to do this without sin and cos.
- (CLLocationDegrees) altCalcBearingWithLatitude:(CLLocationDegrees)latSource 
                                        latitude:(CLLocationDegrees)latDest 
                                       longitude:(CLLocationDegrees)lonSrc 
                                       longitude:(CLLocationDegrees)lonDest

{
    CLLocationDegrees result;


// First You calculate Delta distances.
float dx = lonSrc - latSource;
float dy = lonDest - latDest;

// If x part is 0 we could get into division by zero problems, but in that case result can only be 90 or 270:
if (dx==0)
{
    if (dy > 0)
        result = 90;
    else
        result = 270;
}
else
{
    result = [self toDegrees: atan(dy/dx)];
}

// This is only valid for two quadrants (for right side of the coordinate system) so modify result if necessary...
if (dx < 0) 
    result = result + 180;

// looks better if all numbers are positive (0 to 360 range)
if (result < 0)
    result = result + 360;

// return our result.
return result;

}