6

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! :)

WWJD
  • 1,104
  • 4
  • 12
  • 31
  • eithout code it is hard to say what you do wrong im afraid. (i dont think google's json is bad) – Daij-Djan Mar 20 '14 at 08:31
  • I recommend you to track json data that google returns to you. – birdcage Mar 20 '14 at 07:50
  • I checked the JSON data that Google returns. It's interesting that there are many object but I'm encoding only . I thought that this could be the problem but I'm still not sure. If I track it it's giving me again not the proper polyline. – WWJD Mar 20 '14 at 08:17
  • I see. if it doesnt return the true polyline, u cant see the it on the map properly for sure. – birdcage Mar 20 '14 at 08:28
  • Hi @WWJD, I have the same issue as described in your question(on Android it works as expected). I will appreciate if you can describe your update and explain how do you fixed this issue? Thanks in advance! – David V Jul 09 '14 at 20:01
  • 1
    @IAmDav I've edited the post. If you have more questions feel free to ask! – WWJD Jul 10 '14 at 07:40
  • @WWJD Thank you very much for your Edit! Worked perfectly for me! I spend more then one week in total and don't find where issue comes from! Seems there are no any relevant documentation about this difference... In any case Thank YOU! – David V Jul 10 '14 at 18:27
  • @WWJD i m facing issue could u answer briefly here..http://stackoverflow.com/q/40150430/2522603 – ChenSmile Nov 18 '16 at 04:58
  • @WWJD have you got solutions of above issue. same issue in my side – Rohit Nishad May 26 '20 at 19:26

0 Answers0