5

I wrote simple application which draws route between two locations on MapKit. I am using Google Map API. I used resources I found online and here's the code I am using to make request to Google:

_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:@"http://maps.googleapis.com/"]];
    [_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
    [_httpClient setDefaultHeader:@"Accept" value:@"application/json"];

    NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
    [parameters setObject:[NSString stringWithFormat:@"%f,%f", coordinate.latitude, coordinate.longitude] forKey:@"origin"];
    [parameters setObject:[NSString stringWithFormat:@"%f,%f", endCoordinate.latitude, endCoordinate.longitude] forKey:@"destination"];
    [parameters setObject:@"true" forKey:@"sensor"];

    NSMutableURLRequest *request = [_httpClient requestWithMethod:@"GET" path: @"maps/api/directions/json" parameters:parameters];
    request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];    
    [operation  setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
        NSInteger statusCode = operation.response.statusCode;

        if (statusCode == 200)
        {
            NSLog(@"Success: %@", operation.responseString);
        }
        else
        {
            NSLog(@"Status code = %d", statusCode);
        }
    }
                                      failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                          NSLog(@"Error: %@",  operation.responseString);

                                      }
     ];

    [_httpClient enqueueHTTPRequestOperation:operation];

This works flawlessly. When I run this and try to show route between LA and Chicago, here's how it looks like:

LA - Chicago route zoomed out

BUT. When I zoom map to street level, here's how route looks like:

LA - Chicago route zoomed in

Does anyone know how can I achieve that route I am drawing follows streets when map is zoomed? I'd like route to show exact path through the streets. I don't know if some additional parameter needs to be added to my request to Google.

Any help or advice would be great. Many thanks in advance!


[edit #1: Adding request URL and response from Google]

My request URL after creating operation object from code above looks like this:

http://maps.googleapis.com/maps/api/directions/json?sensor=true&destination=34%2E052360,-118%2E243560&origin=41%2E903630,-87%2E629790

Just paste that URL to your browser and you will see the JSON data Google sends as the response which I get in my code also.


[edit #2: Parsing answer from Google and building the path]

- (void)parseResponse:(NSData *)response
{
    NSDictionary *dictResponse = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableContainers error:nil];
    NSArray *routes = [dictResponse objectForKey:@"routes"];
    NSDictionary *route = [routes lastObject];

    if (route)
    {
        NSString *overviewPolyline = [[route objectForKey: @"overview_polyline"] objectForKey:@"points"];
        _path = [self decodePolyLine:overviewPolyline];
    }
}

- (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;
}
uerceg
  • 4,637
  • 6
  • 45
  • 63

2 Answers2

1

It looks like Google is not giving you all the points, or you are not looking at all the points. Actually, I'd expect polylines between placemarks, not only placemarks like you seem to have (with a straight line).

  • Check DirectionsStatus in the response to see if you are limited
  • Provide the json data that Google sends back.

I'm not so sure they use a radically different Mercator projection from the one used by Google.

Cyril Godefroy
  • 1,400
  • 12
  • 15
  • Thank you for the answer, Cyril. Check edit #1 in my question, I provided data you asked in there. – uerceg Oct 23 '12 at 05:33
  • In edit #2 I added source code which parses answer from Google and builds the path. I tried now to change mode from DRIVING to WALKING and interesting thing is that although JSON response from Google is obviously way bigger than in DRIVING mode, I still get in the end 205 coordinates for WALKING in path, and for DRIVING I get 203 coordinates in path. Strange. – uerceg Oct 23 '12 at 06:23
  • I have unfortunately not enough knowledge of the directions API to help you further. I think a key element is this sentence in documentation: "overview_polyline contains an object holding an array of encoded points that represent an approximate (smoothed) path of the resulting directions." Try the same request with a short route and see if it is more precise, or better yet, try a really square route like in NY or LA, to see if your path gets better as you request a closer route. – Cyril Godefroy Oct 23 '12 at 11:39
  • Yes Cyril, I tried this and forgot to mention it in one of my edits. When I want to display route between LA and Chicago, it looks like mentioned above in my question. But when I put LA coordinates as origin and LA coordinates (latitude and longitude) + 0.3f as target point, route line follows streets of LA really nice. So, looks like that those street points are simply ignored in Google response when I am trying to draw route between two very distant points. – uerceg Oct 23 '12 at 12:08
  • Hi @uerceg, Do you find solution for your question? I'm currently getting the same issue. Any help will be appreciated. Thanks in advance! – David V Jul 09 '14 at 20:36
0

I believe that the projection used by MapKit is different than that used by Google Maps. MapKit uses Cylindrical Mercator, while Google uses a variant of the Mercator Projection.

Converting Between Coordinate Systems Although you normally specify points on the map using latitude and longitude values, there may be times when you need to convert to and from other coordinate systems. For example, you typically use map points when specifying the shape of overlays.

Quoted from Apple:

Marcelo
  • 9,387
  • 3
  • 35
  • 40