1

I am building an application that should show an arrow to a certain location. Forinstance, if I am at position X and the target is set to position Y, it should show an arrow pointing directly to that position.

After searching and searching I found that there are some fancy formulas of calculating this, however I seem to get it wrong over and over.

This is my problem. Although it seems to find the correct initial position, as soon as I turn my device the "arrow" turns in the opposite direction or what it should. So, if I turn my device clockwise, the arrow turns also clockwise... and visa versa.

This is some of my code:

@implementation CompassViewController

BOOL firstPositionFound = NO;
float lastPosition = 0;
float currentHeading = 0;

[...]

#pragma mark - 
#pragma mark Core Location Methods

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    if (newHeading.headingAccuracy > 0) {
        CLLocationDirection theHeading = newHeading.magneticHeading;

        currentHeading = theHeading;

        [self fixPointer:theHeading];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
    self.currentLocation = newLocation;

    [self fixPointer:currentHeading];
}

- (void)fixPointer:(float)heading
{
    float degree = [self calculateDegree:self.currentLocation];

    degree = heading - degree;

    NSLog(@"heading: %f, Degree: %f", heading, degree);

    NSLog(@"Degree 2: %f", degree);

    self.arrowView.transform = CGAffineTransformMakeRotation(degreesToRadians(degree));
}

#pragma mark -
#pragma mark Delegate methods

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark -
#pragma mark Other methods

- (float)calculateDegree:(CLLocation *)newLocation
{
    CLLocationCoordinate2D from = newLocation.coordinate;
    CLLocationCoordinate2D to;
    to.latitude = APP_DESTINATION_LAT;
    to.longitude = APP_DESTINATION_LON;

    float res = atan2(sin((to.longitude*M_PI/180)-(from.longitude*M_PI/180))*cos(to.latitude*M_PI/180),
                      cos(from.latitude*M_PI/180)*sin(to.latitude*M_PI/180)-sin(from.latitude*M_PI/180)*cos(to.latitude*M_PI/180)*cos((to.longitude*M_PI/180)-(from.longitude*M_PI/180)));

    res = res/M_PI*180;

    if (res < 0)
        res = 360.0f + res;

    return res;
}

#pragma mark -

I am just lost, could someone please point out to me where I went wrong? I guess its some simple thing that I currently am to blind for to see.

Paul Peelen
  • 10,073
  • 15
  • 85
  • 168

2 Answers2

2

Have a look at the answer in this Stack Overflow question:

CLLocation Category for Calculating Bearing w/ Haversine function

specifically, this part:

If you are getting negative bearings, add 2*M_PI to the final result in radiansBearing (or 360 if you do it after converting to degrees). atan2 returns the result in the range -M_PI to M_PI (-180 to 180 degrees), so you might want to convert it to compass bearings, using something like the following code

if(radiansBearing < 0.0)
    radiansBearing += 2*M_PI;**

Also, heading info needs to be adjusted for device orientation and angle, unless you are always holding your device in portrait. Turn you device slowly to landscape mode and you will see your heading value change by 90°.

Community
  • 1
  • 1
Jenn
  • 171
  • 7
  • Thank you! Your answer did really help me. I updated my code the the one you refered to, which was way better. However, I still have one problem now: It seems to get the right degrees for my lon/lat towards the destination... but it expects the phone to have a 0 heading (pointing north). If I calculate the radius subtracting the heading from the bearing it still doesn't become accurate. Any suggestions there? – Paul Peelen May 21 '12 at 07:04
  • @jenni-b Do you have any suggestions for me? – Paul Peelen May 24 '12 at 11:52
  • 1
    @Paul Peelen Without seeing your code, I would not know how to answer you, however, the easy answer is to make sure you are using the correct units and adjusting for device orientation. So make sure that you are subtracting degrees from degrees and not degrees from radians and make sure the value you are getting from the magnetometer has been adjusted for the device orientation. – Jenn May 27 '12 at 13:13
0

Check this out Wikipedia - On rotation matrix

From I understand from the code you have the angle between the sin element and the cos element of the given (x,y) coordinate. [Basically given by (tan(x,0)/(0,y))]

lets call this angle theta.

What you should do is take this coordinate and multiply it by

CC wikipedia

lets call the new coordinate (x',y')

x'

y'

Hope this helps.

raam86
  • 6,785
  • 2
  • 31
  • 46