# Compass example from a book

Discussion in 'iOS Programming' started by idelovski, May 11, 2010.

1. ### idelovski macrumors regular

Joined:
Sep 11, 2008
#1
I typed the compass example from "Sams Teach Yourself iPhone Application Development in 24 Hours" that is supposed to point me to the direction of Chapel Hill, N. Carolina in US. I am in Europe, so I expected it to point to the west, but is pointing somewhere north instead.

I even tried the original project that can be downloaded and it works the same. The code can be downloaded here, it is in the chapter 22 folder, ChapelHill project.

The problem could be with the method that calculates heading for a location from current location. Maybe there's somethin related with radians and degrees.
Code:
```/*
* According to Ask Dr. Math:
* http://mathforum.org/library/drmath/view/55417.html
*
* y = sin(lon2-lon1)*cos(lat2)
* x = cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1)
* if y > 0 then
*    if x > 0 then tc1 = arctan(y/x)
*    if x < 0 then tc1 = 180 - arctan(-y/x)
*    if x = 0 then tc1 = 90
* if y < 0 then
*    if x > 0 then tc1 = -arctan(-y/x)
*    if x < 0 then tc1 = arctan(y/x)-180
*    if x = 0 then tc1 = 270
*    if y = 0 then
* if x > 0 then tc1 = 0
*    if x < 0 then tc1 = 180
*    if x = 0 then [the 2 points are the same]
*/
```
That was the algorithm, and here's the actual code:
Code:
```-(double)headingToLocation:(CLLocationCoordinate2D)desired
current:(CLLocationCoordinate2D)current {

// Gather the variables needed by the heading algorithm
double lat1 = current.latitude;
double lat2 = desired.latitude;
double lon1 = current.longitude;
double lon2 = desired.longitude;
double y = sin(lon2-lon1)*cos(lat2);
double x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1);

if (y > 0) {
if (x > 0) heading = atan(y/x);
else if (x < 0) heading = 180 - atan((-1 * y)/x);
} else if (y < 0) {
if (x > 0) heading = -1 * atan((-1 * y)/x);
else if (x < 0) heading = atan(y/x) - 180;
} else {
if (x > 0) heading = 0;
}
}```
That method is then used in this compass delegate:
Code:
```- (void)locationManager:(CLLocationManager *)manager

CLLocation *chapelHill = [[[CLLocation alloc]
initWithLatitude:kChapelHillLatitude
longitude:kChapelHillLongitude] autorelease];
current:recentLocation.coordinate];
if (abs(delta) <= 10) {
directionArrow.image = [UIImage imageNamed:@"up_arrow.png"];
} else {
if (delta > 180) directionArrow.image =
[UIImage imageNamed:@"right_arrow.png"];
else if (delta > 0) directionArrow.image =
[UIImage imageNamed:@"left_arrow.png"];
else if (delta > -180) directionArrow.image =
[UIImage imageNamed:@"right_arrow.png"];
else directionArrow.image = [UIImage imageNamed:@"left_arrow.png"];
}
directionArrow.hidden = NO;
} else {
directionArrow.hidden = YES;
}
}```
Can someone please point me to some sort of a solution.

EDIT: And I am running this code on my 3Gs, original Compass application seem to work ok, Maps can locate me just fine.

2. ### neoserver macrumors 6502

Joined:
Apr 24, 2003
#2
The trig functions require their arguments to be in radians while Lat/long are in degrees. Try multiplying your lat/long by
Code:
`M_PI/180`
to convert them to radians. M_PI is a constant for Pi that should be provided by the SDK.

Like so:
Code:
```double lat1 = current.latitude * (M_PI/180);
```

3. ### chown33 macrumors 604

Joined:
Aug 9, 2009
Location:
Brobdingnag
#3
CLLocationCoordinate2D has units of degrees. AFAIK, the trig functions sin(), cos(), atan(), etc. only take units of radians. So it looks to me like the code is mixing units without proper conversions.

It's pretty easy to write test code to verify what units the trig functions are using.

It should also be pretty easy to write test code to pass specific values in CLLocationCoordinate2D, and see if the method calculates the correct heading. I would try points due north, east, south, and west of Chapel Hill, at a distance of say 10 degrees. The results should be unambiguous.

4. ### idelovski thread starter macrumors regular

Joined:
Sep 11, 2008
#4

Code:
```#define  rad2deg(r) (180. * (r) / M_PI)
#define  deg2rad(d) (M_PI * (d) / 180.)

current:(CLLocationCoordinate2D)current
{
// Gather the variables needed by the heading algorithm

// Values in comments from debugger

double  lon1 = deg2rad(current.longitude);  // 15.93372404 ->  0.278095466
double  lon2 = deg2rad(desired.longitude);  // -79.0557029 -> -1.379782308

double  lat1 = deg2rad(current.latitude);   // 45.780882769999998 -> 0.7990271388
double  lat2 = deg2rad(desired.latitude);   // 35.913150100000003 -> 0.6266802714

double  y = sin (lon2-lon1) * cos (lat2);
double  x = (cos (lat1) * sin (lat2)) - (sin (lat1) * cos (lat2) * cos (lon2-lon1));

if (y > 0)  {
if (x > 0)
else if (x < 0)
else
}
else if (y < 0)  {
if (x > 0)
heading = -1 * rad2deg (atan ((-1 * y)/x));  // This case is used!
else if (x < 0)
else
}
else  {
if (x > 0)
else
}

}
```
As return value, heading is -60 degrees. Just thinking about it, the number doesn't feel right. Should be like 90 to 100 degrees to the west. Greenland is like -60 degrees I suppose.

5. ### chown33 macrumors 604

Joined:
Aug 9, 2009
Location:
Brobdingnag
#5
The convention in navigation is 0 degrees is due north, and degrees increase going clockwise (so due east is +90). This convention has opposite sign and a 1/4-circle offset from conventional 2D cartesian coordinates.

6. ### idelovski thread starter macrumors regular

Joined:
Sep 11, 2008
#6
Yes, when I said "Should be like 90 to 100 degrees to the west" I meant -90 to -100 degrees.

From where I am, Berlin is like at 12 o'clock, Rome is at 6 o'clock, Beijing at 3 o'clock, and Chapel Hill at 9 o'clock, maybe 8:30 or something like that.

7. ### bredell macrumors regular

Joined:
Mar 30, 2008
Location:
Uppsala, Sweden
#7
Actually, the direction from Europe to North Carolina is more north/northwest. If you look at a map NC appears to be to the west but an ordinary map is not an accurate projection of the earth. If you look at a globe you'll see that the direction is more north/northwest.

8. ### idelovski thread starter macrumors regular

Joined:
Sep 11, 2008
#8
Thanks,

Just downloaded that Google Earth plug-in and saw it. Looks so obvious now. And explains why Titanic was so up to the north when it hit that ice.

So, second version of that method works well and -60 degrees (or 300 degrees) it returns as general direction from my place to Chapel Hill is valid. Cool.

### Staff Member

Joined:
Sep 2, 2004
Location:
The Centennial State
#9
idelovski, where exactly in Europe are you? The latitude of Chapel Hill is 35.913N. Therefore, anything around that latitude in Europe is going to give you a heading of about -90º. But Europe is a large place that stretches from about 36N to 71N. So, pretty much all of Europe lies north of Chapel Hill and thus you should expect a heading to be more southwest than northwest.

10. ### idelovski thread starter macrumors regular

Joined:
Sep 11, 2008
#10
dejo,

you can see those 36N to 71N (with more precision) in the comments of my second version of -headingToLocation:current: method.

I am at 45North and that is why I expected the direction to be just over -90 degrees, maybe closer to -100, as you say southwest, something like that. But when I looked at Google Earth, it was obvious that the shortest line on Eart's surface would go a bit more to the north.

edit: coordinets from the book are
Lat: 35.91315010
Long: -79.055702
I just typed them as they were presented in the book. I suppose they are correct.

### Staff Member

Joined:
Sep 2, 2004
Location:
The Centennial State
#11
Shortest line to destination != heading.

12. ### idelovski thread starter macrumors regular

Joined:
Sep 11, 2008
#12
Well, author of the book gave that method its name. Me, I would have called it -degreesToLocation:fromCurrentLocation:.

### Staff Member

Joined:
Sep 2, 2004
Location:
The Centennial State
#13
Maybe I am confusing heading with bearing. Sorry. Just ignore me.

14. ### idelovski thread starter macrumors regular

Joined:
Sep 11, 2008
#14
Well, english is not my first language, so I can never be 100% sure about these things. I had to look it up in a dictionary just to see all of its meanings. For me, bearing was that thing in cars, trains, bikes, ... related to wheels.

Found this: Direction, especially angular direction measured from one position to another using geographical or celestial reference lines.