Декодирование ломаной маршрута

Cервис построения маршрутов использует кодированный формат полилинии для хранения серии координат широты и долготы в виде одной строки. Полилинейное кодирование значительно уменьшает размер ответа.

Для декодирования полилинии в серию координат вы можете использовать приведённые ниже примеры.

JavaScript

polyline.decode = function(str, precision) {
    var index = 0,
        lat = 0,
        lng = 0,
        coordinates = [],
        shift = 0,
        result = 0,
        byte = null,
        latitude_change,
        longitude_change,
        factor = Math.pow(10, precision || 6);
 
    // Coordinates have variable length when encoded, so just keep
    // track of whether we've hit the end of the string. In each
    // loop iteration, a single coordinate is decoded.
    while (index < str.length) {
 
        // Reset shift, result, and byte
        byte = null;
        shift = 0;
        result = 0;
 
        do {
            byte = str.charCodeAt(index++) - 63;
            result |= (byte & 0x1f) << shift;
            shift += 5;
        while (byte >= 0x20);
 
        latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
 
        shift = result = 0;
 
        do {
            byte = str.charCodeAt(index++) - 63;
            result |= (byte & 0x1f) << shift;
            shift += 5;
        while (byte >= 0x20);
 
        longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
 
        lat += latitude_change;
        lng += longitude_change;
 
        coordinates.push([lat / factor, lng / factor]);
    }
 
    return coordinates;
};

C++ 11

#include <vector>
 
constexpr double kPolylinePrecision = 1E6;
constexpr double kInvPolylinePrecision = 1.0 / kPolylinePrecision;
 
struct PointLL {
  float lat;
  float lon;
};
 
std::vector<PointLL> decode(const std::string& encoded) {
  size_t i = 0;     // what byte are we looking at
 
  // Handy lambda to turn a few bytes of an encoded string into an integer
  auto deserialize = [&encoded, &i](const int previous) {
    // Grab each 5 bits and mask it in where it belongs using the shift
    int byte, shift = 0, result = 0;
    do {
      byte = static_cast<int>(encoded[i++]) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    while (byte >= 0x20);
    // Undo the left shift from above or the bit flipping and add to previous
    // since its an offset
    return previous + (result & 1 ? ~(result >> 1) : (result >> 1));
  };
 
  // Iterate over all characters in the encoded string
  std::vector<PointLL> shape;
  int last_lon = 0, last_lat = 0;
  while (i < encoded.length()) {
    // Decode the coordinates, lat first for some reason
    int lat = deserialize(last_lat);
    int lon = deserialize(last_lon);
 
    // Shift the decimal point 5 places to the left
    shape.emplace_back(static_cast<float>(static_cast<double>(lat) *
                                          kInvPolylinePrecision),
                       static_cast<float>(static_cast<double>(lon) *
                                          kInvPolylinePrecision));
 
    // Remember the last one we encountered
    last_lon = lon;
    last_lat = lat;
  }
  return shape;
}

Python

#!/usr/bin/env python
 
import sys
 
 
#six degrees of precision in valhalla
inv = 1.0 / 1e6;
 
 
def decode(encoded):
    """Decodes route polyline which is returned by rose."""
    decoded = []
    = 0
    previous_coords = {'lat'0'lon'0}
    while i < len(encoded):
        coords = dict()
        for coord_name in ('lat''lon'):
            coord = 0
            shift = 0
            byte = 0x20
            # Keep decoding bytes until you have this coord.
            while byte >= 0x20:
                byte = ord(encoded[i]) - 63
                += 1
                coord |= (byte & 0x1f) << shift
                shift += 5
            # Get the final value adding the previous offset and
            # remember it for the next.
            coords[coord_name] = previous_coords[coord_name] + (
                ~(coord >> 1)
                if coord & 1
                else (coord >> 1)
            )
        # Scale by the precision and chop off long coords.
        # Also flip the positions so its the far more standard
        # (lon, lat) instead of (lat, lon).
        decoded.append([
            float(f"{coords['lon'] * inv:.6f}"),
            float(f"{coords['lat'] * inv:.6f}"),
        ])
        previous_coords = coords
    return decoded
 
 
print decode(sys.argv[1])
Was this information helpful?