web-dev-qa-db-fra.com

Comment décoder le champ de polylignes de l'API Google Directions en points longs lat dans objectif-C pour iPhone?

Je souhaite dessiner des itinéraires sur une carte correspondant aux directions JSON que je reçois via l'API Google Directions: http://code.google.com/apis/maps/documentation/directions/

J'ai trouvé comment extraire la latitude et la longitude du champ des marches, mais cela ne suit pas très bien les routes sinueuses. Je pense que ce dont j'ai besoin est de décoder les informations de la polyligne, j'ai trouvé des instructions de Google sur la façon de coder les polylignes: http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html

J'ai trouvé du code ici pour Android et aussi Javascript sur le décodage des polylignes, par exemple:

Map View dessiner des itinéraires à l'aide de l'API Google Directions - décodage des polylignes

Android obtenir et analyser Google Directions

Mais je ne peux pas trouver la même chose pour le code iPhone Objective-C, quelqu'un peut-il m'aider avec cela? Je suis sûr que je peux le faire moi-même si je le dois, mais cela me ferait gagner du temps s'il est déjà disponible quelque part ...

EDIT: la clé ici est de pouvoir décoder l'encodage base64 caractère par caractère. Pour être plus précis, j'obtiens quelque chose comme ça dans JSON de Google qui est encodé en utilisant l'encodage base64 entre autres:

...   "overview_polyline" : {
        "points" : "ydelDz~vpN_@NO@QEKWIYIIO?YCS@WFGBEBICCAE?G@y@RKBEBEBAD?HTpB@LALALCNEJEFSP_@LyDv@aB\\GBMB"
       },
...

Remarque: Je dois mentionner que cette question fait référence à l'API Google Maps v1, il est beaucoup plus facile de le faire dans la v2 en utilisant GMSPolyLine polyLineWithPath comme de nombreuses réponses ci-dessous vous le diront (grâce à @cdescours).

44
Alan Moore

J'espère que ce n'est pas contre les règles de créer un lien vers le mien article de blog si cela est pertinent pour la question, mais j'ai résolu ce problème dans le passé. Réponse autonome de la publication liée:

@implementation MKPolyline (MKPolyline_EncodedString)

+ (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;
}

@end
84
Sedate Alien

La réponse la meilleure et la plus légère devrait être d'utiliser la méthode fournie par Google dans le cadre:

[GMSPolyline polylineWithPath:[GMSPath pathFromEncodedPath:encodedPath]]

31
cdescours

Si vous travaillez avec Google Map sur iOS et que vous souhaitez tracer l'itinéraire, y compris les polylignes, Google lui-même fournit un moyen plus simple d'obtenir le GMSPath à partir de la polyligne,

GMSPath *pathFromPolyline = [GMSPath pathFromEncodedPath:polyLinePoints];

Voici le code complet:

+ (void)callGoogleServiceToGetRouteDataFromSource:(CLLocation *)sourceLocation toDestination:(CLLocation *)destinationLocation onMap:(GMSMapView *)mapView_{
    NSString *baseUrl = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=false", sourceLocation.coordinate.latitude,  sourceLocation.coordinate.longitude, destinationLocation.coordinate.latitude,  destinationLocation.coordinate.longitude];

    NSURL *url = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    NSLog(@"Url: %@", url);

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        GMSMutablePath *path = [GMSMutablePath path];

        NSError *error = nil;
        NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

        NSArray *routes = [result objectForKey:@"routes"];

        NSDictionary *firstRoute = [routes objectAtIndex:0];

        NSDictionary *leg =  [[firstRoute objectForKey:@"legs"] objectAtIndex:0];

        NSArray *steps = [leg objectForKey:@"steps"];

        int stepIndex = 0;

        CLLocationCoordinate2D stepCoordinates[1  + [steps count] + 1];

        for (NSDictionary *step in steps) {

            NSDictionary *start_location = [step objectForKey:@"start_location"];
            stepCoordinates[++stepIndex] = [self coordinateWithLocation:start_location];
            [path addCoordinate:[self coordinateWithLocation:start_location]];

            NSString *polyLinePoints = [[step objectForKey:@"polyline"] objectForKey:@"points"];
            GMSPath *polyLinePath = [GMSPath pathFromEncodedPath:polyLinePoints];
            for (int p=0; p<polyLinePath.count; p++) {
                [path addCoordinate:[polyLinePath coordinateAtIndex:p]];
            }


            if ([steps count] == stepIndex){
                NSDictionary *end_location = [step objectForKey:@"end_location"];
                stepCoordinates[++stepIndex] = [self coordinateWithLocation:end_location];
                [path addCoordinate:[self coordinateWithLocation:end_location]];
            }
        }

        GMSPolyline *polyline = nil;
        polyline = [GMSPolyline polylineWithPath:path];
        polyline.strokeColor = [UIColor grayColor];
        polyline.strokeWidth = 3.f;
        polyline.map = mapView_;
    }];
}

+ (CLLocationCoordinate2D)coordinateWithLocation:(NSDictionary*)location
{
    double latitude = [[location objectForKey:@"lat"] doubleValue];
    double longitude = [[location objectForKey:@"lng"] doubleValue];

    return CLLocationCoordinate2DMake(latitude, longitude);
}
10
RootCode
- (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;
}
- (MKPolygonRenderer *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
  //  MKPolygonRenderer *polylineView = [[MKPolygonRenderer alloc] initWithOverlay:overlay];
    MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
    polylineView.strokeColor = [UIColor redColor];
    polylineView.lineWidth = 4.0;
    [self zoomToPolyLine:mapview polyline:overlay animated:YES];
    return polylineView;
}
-(void)zoomToPolyLine: (MKMapView*)map polyline: (MKPolyline*)polyline animated: (BOOL)animated
{
    [map setVisibleMapRect:[polyline boundingMapRect] edgePadding:UIEdgeInsetsMake(25.0, 25.0, 25.0, 25.0) animated:animated];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
   // NSLog(@"didUpdateToLocation: %@", newLocation);
    CLLocation *currentLocation = newLocation;
    if (currentLocation != nil) {
      currlong  =  [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
       currlt = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
    }
    NSString *Origin = [NSString stringWithFormat:@"%@%@%@",currlt,@",",currlong];

    //I have just mention static location
    NSString *drivein = @"23.0472963,72.52757040000006";
    NSString *apikey = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@",Origin,drivein];

    NSURL *url = [NSURL URLWithString:apikey];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLResponse *response;
    NSError *error;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

    if(!error)
    {
        NSData *data = [responseString dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data
                                                                     options:kNilOptions
                                                                       error:&error];
        NSArray *routesArray = [jsonResponse objectForKey:@"routes"];
        NSLog(@"route array %@",routesArray);
        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];
            [mapview addOverlay:line];
        }
    }
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(currentLocation.coordinate, 500, 500);
    MKCoordinateRegion adjustedRegion = [mapview regionThatFits:viewRegion];
    [mapview setRegion:adjustedRegion animated:YES];
    mapview.showsUserLocation = YES;

    MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
    point.coordinate = currentLocation.coordinate;
    point.title = @"Your current Locations";
    point.subtitle = @"You are here!";
    [mapview addAnnotation:point];
    [locationmanger stopUpdatingLocation];
}
5
kalpesh

Implémentation de Python

Ce n'est pas dans Objective-C, mais ce fil est l'endroit où Google vous dépose si vous cherchez à décoder des chaînes de polyligne à partir de Google Maps. Au cas où quelqu'un d'autre en aurait besoin (un peu comme je l'ai fait), voici une implémentation Python pour le décodage des chaînes de polyligne. Ceci est porté depuis la version JavaScript de Mapbox; plus d'informations sur mon repo page.

def decode_polyline(polyline_str):
    index, lat, lng = 0, 0, 0
    coordinates = []
    changes = {'latitude': 0, 'longitude': 0}

    # Coordinates have variable length when encoded, so just keep
    # track of whether we've hit the end of the string. In each
    # while loop iteration, a single coordinate is decoded.
    while index < len(polyline_str):
        # Gather lat/lon changes, store them in a dictionary to apply them later
        for unit in ['latitude', 'longitude']: 
            shift, result = 0, 0

            while True:
                byte = ord(polyline_str[index]) - 63
                index+=1
                result |= (byte & 0x1f) << shift
                shift += 5
                if not byte >= 0x20:
                    break

            if (result & 1):
                changes[unit] = ~(result >> 1)
            else:
                changes[unit] = (result >> 1)

        lat += changes['latitude']
        lng += changes['longitude']

        coordinates.append((lat / 100000.0, lng / 100000.0))

    return coordinates
3
Mike Davlantes

Voici comment je le fais dans mon application d'itinéraire. keyPlace est votre objet de destination

- (void)getDirections {

  CLLocation *newLocation;// = currentUserLocation;
  MKPointAnnotation *annotation = [[[MKPointAnnotation alloc] init] autorelease];
  annotation.coordinate = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
  annotation.title = @"You";
  [mapView addAnnotation:annotation];

  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=walking", newLocation.coordinate.latitude, newLocation.coordinate.longitude, keyPlace.lat, keyPlace.lon]];
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  [request startSynchronous];

  if ([[request.responseString.JSONValue 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] autorelease] show];
    self.navigationController.navigationBar.userInteractionEnabled = YES;
    return; 
  }

  int points_count = 0;
  if ([[request.responseString.JSONValue objectForKey:@"routes"] count])
    points_count = [[[[[[request.responseString.JSONValue 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] autorelease] show];
    self.navigationController.navigationBar.userInteractionEnabled = YES;
    return;     
  }
  CLLocationCoordinate2D points[points_count * 2];

  int j = 0;
  NSArray *steps = nil;
  if (points_count && [[[[request.responseString.JSONValue objectForKey:@"routes"] objectAtIndex:0] objectForKey:@"legs"] count])
    steps = [[[[[request.responseString.JSONValue 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];

    if (end_lat > 0.0f && end_lon > 0.0f) {
      points[j] = CLLocationCoordinate2DMake(end_lat, end_lon);
      endCoordinate = CLLocationCoordinate2DMake(end_lat, end_lon);
      j++;
    }
  }

  MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:points_count * 2];
  [mapView addOverlay:polyline];


}

#pragma mark - MapKit
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
  MKPinAnnotationView *annView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"currentloc"] autorelease];
  annView.canShowCallout = YES;
  annView.animatesDrop = YES;
  return annView;
}

- (MKOverlayView *)mapView:(MKMapView *)mapView
            viewForOverlay:(id<MKOverlay>)overlay {
  MKPolylineView *overlayView = [[[MKPolylineView alloc] initWithOverlay:overlay] autorelease];
  overlayView.lineWidth = 5;
  overlayView.strokeColor = [UIColor purpleColor];
  overlayView.fillColor = [[UIColor purpleColor] colorWithAlphaComponent:0.5f];
  return overlayView;
}
3
Eugene

Au cas où quelqu'un aurait besoin du code de décodage en VBA, voici un port (de travail):

    Function decodeGeopoints(encoded)
  decodeGeopoints = ""
  ' This code is a port to VBA from code published here:
  ' http://blog.synyx.de/2010/06/routing-driving-directions-on-Android-part-1-get-the-route/

  '//decoding
  'List poly = new ArrayList();

  '// replace two backslashes by one (some error from the transmission)
  'encoded = encoded.replace("\\", "\");
  encoded = Replace(encoded, "\\", "\")

  'int index = 0, len = encoded.length();
  Dim index As Long
  index = 0
  Dim leng As Long
  leng = Len(encoded)

  'int lat = 0, lng = 0;
  Dim lat As Long
  lat = 0
  Dim lng As Long
  lng = 0

  'while (index < len) {
  While (index < leng)
     'int b, shift = 0, result = 0;
     Dim b, shift, result As Long
     b = 0
     shift = 0
     result = 0

     'do {
     Do
        'b = encoded.charAt(index++) - 63;
        index = index + 1
        b = Asc(Mid(encoded, index, 1)) - 63
        'result |= (b & 0x1f) << shift;
        result = result Or ((b And 31) * (2 ^ shift))

        'shift += 5;
        shift = shift + 5
     '} while (b >= 0x20);
     Loop While (b >= 32)
     'int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
     Dim dlat As Long
     If (result And 1) <> 0 Then
      dlat = Not Int(result / 2)
     Else
      dlat = Int(result / 2)
     End If

     'lat += dlat;
     lat = lat + dlat

     'shift = 0;
     shift = 0
     'result = 0;
     result = 0
     'do {
     Do
       'b = encoded.charAt(index++) - 63;
       index = index + 1
       b = Asc(Mid(encoded, index, 1)) - 63
       'result |= (b & 0x1f) << shift;
        result = result Or ((b And 31) * (2 ^ shift))
       'shift += 5;
        shift = shift + 5
     '} while (b >= 0x20);
     Loop While (b >= 32)
     'int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
     Dim dlng As Long
     If (result And 1) <> 0 Then
      dlng = Not Int(result / 2)
     Else
      dlng = Int(result / 2)
     End If

     'lng += dlng;
     lng = lng + dlng

     'GeoPoint p = new GeoPoint((int) (((double) lat / 1E5) * 1E6), (int) (((double) lng / 1E5) * 1E6));
     Dim myLat, myLng As Double
     myLat = (lat / 100000)
     'myLat = myLat * 1000000
     myLng = (lng / 100000)
     'myLng = myLng * 1000000

     'poly.add(p);
     decodeGeopoints = decodeGeopoints & Comma2Dot(myLng) & "," & Comma2Dot(myLat) & ",0 "
  '}
  Wend

End Function
2
Martin

Swift 3.

let polyline = GMSPolyline(path: GMSPath.init(fromEncodedPath: encodedPolyline))
2
apinho

Pour Google Maps, il dispose déjà d'une méthode simple, polylineWithPath, donc je préfère cet extrait.

-(void)drawPathFrom:(CLLocation*)source toDestination:(CLLocation*)destination{

    NSString *baseUrl = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true", source.coordinate.latitude,  source.coordinate.longitude, destination.coordinate.latitude,  destination.coordinate.longitude];

    NSURL *url = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSLog(@"Url: %@", url);
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if(!connectionError){
            NSDictionary *result        = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            NSArray *routes             = [result objectForKey:@"routes"];
            NSDictionary *firstRoute    = [routes objectAtIndex:0];
            NSString *encodedPath       = [firstRoute[@"overview_polyline"] objectForKey:@"points"];

            GMSPolyline *polyPath       = [GMSPolyline polylineWithPath:[GMSPath pathFromEncodedPath:encodedPath]];
            polyPath.strokeColor        = [UIColor redColor];
            polyPath.strokeWidth        = 3.5f;
            polyPath.map                = _mapView;
        }
    }];

}
2
Mrug

Ceci est ma propre revisitation de la réponse de Sedate Alien. Il s'agit de la même mise en œuvre, sauf pour supprimer le code dupliqué et utiliser NSMutableData au lieu d'allouer manuellement des éléments.

@implementation MKPolyline (EncodedString)

+ (float)decodeBytes:(const char *)bytes atPos:(NSUInteger *)idx toValue:(float *)value {
  char byte  = 0;
  int  res   = 0;
  char shift = 0;

  do {
    byte   = bytes[(*idx)++] - 0x3F;
    res   |= (byte & 0x1F) << shift;
    shift += 5;
  }
  while (byte >= 0x20);

  (*value) += ((res & 1) ? ~(res >> 1) : (res >> 1));

  return (*value) * 1E-5;
}

+ (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
  const char             *bytes  = [encodedString UTF8String];
  NSUInteger              length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  NSUInteger              idx    = 0;
  NSMutableData          *data   = [NSMutableData data];
  float                   lat    = 0;
  float                   lon    = 0;
  CLLocationCoordinate2D  coords = CLLocationCoordinate2DMake(0, 0);

  while (idx < length) {

    coords.latitude  = [self decodeBytes:bytes atPos:&idx toValue:&lat];
    coords.longitude = [self decodeBytes:bytes atPos:&idx toValue:&lon];

    [data appendBytes:&coords length:sizeof(CLLocationCoordinate2D)];
  }

  return [MKPolyline polylineWithCoordinates:(CLLocationCoordinate2D *)data.bytes count:data.length / sizeof(CLLocationCoordinate2D)];
}

@end
1
Noberasco

Les autres réponses semblent concerner l'utilisation de Apple Maps, pour utiliser Google Maps, j'ai constaté que je devais apporter quelques modifications à la grande catégorie de @ SedateAlien.

CATÉGORIE MODIFIÉE

+ (GMSPolyline *)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;
        }
    }

    GMSMutablePath *path = [[GMSMutablePath alloc] init];

    int i;
    for (i = 0; i < coordIdx; i++)
    {
        [path addCoordinate:coords[i]];
    }

    GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
    free(coords);

    return polyline;
}

UTILISATION

// Here I make the call to the Google Maps API to get the routes between two points...

....

// Get the encoded array of points.
NSString *points = routes[@"routes"][0][@"overview_polyline"][@"points"];

// Use the modified category to get a polyline from the points.
GMSPolyline *polyline = [GMSPolyline polylineWithEncodedString:points];

// Add the polyline to the map.
polyline.strokeColor = [UIColor redColor];
polyline.strokeWidth = 10.f;
polyline.map = theMapView;
}
1
paulvs

Si quelqu'un d'autre essaie de le faire dans Swift, voici la réponse de @ RootCode adaptée à Swift (2.3):

let path = GMSMutablePath()
let steps = directionsToShowOnMap.steps
for (idx, step) in steps.enumerate() {
    path.addCoordinate(coordinateFromJson(step["start_location"]))
    if let polylinePoints = step["polyline"].string, subpath = GMSPath(fromEncodedPath: polylinePoints) {
        for c in 0 ..< subpath.count() {
            path.addCoordinate(subpath.coordinateAtIndex(c))
        }   
    }
    if idx == steps.count - 1 {
        path.addCoordinate(coordinateFromJson(step["end_location"]))
    }
}
let polyline = GMSPolyline(path: path)
polyline.strokeColor = UIColor.blueColor()
polyline.strokeWidth = 3
polyline.map = mapView

et alors:

private func coordinateFromJson(location: JSON) -> CLLocationCoordinate2D {
    return CLLocationCoordinate2DMake(location["lat"].double!, location["lng"].double!)
}
0
Eric