source

iPhone용 Objective-C에서 Google Directions API polylines 필드를 lat long 포인트로 디코딩하는 방법은 무엇입니까?

lovecheck 2023. 2. 26. 09:50
반응형

iPhone용 Objective-C에서 Google Directions API polylines 필드를 lat long 포인트로 디코딩하는 방법은 무엇입니까?

Google Directions API를 통해 얻은 길잡이 JSON에 대응하는 지도에 경로를 그리고 싶습니다.https://developers.google.com/maps/documentation/directions/start

계단 필드에서 위도와 경도를 추출하는 방법을 알아냈지만, 곡선 도로를 잘 따라가지 못합니다.필요한 것은 폴리라인 정보를 디코딩하는 것입니다.폴리라인 인코딩 방법에 대한 구글의 설명을 찾았습니다.https://developers.google.com/maps/documentation/utilities/polylinealgorithm

Android용 코드와 폴리라인 디코딩에 관한 Javascript를 찾았습니다.예를 들어 다음과 같습니다.

지도 보기 Google Directions API를 사용하여 길찾기 - 폴리선 디코딩

Android가 Google Directions를 가져오고 구문 분석합니다.

하지만 Objective-C 아이폰 코드에는 같은 것을 찾을 수 없습니다.누군가 도와주실 수 있나요?필요하다면 제가 직접 할 수 있지만, 이미 어딘가에서 이용할 수 있다면 분명히 시간을 절약할 수 있을 거예요.

편집: 여기서 중요한 것은 Base64 인코딩을 문자별로 디코딩할 수 있는 것입니다.좀 더 구체적으로 말하면, 구글에서 JSON에서 Base64 인코딩을 사용하여 인코딩된 다음과 같은 정보를 얻을 수 있습니다.

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

주의: 이 질문은 Google Maps API v1에 대한 것입니다.v2에서는 GMSPollyLine polyLine을 사용하여 이 작업을 수행하는 것이 훨씬 쉽습니다.WithPath는 아래 답변의 수만큼 알려줍니다(@cdescours 덕분에).

만약 그것이 질문과 관련이 있다면 내 블로그에 링크하는 것이 규칙에 어긋나지 않기를 바라지만, 나는 이 문제를 과거에 해결했다.링크된 게시물의 독립형 답변:

@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

가장 쉽고 최선의 답은 프레임워크에서 Google이 제공하는 방법을 사용하는 것입니다.

[GMSPolyline polylineWithPath:[GMSPath pathFromEncodedPath:encodedPath]]

iOS에서 Google Map을 사용하여 폴리라인을 포함한 경로를 그리려면 Google 자체에서 폴리라인에서 GMSPath를 쉽게 가져올 수 있습니다.

GMSPath *pathFromPolyline = [GMSPath pathFromEncodedPath:polyLinePoints];

다음은 완전한 코드입니다.

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

Swift 3.0

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

Python 구현

Objective-C에는 없지만 Google 지도에서 폴리라인 문자열을 해독하려면 이 스레드가 필요합니다.(나처럼) 다른 사람이 필요할 경우를 대비해 폴리라인 스트링을 디코딩하기 위한 Python 구현이 있습니다.이것은 Mapbox JavaScript 버전에서 이식된 것입니다. 자세한 내용은 내 repo 페이지를 참조하십시오.

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

길찾기 앱은 다음과 같습니다.keyPlace는 대상 객체입니다.

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

VBA의 디코딩 코드가 필요한 경우는, 다음의 포토가 동작하고 있습니다.

    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

구글 지도의 경우, 그것은 이미 간단한 방법을 가지고 있다.polylineWithPath그래서 저는 이 토막이 더 좋아요.

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

}

Swift 4.2 / Swift 5

let gmsPolyline = GMSPolyline(path: GMSPath(fromEncodedPath: encodedPolyline))
gmsPolyline.map = map

이건 내가 다시 생각해본 Sedate Alien의 대답이야.중복된 코드를 제거하고 수동으로 할당하는 대신 NSMutableData를 사용하기 위한 구현 세이브와 동일합니다.

@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

다른 답변은 Apple Maps 사용인 것 같습니다.Google Maps를 사용하기 위해 @Sedate Alien의 훌륭한 카테고리를 수정해야 했습니다.

카테고리 변경

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

사용.

// 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;
}

이것을 신속히 실행하려고 하는 사람이 있다면, swift(2.3)에 맞춘 @RootCode의 회답은 다음과 같습니다.

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

그 후:

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

언급URL : https://stackoverflow.com/questions/9217274/how-to-decode-the-google-directions-api-polylines-field-into-lat-long-points-in

반응형