3

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;

enter image description here

Why it is drawing like that and not going into the street it self?

What am I doing wrong here?

Jagat Dave
  • 1,643
  • 3
  • 23
  • 30
ytpm
  • 4,962
  • 6
  • 56
  • 113

2 Answers2

4

Try this it draws exact path like in driving mode - StreetMode, Here's my code :

iOS GSMPolyLine

adijazz91
  • 404
  • 3
  • 12
2

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.

ytpm
  • 4,962
  • 6
  • 56
  • 113