Как декодировать полилинии поля Google Directions API в длинные длинные точки в target-C для iPhone? - PullRequest
43 голосов
/ 09 февраля 2012

Я хочу нарисовать маршруты на карте, соответствующей направлениям JSON, которые я получаю через API-интерфейсы Google: http://code.google.com/apis/maps/documentation/directions/

Я понял, как извлечь широту и долготу из поля шагов, однако это не очень хорошо подходит для извилистых дорог. Я думаю, что мне нужно, чтобы декодировать информацию о полилинии, я нашел Googles инструкции о том, как кодировать полилинии: http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html

Я нашел здесь некоторый код для Android, а также Javascript для декодирования полилиний, например:

Карта Просмотр направлений рисования с использованием Google Directions API - декодирование полилиний

Android получить и разобрать Google Directions

Но я не могу найти то же самое для кода Objective-C iPhone, кто-нибудь может мне помочь с этим? Я уверен, что смогу сделать это сам, если придется, но это сэкономит мне время, если оно уже где-то доступно ...

РЕДАКТИРОВАТЬ: ключ здесь в состоянии декодировать кодировку base64 на символьной основе. Чтобы быть более конкретным, я получаю нечто подобное в JSON от Google, который, помимо прочего, кодируется с использованием кодировки base64:

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

Примечание: я должен упомянуть, что этот вопрос относится к API Карт Google v1, это гораздо проще сделать в v2 с помощью GMSPolyLine polyLineWithPath, как вам ответят многие ответы ниже (благодаря @cdescours).

Ответы [ 12 ]

1 голос
/ 08 октября 2013

Это мое собственное повторение ответа Седаты Чужой.Это та же самая реализация, за исключением удаления дублированного кода и использования 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
0 голосов
/ 28 сентября 2016

Если кто-то еще пытается сделать это быстро, вот ответ @ 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!)
}
...