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?
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);
}
Related
First, thank you, and next, it's my problem, the core code:
for(int idx = 0; idx < route0.polyLine.count; idx++)
{
CLLocationCoordinate2D coordinate = [[route0.polyLine objectAtIndex:idx] coordinate];
minLat = MIN(minLat, coordinate.latitude);
minLon = MIN(minLon, coordinate.longitude);
maxLat = MAX(maxLat, coordinate.latitude);
maxLon = MAX(maxLon, coordinate.longitude);
}
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 1.06f*(maxLat - minLat);
span.longitudeDelta = 1.06f*(maxLon - minLon);
CLLocationCoordinate2D location;
location.latitude = (minLat + maxLat)/2;
location.longitude = (minLon + maxLon)/2;
region.span=span;
region.center=location;
[_mapView regionThatFits:region];
[_mapView setRegion:region animated:false];
My attentio is let the annotations on the mapview just fit screen, but if the annotations is too close, will appear:
When I show UIViewController with UIMapView, in viewDidLoad I add PointAnnotation to map and to array. Then I calculate the region for these annotations and set that region to map.
The point is that sometimes (basically only once after installing app for the first time) the map shows region for equator even if my data is correct.
-(void)viewDidLoad
{
NSLog(#"Spot: %#", _spot);
_annotations = [[NSMutableArray alloc] init];
[super viewDidLoad];
// Adding annotation of spot
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = self.spot.latitude;
annotationCoord.longitude = self.spot.longitude;
POPointAnnotation *annotationPoint = [[POPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = self.spot.name;
annotationPoint.subtitle = self.spot.address;
annotationPoint.type = PointAnnotaitonTypeSpot;
[_annotations addObject:annotationPoint];
[((SpotsMapView *)self.view).mapView addAnnotation:annotationPoint];
[annotationPoint release];
// Adding annotation of user position
CLLocationCoordinate2D userCoord;
userCoord = [[POLocationManager sharedInstance] location].coordinate;
POPointAnnotation *userPoint = [[POPointAnnotation alloc] init];
userPoint.coordinate = userCoord;
userPoint.title = NSLocalizedString(#"Punkt startowy", #"Punkt startowy");
userPoint.type = PointAnnotationTypeStart;
[_annotations addObject:userPoint];
[((SpotsMapView *)self.view).mapView addAnnotation:userPoint];
[userPoint release];
[((SpotsMapView *)self.view).mapView setRegion:[self regionFromLocations] animated:YES];
[((SpotsMapView *)self.view).mapView setShowsUserLocation:YES];
}
and region here:
- (MKCoordinateRegion)regionFromLocations {
CLLocationCoordinate2D upper = [[self.annotations objectAtIndex:1] coordinate];
CLLocationCoordinate2D lower = [[self.annotations objectAtIndex:1] coordinate];
NSLog(#"Loc Upper: %f, %f", upper.latitude, upper.longitude);
NSLog(#"Loc Lower: %f, %f", lower.latitude, lower.longitude);
// FIND LIMITS
for(MKPointAnnotation *eachLocation in self.annotations) {
if([eachLocation coordinate].latitude > upper.latitude) upper.latitude = [eachLocation coordinate].latitude;
if([eachLocation coordinate].latitude < lower.latitude) lower.latitude = [eachLocation coordinate].latitude;
if([eachLocation coordinate].longitude > upper.longitude) upper.longitude = [eachLocation coordinate].longitude;
if([eachLocation coordinate].longitude < lower.longitude) lower.longitude = [eachLocation coordinate].longitude;
}
NSLog(#"Loc Upper: %f, %f", upper.latitude, upper.longitude);
NSLog(#"Loc Lower: %f, %f", lower.latitude, lower.longitude);
// FIND REGION
MKCoordinateSpan locationSpan;
locationSpan.latitudeDelta = upper.latitude - lower.latitude + 0.003;
locationSpan.longitudeDelta = upper.longitude - lower.longitude+ 0.003;
CLLocationCoordinate2D locationCenter;
locationCenter.latitude = (upper.latitude + lower.latitude) / 2;
locationCenter.longitude = (upper.longitude + lower.longitude) / 2;
MKCoordinateRegion region = MKCoordinateRegionMake(locationCenter, locationSpan);
return region;
}
Once after installing app I get this:
and after that I get this view:
Any idea what can be wrong?
This question already has answers here:
Finding Path/Route Between two points on MapKit in iPhone
(5 answers)
Closed 9 years ago.
I am using MKMapView to show route. I want to zoom out this map so that it will show both source at destination at a time.
how can I zoom out map as per distance so that it will show whole route in one screen.
I am using this code:
double maxLatitude = annotation.coordinate.latitude;
double maxLongitude = annotation.coordinate.longitude;
double minLatitude = annotation.coordinate.latitude;
double minLongitude = annotation.coordinate.longitude;
MKCoordinateRegion region;
region.center.latitude = (minLatitude + maxLatitude) / 2;
region.center.longitude = (minLongitude + maxLongitude) / 2;
region.span.latitudeDelta = (maxLatitude - minLatitude) * MAP_PADDING;
region.span.latitudeDelta = (region.span.latitudeDelta < MINIMUM_VISIBLE_LATITUDE)
? MINIMUM_VISIBLE_LATITUDE
: region.span.latitudeDelta;
region.span.longitudeDelta = (maxLongitude - minLongitude) * MAP_PADDING;
[self.mapView addAnnotation:annotation];
[self.mapView regionThatFits:region];
You can try it by the following method
for (int i = 1; i<[arrayOfPointsToFindDistance count]; i++) {
connection_listdata *detail_connection=[arrayOfPointsToFindDistance objectAtIndex:i];
[self findDistancewithConnecionList:detail_connection];
}
findDistancewithConnecionList method is given below.
-(void)findDistancewithConnecionList:(connection_listdata *)connectionlist{
NSLog(#"sssssss");
CLLocation *oldLoc = [[CLLocation alloc] initWithLatitude:connectionlist.coordinate_connection.latitude longitude: connectionlist.coordinate_connection.longitude];
for(int i =0; i<[mapArray count];i++){
NSLog(#"ghsghshhs");
NSMutableArray *firstArrayTemp = [mapArray objectAtIndex:i];
connection_listdata *detail_connection=[firstArrayTemp objectAtIndex:0];
CLLocation *newLoc = [[CLLocation alloc] initWithLatitude:detail_connection.coordinate_connection.latitude longitude: detail_connection.coordinate_connection.longitude];
CLLocationDistance d = [newLoc distanceFromLocation:oldLoc];
NSLog(#"distanceeeee:%f",d);
if(d <= 500){
NSLog(#"foundddd");
NSLog(#"maparray values= %#",mapArray);
[firstArrayTemp addObject:connectionlist];
[mapArray addObject:firstArrayTemp];
return;
}
[newLoc release];
}
NSMutableArray *array = [[NSMutableArray alloc]init];
[array addObject:connectionlist];
[mapArray addObject:array];
[array release];
[oldLoc release];
return;
}
When i drop multiple pins in map depends on different latitude and longitude values. im getting all pins are at one place in map.
I wrote this code for dropping multiple pins .
dealerMapView.mapType = MKMapTypeStandard;
dealerMapView.zoomEnabled =YES;
[dealerMapView setDelegate:nil];
dealerMapView.scrollEnabled = YES;
dealerMapView.showsUserLocation = NO;
CLLocationCoordinate2D location;
for (int i =0; i<[delarsInfoArray count]; i++) {
NSString *lattitudeValue = [[delarsInfoArray objectAtIndex:i]objectForKey:#"LATITUDE" ];
NSString *longitudeValue = [[delarsInfoArray objectAtIndex:i]objectForKey:#"LONGITUDE" ];
CLLocationCoordinate2D pCoordinate ;
pCoordinate.latitude = [lattitudeValue floatValue];
pCoordinate.longitude = [longitudeValue floatValue];
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.005;
span.longitudeDelta = 0.005;
region.span = span;
region.center = location;
[dealerMapView setRegion:region animated:YES];
myAnnotation1 = [[MyAnnotation alloc] init];
myAnnotation1.coordinate = location;
myAnnotation1.title = [[delarsInfoArray objectAtIndex:i]objectForKey:#"STORE"];
[dealerMapView addAnnotation:myAnnotation1];
}
Try this code:
MKCoordinateSpan span;
span.latitudeDelta = 0.2;
span.longitudeDelta= 0.2;
if( [delarsInfoArray count] > 0 ){
CLLocationCoordinate2D start;
NSString *lattitudeValue = [[delarsInfoArray objectAtIndex:0]objectForKey:#"LATITUDE" ];
NSString *longitudeValue = [[delarsInfoArray objectAtIndex:j]objectForKey:#"LONGITUDE" ];
// create region, consisting of span and location
MKCoordinateRegion mapRegion;
mapRegion.span = span;
mapRegion.center = start;
//Move the map to our location //
[dealerMapView setRegion:mapRegion animated:YES];
}
// do not show pins and annotations more then 200 in the map at a time.
for (int j = 0; j< ([delarsInfoArray count] < 200?[delarsInfoArray count]:200); j++) {
NSString *lattitudeValue = [[delarsInfoArray objectAtIndex:i]objectForKey:#"LATITUDE"];
NSString *longitudeValue = [[delarsInfoArray objectAtIndex:i]objectForKey:#"LONGITUDE" ];
CLLocationCoordinate2D pinLocation;
if(([lattitudeValue floatValue] != 0) && ([longitudeValue floatValue] != 0) ) {
pinLocation.latitude = [lattitudeValue floatValue];
pinLocation.longitude = [longitudeValue floatValue];
if(pinLocation.latitude !=0 && pinLocation.longitude !=0) {
myAnnotation1 = [[MyAnnotation alloc] init];
myAnnotation1.coordinate = location;
myAnnotation1.title = [[delarsInfoArray objectAtIndex:i] objectForKey: #"STORE"];
[dealerMapView addAnnotation:myAnnotation1];
}
}
}
I hope it helps you!! Best Luck. Cheers!!
i have the following code...
DistanceInformation *distanceInformation=[[DistanceInformation alloc]init];
NSArray *latLongArray=[distanceInformation calculateDistance];
[distanceInformation release];
NSLog(#"lat l %#",latLongArray);
NSUInteger length,count;
length = [[latLongArray objectAtIndex:0] count];
//Calcualte center of the map based on current location and airport location
CLLocationCoordinate2D centerOfMap;
centerOfMap.latitude = (27.1766700 + 28.6361600)/2;
centerOfMap.longitude = (78.0080700 + 78.0526500)/2;
//Set map span according to the distance between airport and user location
CGFloat zoomingLevel;
//set the zoom level of the map according to the distance to airport
if([[latLongArray objectAtIndex:2] intValue] <= 50)
zoomingLevel = 0.2;
else if(([[latLongArray objectAtIndex:2] intValue] > 50)&&([[latLongArray objectAtIndex:2] intValue] <= 100))
zoomingLevel = 0.6;
else if(([[latLongArray objectAtIndex:2] intValue]> 100)&&([[latLongArray objectAtIndex:2] intValue] <= 500))
zoomingLevel = 1.7;
else if(([[latLongArray objectAtIndex:2] intValue] > 500)&&([[latLongArray objectAtIndex:2] intValue] <= 1000))
zoomingLevel = 2.0;
else
zoomingLevel = 2.5;
NSLog(#"Center of map: %f, %f",centerOfMap.latitude, centerOfMap.longitude);
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta=zoomingLevel;
span.longitudeDelta=zoomingLevel;
region.span = span;
region.center = centerOfMap;
[mapView setRegion:region animated:TRUE];
[mapView regionThatFits:region];
CLLocationCoordinate2D coords[length];
for (count = 0; count<length; count++) {
NSLog(#"coo ");
coords[count] = CLLocationCoordinate2DMake([[[latLongArray objectAtIndex:0] objectAtIndex:count] doubleValue], [[[latLongArray objectAtIndex:1] objectAtIndex:count] doubleValue]);
}
//Display polyline containing route points as an overlay over the mapview
MKPolyline *polyLine=[MKPolyline polylineWithCoordinates:coords count:length];
NSLog(#"polyLine.pointCount %d",polyLine.pointCount) ;
[mapView addOverlay:polyLine];
[polyLine release];
but the polyline is not visible on map. The polyline is getting initialized with values that I have checked..
Noob mistake on my side... Forgot to implement the MKMapViewDelegate method..
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id < MKOverlay >)overlay{
}