I'm trying to draw route on my map using Google Maps SDK.
This is the URL that i'm calling and I parse the JSON response to array of coordinates:
id jsonResponse = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
int points_count = 0;
points_count = [[[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
NSArray *steps = nil;
if (points_count && [[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
{
steps = [[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
}
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:points_count];
for (int i = 0; i < points_count; i++)
{
NSDictionary *start;
NSDictionary *finish;
double st_lat = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lat"] doubleValue];
double st_lon = [[[[steps objectAtIndex:i] objectForKey:#"start_location"] valueForKey:#"lng"] doubleValue];
if (st_lat > 0.0f && st_lon > 0.0f)
{
start = #{ #"latitude" : [NSNumber numberWithDouble:st_lat], #"longitude" : [NSNumber numberWithDouble:st_lon] };
}
double end_lat = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lat"] doubleValue];
double end_lon = [[[[steps objectAtIndex:i] objectForKey:#"end_location"] valueForKey:#"lng"] doubleValue];
if (end_lat > 0.0f && end_lon > 0.0f)
{
finish = #{ #"latitude" : [NSNumber numberWithDouble:end_lat], #"longitude" : [NSNumber numberWithDouble:end_lon] };
}
[coordinates addObject:#{ #"start" : start, #"finish" : finish }];
}
And than drawing on the map view with this method:
GMSMutablePath *path = [GMSMutablePath path];
for (NSDictionary *d in directions)
{
NSDictionary *start = d[#"start"];
NSDictionary *finish = d[#"finish"];
CLLocationCoordinate2D c_start = CLLocationCoordinate2DMake([start[#"latitude"] doubleValue], [start[#"longitude"] doubleValue]);
CLLocationCoordinate2D c_finish = CLLocationCoordinate2DMake([finish[#"latitude"] doubleValue], [finish[#"longitude"] doubleValue]);
[path addCoordinate:c_start];
[path addCoordinate:c_finish];
}
GMSPolyline *line = [GMSPolyline polylineWithPath:path];
line.strokeColor = [UIColor redColor];
line.strokeWidth = 2.0f;
line.map = self.mapView;
Why it is drawing like that and not going into the street it self?
What am I doing wrong here?
Try this it draws exact path like in driving mode - StreetMode, Here's my code :
iOS GSMPolyLine
So the problem was that I used the start_location and end_location instead of the polyline -> points. Fixed my code into this:
Request URL for example: https://maps.googleapis.com/maps/api/directions/json?origin=40.716072,-74.008836&destination=40.697545,-73.983892&sensor=false&waypoints=optimize:true&mode=driving
id jsonResponse = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
int points_count = 0;
points_count = [[[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] count];
NSArray *steps = nil;
if (points_count && [[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] count])
{
steps = [[[[[jsonResponse objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
}
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:points_count];
for (int i = 0; i < points_count; i++)
{
NSString *toDecode = [[[steps objectAtIndex:i] objectForKey:#"polyline"] valueForKey:#"points"];
NSArray *locations = [AppUtils decodePolylineWithString:toDecode];
for (int i = 0 ; i < locations.count ; i++)
{
if (i != locations.count - 1) {
CLLocation *start = [locations objectAtIndex:i];
CLLocation *finish = [locations objectAtIndex:i + 1];
[coordinates addObject:#{ #"start" : start, #"finish" : finish }];
}
}
}
GMSMutablePath *path = [GMSMutablePath path];
for (NSDictionary *d in directions)
{
CLLocation *start = d[#"start"];
CLLocation *finish = d[#"finish"];
[path addCoordinate:start.coordinate];
[path addCoordinate:finish.coordinate];
}
GMSPolyline *line = [GMSPolyline polylineWithPath:path];
line.strokeColor = [UIColor redColor];
line.strokeWidth = 2.0f;
line.map = self.mapView;
+ (NSArray*)decodePolylineWithString:(NSString *)encodedString
{
NSMutableArray *coordinates = [NSMutableArray array];
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;
CLLocation *location = [[CLLocation alloc] initWithLatitude:finalLat longitude:finalLon];
[coordinates addObject:location];
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
free(coords);
return coordinates;
}
I know it's a little bit dirty, but that's work and it works great.
Enjoy.
Related
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.
I have create a PolyLine in MapView. I tried to many times but did not draw. Ones a draw polyLine but that case run only simulator, I run in device and crash my app. and I already post my question here
I tried to many times and using lots of tutorials, please suggest any other tutorial.
I want to create a PolyLine in MapView using google direction URL. Starting point is my device location and end point is any lat long. so both points in centre draw a polyLine. That means create a root map starting point to end point draw a PolyLine.
Please help, Thank you
you can use google api for this
http://maps.googleapis.com/maps/api/directions/json?origin
in this api you have to pass lat log of your locations like this methode
-(NSArray*) calculateRoutes
{
NSString *baseUrl = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true",currentlatitude,currentlongitude,destination lat,destination log];
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:baseUrl]];
if (data) {
NSDictionary *direction_dictionary=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (direction_dictionary) {
if ([[direction_dictionary valueForKey:#"status"] isEqualToString:#"OK"]) {
NSArray *routes_array=[direction_dictionary valueForKey:#"routes"];
if (routes_array) {
NSString *poinstEncoded_String=[[[routes_array firstObject] valueForKey:#"overview_polyline"] valueForKey:#"points"];
routes = [self decodePolyLine:[poinstEncoded_String mutableCopy]];
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
dispatch_async(dispatch_get_main_queue(), ^{
[self.MapVw addOverlay:polyLine];
// add polyline here to your mapview
});
}
}
}
}
}
-(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];
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
After getting response (Full example http://way2ios.com/development/ios-development-2/iphone-2/draw-polygon-mkmapview-stylus/):
– (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
{
MKPolygonView *polygonView = [[MKPolygonView alloc] initWithPolygon:overlay];
polygonView.lineWidth = 5;
polygonView.strokeColor = [UIColor redColor];
polygonView.fillColor = [UIColor colorWithRed:0 green:191 blue:255 alpha:0.5];
mapView.userInteractionEnabled = YES;
return polygonView;
}
Check these also :
https://github.com/kadirpekel/MapWithRoutes and https://github.com/versluis/MapViewLines
i want to draw polyline using googleMap Api on MKMapView.
i am doing this way. Here is Code for it.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
NSString *urlString =#"https://maps.googleapis.com/maps/api/directions/json";
NSString *origin = #"23.0061,72.5647";
NSString *dstinatin = #"23.03293,72.6284";
MKPointAnnotation *annotationEnd = [[MKPointAnnotation alloc] init];
[annotationEnd setCoordinate:CLLocationCoordinate2DMake(23.0293, 72.6284)];
[annotationEnd setTitle:#"Ending"]; //You can set the subtitle too
[self.mkMapView addAnnotation:annotationEnd];
NSDictionary *dictParameters = #{#"origin" : [NSString stringWithFormat:#"%#",origin], #"destination" : [NSString stringWithFormat:#"%#",dstinatin], #"mode" : #"driving", #"sensor" : #"true"};
[manager GET:urlString parameters:dictParameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *routesArray = [responseObject objectForKey:#"routes"];
if ([routesArray count] > 0)
{
NSDictionary *routeDict = [routesArray objectAtIndex:0];
NSDictionary *routeOverviewPolyline = [routeDict objectForKey:#"overview_polyline"];
NSString *points = [routeOverviewPolyline objectForKey:#"points"];
MKPolyline *line = [self polylineWithEncodedString:points];
[mkMapView addOverlay:line];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
my decoding method is :
-(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;
}
i think my coding is ok but i am not getting proper polyline. i am getting it as seen in screen shot. polyline's last end should be on my MKPointAnnotation. Sorry for my english. please help me.
The destination of the route:
23.03293,72.6284
//____^
isn't equal to the marker-position:
23.0293,72.6284
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;
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! :)