如何将 Google Directions API 折线字段解码为 Objective-C for iPhone 中的经纬度点?

问题描述 投票:0回答:14

我想在地图上绘制与我通过 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 iPhone 代码,有人可以帮我吗?我确信如果有必要的话我可以自己做,但如果它已经在某个地方可用,它肯定会节省我一些时间。

编辑:这里的关键是能够逐个字符地解码 Base64 编码。更具体地说,我从 Google 得到了类似 JSON 的内容,它是使用 base64 编码等进行编码的:

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

注意:我应该提到这个问题是指 Google Maps API v1,在 v2 中使用 GMSPolyLine polyLineWithPath 更容易做到这一点,下面的许多答案都会告诉你(感谢 @cdescours)。

iphone objective-c json google-polyline google-directions-api
14个回答
88
投票

我希望链接到我自己的博客文章(如果它与问题相关)不违反规则,但我过去已经解决了这个问题。来自链接帖子的独立答案:

@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

33
投票

最好、最简单的答案应该是使用框架中Google提供的方法:

[GMSPolyline polylineWithPath:[GMSPath pathFromEncodedPath:encodedPath]]


10
投票

如果您在 iOS 上使用 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);
}

6
投票

斯威夫特3.0

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

5
投票

Python 实现

这不是 Objective-C 中的内容,但如果您想从 Google 地图中解码折线字符串,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

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

3
投票

这是我在路线应用程序中的操作方法。 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;
}

2
投票

如果有人需要 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

2
投票

对于谷歌地图,它已经有一个直接的方法,

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

}

2
投票

斯威夫特 4.2 / 斯威夫特 5

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

1
投票

这是我自己对 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

1
投票

这里的其他答案似乎是关于使用苹果地图,为了使用谷歌地图,我发现我必须对@SedateAlien的伟大类别进行一些修改。

修改类别

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

0
投票

如果其他人尝试在 swift 中执行此操作,这里是 @RootCode 的答案,适用于 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

然后:

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

0
投票

我想分享 ChatGPT 版本的解决方案

public static List<Tuple<double, double>> DecodePolyline(string encodedPolyline)
{
    List<Tuple<double, double>> polyLinePoints = new List<Tuple<double, double>>();

    int index = 0;
    int latitude = 0;
    int longitude = 0;

    while (index < encodedPolyline.Length)
    {
        int shift = 0;
        int result = 0;

        int currentByte;
        do
        {
            currentByte = encodedPolyline[index++] - 63;
            result |= (currentByte & 0x1F) << shift;
            shift += 5;
        }
        while (currentByte >= 0x20);

        int deltaLatitude = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        latitude += deltaLatitude;

        shift = 0;
        result = 0;

        do
        {
            currentByte = encodedPolyline[index++] - 63;
            result |= (currentByte & 0x1F) << shift;
            shift += 5;
        }
        while (currentByte >= 0x20);

        int deltaLongitude = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
        longitude += deltaLongitude;

        double finalLat = latitude / 1E5;
        double finalLng = longitude / 1E5;

        polyLinePoints.Add(new Tuple<double, double>(finalLat, finalLng));
    }

    return polyLinePoints;
}

经过尝试和测试

points: ec`xA_`saVAkC?o@?c@?O?}B?Q?K@qAAsB?e@Fe@Ae@?U?a@@G@E^gA

已解码

Latitude: 14.58755, Longitude: 121.01648
Latitude: 14.58756, Longitude: 121.01718
Latitude: 14.58756, Longitude: 121.01742
Latitude: 14.58756, Longitude: 121.0176
Latitude: 14.58756, Longitude: 121.01768
Latitude: 14.58756, Longitude: 121.01831
Latitude: 14.58756, Longitude: 121.0184
Latitude: 14.58756, Longitude: 121.01846
Latitude: 14.58755, Longitude: 121.01887
Latitude: 14.58756, Longitude: 121.01945
Latitude: 14.58756, Longitude: 121.01964
Latitude: 14.58752, Longitude: 121.01983
Latitude: 14.58753, Longitude: 121.02002
Latitude: 14.58753, Longitude: 121.02013
Latitude: 14.58753, Longitude: 121.0203
Latitude: 14.58752, Longitude: 121.02034
Latitude: 14.58751, Longitude: 121.02037
Latitude: 14.58735, Longitude: 121.02073

您也可以在这里验证 https://developers.google.com/maps/documentation/utilities/polylineutility

© www.soinside.com 2019 - 2024. All rights reserved.