Reputation: 10329
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
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
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
lets call the new coordinate (x',y')
Hope this helps.
Upvotes: 0