Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Point to location using compass

I am trying to develop a compass for an appliation which has a set of annotations on a map. I would like to be able to choose an annotation and then have the compass point the user to the chosen location.

I have calculated the degress from the user's location to the location of the annotation and I have the magnetic heading and the true heading of the iPhone. Also I know how to rotate an image. But I can't figure out what the next step is.

The degrees between the user's location and the annotation location is calculated like this:

    // get user location
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self; 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
    locationManager.distanceFilter = kCLDistanceFilterNone; 
    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];
    CLLocation *location = [locationManager location];
    CLLocationCoordinate2D coordinate = [location coordinate];

    float x1 = coordinate.latitude;
    float y1 = coordinate.longitude;
    float x2 = [annLatitude floatValue];
    float y2 = [annLongitude floatValue];

    float dx = (x2 - x1);
    float dy = (y2 - y1);

    if (dx == 0) {
        if (dy > 0) {
            result = 90;
        }
        else {
            result = 270;
        }
    }
    else {
        result = (atan(dy/dx)) * 180 / M_PI;
    }

    if (dx < 0) {
        result = result + 180;
    }

    if (result < 0) {
        result = result + 360;
    }

The true and the magnetic heading is retrieved like this:

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    arrow.transform = CGAffineTransformMakeRotation(newHeading.magneticHeading);

    // NSLog(@"magnetic heading: %f", newHeading.magneticHeading);
    // NSLog(@"true heading: %f", newHeading.trueHeading);
}

Can anyone tell me what I should do now to make the arrow point to the location - even if the iPhone is rotated?

like image 627
simonbs Avatar asked Feb 23 '11 15:02

simonbs


People also ask

How do you navigate coordinates with a compass?

Place the straight edge of the compass's base along the line, and point its direction-of-travel arrow in the direction you want to go. Rotate the bezel until the orienting lines align with the grid lines running north to south on the map. The north marker on the compass' bezel should point north on the map.


1 Answers

I had time to play with this again.

This will do it:

- (void)viewDidLoad {
    [super viewDidLoad];

    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self; 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
    locationManager.distanceFilter = kCLDistanceFilterNone; 
    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];

    CLLocation *location = [locationManager location];
    CLLocationCoordinate2D user = [location coordinate];

    [self calculateUserAngle:user];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    CLLocationCoordinate2D here =  newLocation.coordinate;

    [self calculateUserAngle:here];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    compass.transform = CGAffineTransformMakeRotation(newHeading.magneticHeading * M_PI / 180);
    needle.transform = CGAffineTransformMakeRotation((degrees - newHeading.magneticHeading) * M_PI / 180);
}

-(void) calculateUserAngle:(CLLocationCoordinate2D)user {
    locLat = [[targetLocationDictionary objectForKey:@"latitude"] floatValue];
    locLon = [[targetLocationDictionary objectForKey:@"longitude"] floatValue];

    NSLog(@"%f ; %f", locLat, locLon);

    float pLat;
    float pLon;

    if(locLat > user.latitude && locLon > user.longitude) {
        // north east

        pLat = user.latitude;
        pLon = locLon;

        degrees = 0;
    }
    else if(locLat > user.latitude && locLon < user.longitude) {
        // south east

        pLat = locLat;
        pLon = user.longitude;

        degrees = 45;
    }
    else if(locLat < user.latitude && locLon < user.longitude) {
        // south west

        pLat = locLat;
        pLon = user.latitude;

        degrees = 180;
    }
    else if(locLat < user.latitude && locLon > user.longitude) {
        // north west

        pLat = locLat;
        pLon = user.longitude;

        degrees = 225;
    }

    // Vector QP (from user to point)
    float vQPlat = pLat - user.latitude;
    float vQPlon = pLon - user.longitude;

    // Vector QL (from user to location)
    float vQLlat = locLat - user.latitude;
    float vQLlon = locLon - user.longitude;

    // degrees between QP and QL
    float cosDegrees = (vQPlat * vQLlat + vQPlon * vQLlon) / sqrt((vQPlat*vQPlat + vQPlon*vQPlon) * (vQLlat*vQLlat + vQLlon*vQLlon));
    degrees = degrees + acos(cosDegrees);
}
like image 82
simonbs Avatar answered Sep 18 '22 10:09

simonbs