How to get directions between two addresses in iOS - ios

I'm using this code to try get directions between two locations. But it outputs co-ordinates using latitude and longitude. But what I want is to get directions for searching based on 2 addresses. How can I get this code to work with addresses?
MKPlacemark *source = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(37.776142, -122.424774) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:source];
[srcMapItem setName:#""];
MKPlacemark *destination = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(37.73787, -122.373962) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
MKMapItem *distMapItem = [[MKMapItem alloc]initWithPlacemark:destination];
[distMapItem setName:#""];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:srcMapItem];
[request setDestination:distMapItem];
[request setTransportType:MKDirectionsTransportTypeAny];
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
NSLog(#"response = %#",response);
NSArray *arrRoutes = [response routes];
[arrRoutes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
MKRoute *rout = obj;
MKPolyline *line = [rout polyline];
[mapview addOverlay:line];
NSLog(#"Rout Name : %#",rout.name);
NSLog(#"Total Distance (in Meters) :%f",rout.distance);
NSArray *steps = [rout steps];
NSLog(#"Total Steps : %lu",(unsigned long)[steps count]);
NSMutableArray *stepsArray=[[NSMutableArray alloc] init];
[steps enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Rout Instruction : %#",[obj instructions]);
NSLog(#"Rout Distance : %f",[obj distance]);
[stepsArray addObject:[obj instructions]];
}];
[self myShowDirections:response];
self.steps.text=[NSString stringWithFormat:#"%#",stepsArray];

First you need to check ios8 in your view didload
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
// self.map.showsUserLocation=YES;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager setDistanceFilter:kCLDistanceFilterNone];
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){
NSUInteger code = [CLLocationManager authorizationStatus];
if (code == kCLAuthorizationStatusNotDetermined && ([locationManager respondsToSelector:#selector(requestAlwaysAuthorization)] || [locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])) {
// choose one request according to your business.
if([[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSLocationAlwaysUsageDescription"]){
[locationManager requestAlwaysAuthorization];
} else if([[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSLocationWhenInUseUsageDescription"]) {
[locationManager requestWhenInUseAuthorization];
} else {
NSLog(#"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
}
}
-(void) centerMapForCoordinateArray:(CLLocationCoordinate2D *)routes andCount:(int)count{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx <count; idx++)
{
CLLocationCoordinate2D currentLocations = routes[idx];
if(currentLocations.latitude > maxLat)
maxLat = currentLocations.latitude;
if(currentLocations.latitude < minLat)
minLat = currentLocations.latitude;
if(currentLocations.longitude > maxLon)
maxLon = currentLocations.longitude;
if(currentLocations.longitude < minLon)
minLon = currentLocations.longitude;
}
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
[self.map setRegion:region animated:YES];
}
- (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
- (void)getDirections {
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:currentLocation.coordinate.latitude longitude:currentLocation.coordinate.longitude];
MKPointAnnotation *provider = [[MKPointAnnotation alloc] init];
provider.coordinate = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
provider.title = [self getAddress];
[self.map addAnnotation:provider];
// 13.069166 80.191388
CLLocationCoordinate2D location;
// location.latitude =12.982672000000000000; // change to your coordinate latitude
// location.longitude =80.263380999999980000;
location.latitude =[self.Latitude doubleValue]; // change to your coordinate latitude
location.longitude =[self.Longtitude doubleValue];
CLLocation *keyPlace = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
MKPointAnnotation *user = [[MKPointAnnotation alloc] init];
user.coordinate = CLLocationCoordinate2DMake(keyPlace.coordinate.latitude, keyPlace.coordinate.longitude);
NSString *add=[NSString stringWithFormat:#"%f %f",location.latitude,location.longitude];
NSString *tit=[self getAddressFromLatLong:add];
user.title=tit;
[self.map addAnnotation:user];
CLLocationCoordinate2D endCoordinate;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=false&mode=driving", newLocation.coordinate.latitude, newLocation.coordinate.longitude, keyPlace.coordinate.latitude, keyPlace.coordinate.longitude]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&error];
if ([[responseDict valueForKey:#"status"] isEqualToString:#"ZERO_RESULTS"]) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not route path from your current location"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil, nil] show];
return;
}
int points_count = 0;
if ([[responseDict objectForKey:#"routes"] count])
points_count = (int)[[[[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
if (!points_count) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not route path from your current location"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil, nil] show];
return;
}
CLLocationCoordinate2D points[points_count];
NSLog(#"routes %#", [[[[responseDict objectForKey:#"routes"] objectAtIndex:0]objectForKey:#"overview_polyline"] objectForKey:#"points"]
);
MKPolyline *polyline = [self polylineWithEncodedString:[[[[responseDict objectForKey:#"routes"] objectAtIndex:0]objectForKey:#"overview_polyline"] objectForKey:#"points"]];
[self.map addOverlay:polyline];
int j = 0;
NSArray *steps = nil;
if (points_count && [[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
steps = [[[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i = 0; i < points_count; i++) {
double st_lat = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lat"] doubleValue];
double st_lon = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lng"] doubleValue];
//NSLog(#"lat lon: %f %f", st_lat, st_lon);
if (st_lat > 0.0f && st_lon > 0.0f) {
points[j] = CLLocationCoordinate2DMake(st_lat, st_lon);
j++;
}
double end_lat = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lat"] doubleValue];
double end_lon = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lng"] doubleValue];
//NSLog(#"lat %f lng %f",end_lat,end_lon);
//if (end_lat > 0.0f && end_lon > 0.0f) {
points[j] = CLLocationCoordinate2DMake(end_lat, end_lon);
endCoordinate = CLLocationCoordinate2DMake(end_lat, end_lon);
j++;
//}
}
NSLog(#"points Count %d",points_count);
// MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:points_count];
// [self.mapView addOverlay:polyline];
[self centerMapForCoordinateArray:points andCount:points_count];
}
}
- (MKPolylineRenderer *)mapView:(MKMapView *)mapView
viewForOverlay:(id<MKOverlay>)overlay {
MKPolylineRenderer *polylineView = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
polylineView.lineWidth = 3;
polylineView.strokeColor = [[UIColor alloc] initWithRed:5.0/255 green:102.0/255 blue:48.0/255 alpha:1];
return polylineView;
}
EDIT:
-(void)showRoute:(MKDirectionsResponse *)response
{
for (MKRoute *route in response.routes){
[mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
}
-(void)getPathDirections:(CLLocationCoordinate2D)source withDestination:(CLLocationCoordinate2D)destination{
MKPlacemark *placemarkSrc = [[MKPlacemark alloc] initWithCoordinate:source addressDictionary:nil];
MKMapItem *mapItemSrc = [[MKMapItem alloc] initWithPlacemark:placemarkSrc];
MKPlacemark *placemarkDest = [[MKPlacemark alloc] initWithCoordinate:destination addressDictionary:nil];
MKMapItem *mapItemDest = [[MKMapItem alloc] initWithPlacemark:placemarkDest];
[mapItemSrc setName:#"name1"];
[mapItemDest setName:#"name2"];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
[request setSource:mapItemSrc];
[request setDestination:mapItemDest];
[request setTransportType:MKDirectionsTransportTypeAutomobile];
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
// UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"ShareMyTable" message:#"Root Map not available to your location." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
// [alert show];
} else {
[mapView removeOverlays:mapView.overlays];
[self showRoute:response];
}
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
// 41,142,175
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = (MKPolyline *)overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.strokeColor = [UIColor colorWithRed:(41/255.0) green:(142/255.0) blue:(175/255.0) alpha:0.6f];
routeRenderer.lineWidth = 2.5;
return routeRenderer;
}
else return nil;
}
you can read about supported country list
link

When you find any rout between two places,than always use different source and destination place.
In your code you use same latitude and longitude so MKDirections have no Rout to make direction.
So in Your code use different Lat. and Long.
Like...
KPlacemark *source = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(37.776142, -122.424774) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:source];
[srcMapItem setName:#""];
MKPlacemark *destination=[[MKPlacemarkalloc]initWithCoordinate:CLLocationCoordinate2DMake(40.73787, -142.373962) addressDictionary:[NSDictionary dictionaryWithObjectsAndKeys:#"",#"", nil] ];
After use this Latitude and Longitude you can draw your rout any two places.
I hope my answer is helpful for you.

Related

My project run only in simulator but do not work in device, why?

I create a polyline in map. and successfully create polyline in map view.
My problem is, This code run only simulator. do not work on device. I tried to many times but do not work on device.
Genrate the IPA and install in my device and crash my app. why? and simply run in simulator, why?
I follow this link
Why is this happining? please help
Thankyou
my code
-(void) centerMapForCoordinateArray:(CLLocationCoordinate2D *)routes andCount:(int)count{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx <count; idx++)
{
CLLocationCoordinate2D currentLocation = routes[idx];
if(currentLocation.latitude > maxLat)
maxLat = currentLocation.latitude;
if(currentLocation.latitude < minLat)
minLat = currentLocation.latitude;
if(currentLocation.longitude > maxLon)
maxLon = currentLocation.longitude;
if(currentLocation.longitude < minLon)
minLon = currentLocation.longitude;
}
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
[self.mapView setRegion:region animated:YES];
}
- (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
- (void)getDirections {
//Cross country
//37.705553,-122.372074 to 25.883937,-80.223026
//Home to work
//37.7577,-122.4376 to 37.764473,-122.399639
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:22.7001469 longitude:75.8758194];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
annotation.title = #"You";
[self.mapView addAnnotation:annotation];
CLLocation *keyPlace = [[CLLocation alloc] initWithLatitude:22.6924483 longitude:75.8653895];
MKPointAnnotation *endannotation = [[MKPointAnnotation alloc] init];
endannotation.coordinate = CLLocationCoordinate2DMake(keyPlace.coordinate.latitude, keyPlace.coordinate.longitude);
endannotation.title = #"School";
[self.mapView addAnnotation:endannotation];
CLLocationCoordinate2D endCoordinate;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=false&mode=driving", newLocation.coordinate.latitude, newLocation.coordinate.longitude, keyPlace.coordinate.latitude, keyPlace.coordinate.longitude]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&error];
NSLog(#"response == %#",responseDict);
if ([[responseDict valueForKey:#"status"] isEqualToString:#"ZERO_RESULTS"]) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not route path from your current location"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil, nil] show];
return;
}
int points_count = 0;
if ([[responseDict objectForKey:#"routes"] count])
points_count = [[[[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
if (!points_count) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not route path from your current location"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil, nil] show];
return;
}
CLLocationCoordinate2D points[points_count];
NSLog(#"routes %#", [[[[responseDict objectForKey:#"routes"] objectAtIndex:0]objectForKey:#"overview_polyline"] objectForKey:#"points"]
);
MKPolyline *polyline = [self polylineWithEncodedString:[[[[responseDict objectForKey:#"routes"] objectAtIndex:0]objectForKey:#"overview_polyline"] objectForKey:#"points"]];
[self.mapView addOverlay:polyline];
int j = 0;
NSArray *steps = nil;
if (points_count && [[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
steps = [[[[[responseDict objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i = 0; i < points_count; i++) {
double st_lat = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lat"] doubleValue];
double st_lon = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lng"] doubleValue];
//NSLog(#"lat lon: %f %f", st_lat, st_lon);
if (st_lat > 0.0f && st_lon > 0.0f) {
points[j] = CLLocationCoordinate2DMake(st_lat, st_lon);
j++;
}
double end_lat = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lat"] doubleValue];
double end_lon = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lng"] doubleValue];
//NSLog(#"lat %f lng %f",end_lat,end_lon);
//if (end_lat > 0.0f && end_lon > 0.0f) {
points[j] = CLLocationCoordinate2DMake(end_lat, end_lon);
endCoordinate = CLLocationCoordinate2DMake(end_lat, end_lon);
j++;
//}
}
NSLog(#"points Count %d",points_count);
// MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:points_count];
// [self.mapView addOverlay:polyline];
[self centerMapForCoordinateArray:points andCount:points_count];
}
}
#pragma mark - MapKit
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *annView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"currentloc"];
annView.canShowCallout = YES;
annView.animatesDrop = YES;
return annView;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView
viewForOverlay:(id<MKOverlay>)overlay {
MKPolylineView *overlayView = [[MKPolylineView alloc] initWithOverlay:overlay];
overlayView.lineWidth = 5;
overlayView.strokeColor = [UIColor purpleColor];
overlayView.fillColor = [[UIColor purpleColor] colorWithAlphaComponent:0.5f];
return overlayView;
}
I go through your code and run in simulator, it will show warning CFNetwork SSLHandshake failed (-9824) NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824), so i think you miss the NSAppTransportSecurity key in your plist.
Problem seems with certificate try by setting development certificates and check provisioning profile.
Set the proper certificates and provisioning profile in build setting/target then check.
More detail read:
https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppStoreDistributionTutorial/LaunchingYourApponDevices/LaunchingYourApponDevices.html
Try to Run in iphone4s or 5 Simulator, if it crash in simulator than change
points[j] = CLLocationCoordinate2DMake(end_lat, end_lon);
endCoordinate = CLLocationCoordinate2DMake(end_lat, end_lon);
j++;
With
if (j<=points_count) {
points[j] = CLLocationCoordinate2DMake(end_lat, end_lon);
endCoordinate = CLLocationCoordinate2DMake(end_lat, end_lon);
j++;
}
Why? Because
we declare CLLocationCoordinate2D points[points_count];
So max Coordinate2D is points_count
but some latitude longitude j value is higher than the points_count so we have to put if condition for j
Check it and let me know it it solve your problem or not.

Application get crashed when create long distance path on Google Map

I am working on an application where i want path between two locations.
I implemented some code. This is fine for short distance path but when i creating path for long distance like From Jaipur, Rajasthan, India to Jorhat, Aasam, India, my application get crashed.
This is my code
-(void)findPath{
[rectangle setMap:nil];
NSString* str = [NSMutableString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=true", self.FromSearch, self.toSearch];
if (_travelMode==UICGTravelModeWalking) {
str=[str stringByAppendingFormat:#"&mode=walking"];
}
NSURL *url=[[NSURL alloc]initWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSArray* latestRoutes = [json objectForKey:#"routes"];
NSString *points=[[[latestRoutes objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
if ([latestRoutes isKindOfClass:[NSArray class]]&&latestRoutes.count==0) {
UIAlertView *alrt=[[UIAlertView alloc]initWithTitle:#"Alert" message:#"didn't find direction" delegate:nil cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alrt show];
return;
}
arrDistance =[[[json valueForKeyPath:#"routes.legs.steps.distance.text"] objectAtIndex:0]objectAtIndex:0];
totalDuration = [[[json valueForKeyPath:#"routes.legs.duration.text"] objectAtIndex:0]objectAtIndex:0];
totalDistance = [[[json valueForKeyPath:#"routes.legs.distance.text"] objectAtIndex:0]objectAtIndex:0];
arrDescription =[[[json valueForKeyPath:#"routes.legs.steps.html_instructions"] objectAtIndex:0] objectAtIndex:0];
dictRouteInfo=[NSDictionary dictionaryWithObjectsAndKeys:totalDistance,#"totalDistance",totalDuration,#"totalDuration",arrDistance ,#"distance",arrDescription,#"description", nil];
double srcLat=[[[[json valueForKeyPath:#"routes.legs.start_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
double srcLong=[[[[json valueForKeyPath:#"routes.legs.start_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
totalLat = [[NSMutableArray alloc]init];
totalLong = [[NSMutableArray alloc]init];
//for (int i = 0; i<arrDistance.count; i++) {
totalLat = [[[json valueForKeyPath:#"routes.legs.steps.start_location.lat"] objectAtIndex:0] objectAtIndex:0];
totalLong = [[[json valueForKeyPath:#"routes.legs.steps.start_location.lng"] objectAtIndex:0] objectAtIndex:0];
[self saveInfoForPath];
// }
CLLocationCoordinate2D location;
location.latitude = srcLat;
location.longitude = srcLong;
// mapView.camera = [GMSCameraPosition cameraWithTarget:location
// zoom:10];
//GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc]initWithPath:<#(GMSPath *)#>]
// [[GMSCoordinateBounds alloc] initWithCoordinate:vancouver coordinate:calgary];
#try {
// TODO: better parsing. Regular expression?
NSArray *temp= [self decodePolyLine:[points mutableCopy]];
GMSMutablePath *path = [GMSMutablePath path];
for(int idx = 0; idx < [temp count]; idx++)
{
CLLocation *location=[temp objectAtIndex:idx];
[path addCoordinate:location.coordinate];
}
// create the polyline based on the array of points.
rectangle = [GMSPolyline polylineWithPath:path];
rectangle.strokeWidth=5.0;
rectangle.map = mapView;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc]initWithPath:path];
[mapView moveCamera:[GMSCameraUpdate fitBounds:bounds]];
}
#catch (NSException * e) {
// TODO: show error
}
}
decodePolyline() method coding
-(NSMutableArray *)decodePolyLine: (NSMutableString *)encoded {
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init] ;
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5] ;
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5] ;
printf("[%f,", [latitude doubleValue]);
printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]] ;
[array addObject:loc];
}
return array;
}
What should i do. Please suggest.
You can try pathFromEncodedPath method in place of decodePolyLine for getting path from encodeString.
NSString *points=[[[latestRoutes objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
polyline = [GMSPolyline polylineWithPath: [GMSPath pathFromEncodedPath: points]];
polyline.map = mapView;
polyline.strokeColor = [UIColor colorWithRed:0/255.0 green:4/255.0 blue:255/255.0 alpha:1.0];
polyline.strokeWidth = 4.0f;

Do not add annotations repeated

I am inserting some annotations that are coming from a json server, but I wanted to check if the annotation is already on the map, if so, does not add it again. For they are being added on each other , have someone help me solve this problem?
my code:
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
[annotationsPins addObject:myAnn];
}
[self.mapView addAnnotations:annotationsPins];
}
You can iterate through annotations already on MkMapView and see if they are already there:
NSArray * annotations = [self.mapView.annotations copy];
for (NSDictionary *annotationDeProdutos in objetos)
{
// Check if annotation in annotations are duplicate of annotationDeProdutos.
// You can match using name.
}
Or the other way if you only want to show annotations from single server call:
[self.mapView removeAnnotations: self.mapView.annotations];
// Now add from JSON response.
You can do this for each of your annotations:
if(![self.mapView.annotations containsObject: myAnn]) {
[self.mapView addAnnotations: myAnn];
}
I solved the problem with this code :
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
if (self.mapView.annotations.count <1) {
[annotationsPins addObject:myAnn];
} else {
__block NSInteger foundIndex = NSNotFound;
[annotationsPins enumerateObjectsUsingBlock:^(AnnotationMap *annotation, NSUInteger idx, BOOL *stop) {
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
if ([loc1 distanceFromLocation:loc2] <= 1.0f) {
foundIndex = idx;
*stop = YES;
}
}];
if (foundIndex != NSNotFound) {
[annotationsPins addObject:myAnn];
}
}
}
[self.mapView addAnnotations:annotationsPins];
}

Draw route directions using Google Maps iOS

I am getting a GMSPolyline to custom location but I am not getting a route direction (GMSPolyline) from user location to some custom location.
What I have done is placed a GMSMapView and kept core location. I am updating the route in core location delegate method (locationManager: didUpdateLocations:).
I want to use Google Maps for iOS SDK since Apple Maps don't have directions in the country I need. My code is below:
- (void)viewDidLoad
{
[super viewDidLoad];
waypointStrings_ = [[NSMutableArray alloc]init];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:self.latitude longitude:self.longitude zoom:13];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
mapView_.myLocationEnabled = YES;
self.view = mapView_;
CLLocationManager *locManager = [[CLLocationManager alloc] init];
if ( [CLLocationManager locationServicesEnabled] ) {
[locManager setDelegate:self];
[locManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocationCoordinate2D userCoordinate = [[locations lastObject] coordinate];
GMSMarker *marker = [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(self.latitude,self.longitude)];
marker.map = mapView_;
NSString *majlisPositionString = [[NSString alloc] initWithFormat:#"%f,%f", self.latitude,self.longitude];
[waypointStrings_ addObject:majlisPositionString];
GMSMarker *userMarker = [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(userCoordinate.latitude, userCoordinate.longitude)];
userMarker.map = mapView_;
NSString *userPositionString = [[NSString alloc] initWithFormat:#"%f,%f", userCoordinate.latitude, userCoordinate.longitude];
[waypointStrings_ addObject:userPositionString];
NSString *sensor = #"false";
NSArray *parameters = [NSArray arrayWithObjects:sensor, waypointStrings_, nil];
NSArray *keys = [NSArray arrayWithObjects:#"sensor", #"waypoints", nil];
NSDictionary *query = [NSDictionary dictionaryWithObjects:parameters forKeys:keys];
MDDirectionService *mds=[[MDDirectionService alloc] init];
SEL selector = #selector(addDirections:);
[mds setDirectionsQuery:query withSelector:selector withDelegate:self];
}
- (void)addDirections:(NSDictionary *)json {
NSDictionary *routes = [json objectForKey:#"routes"][0];
NSDictionary *route = [routes objectForKey:#"overview_polyline"];
NSString *overview_route = [route objectForKey:#"points"];
GMSPath *path = [GMSPath pathFromEncodedPath:overview_route];
GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
polyline.map = mapView_;
}
-(void)LoadMapRoute:(NSString*)SourceAddress andDestinationAddress:(NSString*)DestinationAdds
{
NSString *strUrl;
strUrl= [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false",SourceAddress,DestinationAdds];
strUrl=[strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *data =[NSData dataWithContentsOfURL:[NSURL URLWithString:strUrl]];
NSError* error;
if (data) {
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data //1
options:kNilOptions
error:&error];
NSArray *arrRouts=[json objectForKey:#"routes"];
if ([arrRouts isKindOfClass:[NSArray class]]&&arrRouts.count==0) {
[self zoomToFitMapAnnotations:self.mapView];
return;
}
CLLocationCoordinate2D coordinates[2];
coordinates[0].latitude = [[CommonUtils checkNullString:[AppDelegate getAppDelegate].strLatitude] doubleValue];Current loaction latitude.
coordinates[0].longitude = [[CommonUtils checkNullString:[AppDelegate getAppDelegate].strLongitude] doubleValue];//Current loaction longitude.
coordinates[1].latitude = [[CommonUtils checkNullString:latitute] doubleValue];
coordinates[1].longitude = [[CommonUtils checkNullString:longitude] doubleValue];
if (CLLocationCoordinate2DIsValid(coordinates[1]) && CLLocationCoordinate2DIsValid(coordinates[0]))
{
//NSLog(#"Coordinate valid");
self.mapView.delegate=self;
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:coordinates[0].latitude longitude:coordinates[0].longitude];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:coordinates[1].latitude longitude:coordinates[1].longitude];
CLLocationDistance kilometers = [location1 distanceFromLocation:location2] / 1000;
//NSLog(#"%f",kilometers);
self.lblRideViewkilometer.text=[NSString stringWithFormat:#"%f KM",kilometers];
// //NSLog(#"Distance i meters: %f", [location1 distanceFromLocation:location2]);
// self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:2];
// [self.mapView setVisibleMapRect:[self.polyline boundingMapRect]];
//
//
// //If you want the route to be visible
// [self.mapView addOverlay:self.polyline];
} else {
//NSLog(#"Coordinate invalid");
}
NSArray* arrpolyline = [[[json valueForKeyPath:#"routes.legs.steps.polyline.points"] objectAtIndex:0] objectAtIndex:0]; //2
double srcLat=[[[[json valueForKeyPath:#"routes.legs.start_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
double srcLong=[[[[json valueForKeyPath:#"routes.legs.start_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
double destLat=[[[[json valueForKeyPath:#"routes.legs.end_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
double destLong=[[[[json valueForKeyPath:#"routes.legs.end_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
CLLocationCoordinate2D sourceCordinate = CLLocationCoordinate2DMake(srcLat, srcLong);
CLLocationCoordinate2D destCordinate = CLLocationCoordinate2DMake(destLat, destLong);
[self addAnnotationSrcAndDestination:sourceCordinate :destCordinate andAdds:nil andDestinationAddress:DestinationAdds];
// NSArray *steps=[[aary objectAtIndex:0]valueForKey:#"steps"];
// replace lines with this may work
polyLinesArray =[[NSMutableArray alloc]initWithCapacity:0];
for (int i = 0; i < [arrpolyline count]; i++)
{
NSString* encodedPoints = [arrpolyline objectAtIndex:i] ;
MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
[polyLinesArray addObject:route];
}
self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:2];
[self.mapView setVisibleMapRect:[self.polyline boundingMapRect]];
[self.mapView addOverlays:polyLinesArray];
self.mapView.delegate = self;
[self zoomToFitMapAnnotations:self.mapView];
}else{
// [self.btnDirection setEnabled:NO];
// [self ShowAlert:#"didn't find direction"];
}
}-(void)addAnnotationSrcAndDestination :(CLLocationCoordinate2D )srcCord :(CLLocationCoordinate2D)destCord andAdds:(NSString*)SourceAddress andDestinationAddress:(NSString*)DestinationAdds
{
MKPointAnnotation *sourceAnnotation = [[MKPointAnnotation alloc]init];
destAnnotation = [[MKPointAnnotation alloc]init];
sourceAnnotation.coordinate=srcCord;
destAnnotation.coordinate=destCord;
sourceAnnotation.title=SourceAddress;
CLLocation *LocationAtual = [[CLLocation alloc] initWithLatitude:destCord.latitude longitude:destCord.longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
[geocoder reverseGeocodeLocation:LocationAtual
completionHandler:^(NSArray *placemarks, NSError *error)
{
if (error){
//NSLog(#"Geocode failed with error: %#", error);
return;
}
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//NSLog(#"placemark.ISOcountryCode %#",placemark.ISOcountryCode);
//NSLog(#"locality %#",placemark.subLocality);
//NSLog(#"postalCode %#",placemark.postalCode);
destAnnotation.title=[NSString stringWithFormat:#"%# %# ",placemark.name,placemark.locality];
// [self.mapView.userLocation setTitle:[NSString stringWithFormat:#"%# %# ",placemark.name,placemark.locality]];
}];
// destAnnotation.title=DestinationAdds;
//destAnnotation.title=[NSString stringWithFormat:#"%#,%#,%#",[self.dictRetailerInfo objectForKey:#"street_address1"],[self.dictRetailerInfo objectForKey:#"city"],[self.dictRetailerInfo objectForKey:#"country"]];
// destAnnotation.title=nil;
[self.mapView addAnnotation:sourceAnnotation];
[self.mapView addAnnotation:destAnnotation];
}
- (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
-(void)zoomToFitMapAnnotations:(MKMapView*)aMapView
{
if([aMapView.annotations count] == 0)
return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(MKPointAnnotation *annotation in self.mapView.annotations)
{
if (![[annotation class] isEqual:[MKUserLocation class]]) {
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides
region = [aMapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
mapZoom=YES;
}
//- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
//{
// MKMapRect zoomRect = MKMapRectNull;
// for (id <MKAnnotation> annotation in mv.annotations)
// {
// MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
// MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
// zoomRect = MKMapRectUnion(zoomRect, pointRect);
// }
// [mv setVisibleMapRect:zoomRect animated:YES];
//}
- (void)moveMapToLocation:(CLLocation*)tmpLocation {
CLLocationDistance visibleDistance = 1000; // 1 kilometers
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(tmpLocation.coordinate, visibleDistance, visibleDistance);
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:viewRegion];
[self.mapView setRegion:adjustedRegion animated:YES];
}
var arrayPolyline = [GMSPolyline]()
var selectedRought:String!
func LoadMapRoute1()
{
let strUrl:String = "https://maps.googleapis.com/maps/api/directions/json?sensor=false&mode=driving&alternatives=true&origin=\(self.source.latitude),\(self.source.longitude)&destination=\(self.destination.latitude),\(self.destination.longitude)"
let escapedString = strUrl.replacingOccurrences(of: " ", with: "")
let url = URL(string: escapedString)
URLSession.shared.dataTask(with: url!, completionHandler:
{
(data, response, error) in
if(error != nil)
{
print("error")
}
else
{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let arrRouts = json["routes"] as! NSArray
for polyline in self.arrayPolyline
{
polyline.map = nil;
}
self.arrayPolyline.removeAll()
let pathForRought:GMSMutablePath = GMSMutablePath()
if (arrRouts.count == 0)
{
let distance:CLLocationDistance = CLLocation.init(latitude: self.source.latitude, longitude: self.source.longitude).distance(from: CLLocation.init(latitude: self.destination.latitude, longitude: self.destination.longitude))
pathForRought.add(self.source)
pathForRought.add(self.destination)
let polyline = GMSPolyline.init(path: pathForRought)
polyline.strokeWidth = 5
polyline.strokeColor = UIColor.blue
polyline.isTappable = true
self.arrayPolyline.append(polyline)
if (distance > 8000000)
{
polyline.geodesic = false
}
else
{
polyline.geodesic = true
}
polyline.map = self.mapView;
}
else
{
for (index, element) in arrRouts.enumerated()
{
let dicData:NSDictionary = element as! NSDictionary
let routeOverviewPolyline = dicData["overview_polyline"] as! NSDictionary
let path = GMSPath.init(fromEncodedPath: routeOverviewPolyline["points"] as! String)
let polyline = GMSPolyline.init(path: path)
polyline.isTappable = true
self.arrayPolyline.append(polyline)
polyline.strokeWidth = 5
if index == 0
{
polyline.strokeColor = UIColor.blue;
}
else
{
polyline.strokeColor = UIColor.darkGray;
}
polyline.geodesic = true;
}
for po in self.arrayPolyline.reversed()
{
po.map = self.mapView;
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
{
let bounds:GMSCoordinateBounds = GMSCoordinateBounds.init(path: GMSPath.init(fromEncodedPath: self.selectedRought)!)
self.mapView.animate(with: GMSCameraUpdate.fit(bounds))
}
}
catch let error as NSError
{
print("error:\(error)")
}
}
}).resume()
}

Route drawing on Google Maps for iOS not following the street lines

I'm developing an iOS app which is using Google Directions API to draw routes on maps which are provided by Google Maps SDK. It works well on small distance although when I zoom the map camera very close I see that the route polylines are often getting out of the streets. When the distance is longer it's a real disaster and it's not following the streets curves if I zoom in. I'm getting the points from the overview-polyline which I receive from the Directions API but it seems like the polyline is not that poly as I want. On Android it works perfectly. Could it be that Google sends different directions to iOS than Android? Has some of you had the same problem as me?
EDIT:
-(int) requestDirecionsAndshowOnMap:(GMSMapView *)aMapView{
NSArray* mode=[[NSArray alloc]initWithObjects:#"transit",#"bicycling",#"walking",#"driving", nil];
NSString *depart=[[NSString alloc] initWithFormat:#""];
NSString *origin=[[NSString alloc] initWithFormat:#""];
NSString *destination=[[NSString alloc] initWithFormat:#""];
if (self.setLanguage)
self.setLanguage=[NSString stringWithFormat:#"language=%#",self.setLanguage];
else self.setLanguage=#"language=en";
if (searchModeOption==0) {
if (self.departDate==nil) {
self.departDate=[NSDate date];
}
depart=[NSString stringWithFormat:#"&departure_time=%i",(int)[self.departDate timeIntervalSince1970]];
}
if (self.origin) {
origin=[NSString stringWithFormat:#"origin=%#",self.origin];
}else if (self.originCoordinate.latitude && self.originCoordinate.longitude){
origin=[NSString stringWithFormat:#"origin=%f,%f",self.originCoordinate.latitude,self.originCoordinate.longitude];
}else{
NSLog(#"No origin setted");
return -1;
}
if (self.destination) {
destination=[NSString stringWithFormat:#"destination=%#",self.destination];
}else if (self.destinationCoordinate.latitude && self.destinationCoordinate.longitude){
destination=[NSString stringWithFormat:#"destination=%f,%f",self.destinationCoordinate.latitude,self.destinationCoordinate.longitude];
}else{
NSLog(#"No destination setted");
return -1;
}
NSString* URLforRequest=[[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?%#&%#&sensor=false&%#&alternative=false&mode=%#%#",origin,destination,self.setLanguage,[mode objectAtIndex:searchModeOption],depart] stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
// NSLog(#"%#",URLforRequest);
NSURLRequest *requests = [NSURLRequest requestWithURL:[NSURL URLWithString:URLforRequest]];
[NSURLConnection sendAsynchronousRequest:requests queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error==nil && data) {
// NSLog(#"%#",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
directions = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if (error) {
NSLog(#"%#",error);
}
NSString* status=[directions objectForKey:#"status"];
NSLog(#"Status: %#", status);
if ([status isEqualToString:#"OK"]) {
[self decodeResult];
if (aMapView)
[self showOnMap:aMapView];
}
}else NSLog(#"%#",error);
[[NSNotificationCenter defaultCenter] postNotificationName:#"Request Done" object:nil];
}];
return 0;
}
-(void) decodeResult{
self.destination=[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"end_address"];
self.distance=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"distance"] objectForKey:#"text"] doubleValue];
self.duration=[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"duration"] objectForKey:#"text"];
//Get Array of Instructions
self.instrunctions=[[NSMutableArray alloc] init];
for (int n=0; n<[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; n++) {
[self.instrunctions addObject:[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] objectAtIndex:n] objectForKey:#"html_instructions"]];
}
//Get Overview Polyline
NSString *polystring=[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
NSMutableArray* decodedpolystring=[self decodePolyLine:polystring];
int numberOfCC=[decodedpolystring count];
GMSMutablePath *path = [GMSMutablePath path];
for (int index = 0; index < numberOfCC; index++) {
CLLocation *location = [decodedpolystring objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
}
self.overviewPolilyne= [GMSPolyline polylineWithPath:path];
//Get Coordinates of origin and destination to be displayed on a map
float lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lat"] floatValue];
float lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lng"] floatValue];
CLLocationCoordinate2D tmp;
tmp.latitude=lat;
tmp.longitude=lng;
self.destinationCoordinate=tmp;
lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lat"] floatValue];
lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lng"] floatValue];
tmp.latitude=lat;
tmp.longitude=lng;
self.originCoordinate=tmp;
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
-(void)showOnMap:(GMSMapView *)aMapView{
GMSPolyline *polyline =self.overviewPolilyne;
polyline.strokeColor = [UIColor blueColor];
polyline.strokeWidth = 2.f;
//polyline.geodesic = YES;
polyline.map = aMapView; }
UPDATE:
I had to process every step's polyline, not just the overview-polyline. Now it works perfectly.
Here's the code I'm using now:
// Get polyline
GMSMutablePath *path = [GMSMutablePath path];
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
int zero=0;
NSArray *steps = [[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i=0; i<[[[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; i++) {
NSString* encodedPoints =[[[steps objectAtIndex:i]objectForKey:#"polyline"]valueForKey:#"points"];
polyLinesArray = [self decodePolyLine:encodedPoints];
NSUInteger numberOfCC=[polyLinesArray count];
for (NSUInteger index = 0; index < numberOfCC; index++) {
CLLocation *location = [polyLinesArray objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
if (index==0) {
[self.coordinates addObject:location];
}
}
}
self.overviewPolilyne = [GMSPolyline polylineWithPath:path];
What I basically did before was that I was getting and working only with the information I'm receiving in the routes while if you check the JSON file you're receiving from Google Directions API, you'll see that you receive much more information in the <legs> and the <steps>. This is the information we need to produce the proper results and the right polyline.
Good luck! :)

Resources