Paul Peelen
Paul Peelen

Reputation: 10329

Calculate degrees for position

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.

Upvotes: 1

Views: 2475

Answers (2)

Jenn
Jenn

Reputation: 171

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°.

Upvotes: 2

raam86
raam86

Reputation: 6871

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.

Upvotes: 0

Related Questions