Polyline Encoding

Understand the encoded polyline algorithm and use our interactive playground to encode/decode coordinates

Overview

Polyline encoding is a lossy compression algorithm that stores a series of coordinates as a single ASCII string. The Woosmap Directions API returns route geometries as encoded polylines.

When using the Map JS API with DirectionsRenderer, decoding and display are handled automatically. The DirectionResult object also provides a pre-decoded overview_path property if you need direct access to the coordinates.

Polyline Encoding Algorithm

The encoding process converts coordinates into ASCII characters using a base64-like scheme. Each encoded value is summed with 63 (the ASCII character ?) to ensure printable characters.

Key points:

  • Coordinates are multiplied by 1e5 and rounded to integers
  • Points store only the offset from the previous point (delta encoding)
  • A continuation bit indicates when more data follows for a single value
  • Negative values use two’s complement with bit inversion

Note: Backslash characters in encoded strings must be escaped as double-backslashes in string literals.

Encoding Steps

  1. Take the signed value (e.g., -179.9832104)
  2. Multiply by 1e5, round → -17998321
  3. Convert to binary using two’s complement for negatives
  4. Left-shift one bit
  5. Invert if original was negative
  6. Break into 5-bit chunks, reverse order
  7. OR with 0x20 if more chunks follow
  8. Add 63, convert to ASCII

Example

Encoding three points: (38.5, -120.2), (40.7, -120.95), (43.252, -126.453)

Latitude Longitude Δ Lat Δ Lng Encoded Point
38.5 -120.2 +3850000 -12020000 _p~iF~ps\|U
40.7 -120.95 +220000 -75000 _ulLnnqC
43.252 -126.453 +255200 -550300 _mqNvxq\@

Result: _p~iF~ps|U_ulLnnqC_mqNvxq@

Using the Map JS API

The simplest way to display a route is with DirectionsRenderer, which handles decoding automatically:

javascript
        const directionsService = new woosmap.map.DirectionsService();
const directionsRenderer = new woosmap.map.DirectionsRenderer({ map: map });

directionsService.route({
  origin: { lat: 48.8566, lng: 2.3522 },
  destination: { lat: 45.764, lng: 4.8357 }
}).then((response) => {
  directionsRenderer.setDirections(response);
});

    

If you need the decoded coordinates directly, use the overview_path property:

javascript
        directionsService.route({
  origin: { lat: 48.8566, lng: 2.3522 },
  destination: { lat: 45.764, lng: 4.8357 }
}).then((response) => {
  const path = response.routes[0].overview_path; // Already decoded!
  
  const routeLine = new woosmap.map.Polyline({
    path: path,
    strokeColor: "#4285F4",
    strokeWeight: 4
  });
  routeLine.setMap(map);
});

    

Manual Decoding

If you need to decode polylines outside the Map JS API context (e.g., server-side or with raw API responses):

Decode to [lat, lng] array
        function decodePolyline(encoded, precision = 5) {
  const coordinates = [];
  const factor = Math.pow(10, precision);
  let index = 0;
  let lat = 0;
  let lng = 0;

  while (index < encoded.length) {
    let byte;
    let shift = 0;
    let result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const latitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    shift = 0;
    result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const longitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    lat += latitudeChange;
    lng += longitudeChange;

    coordinates.push([lat / factor, lng / factor]);
  }

  return coordinates;
}

    
        type LatLngTuple = [latitude: number, longitude: number];

function decodePolyline(encoded: string, precision: number = 5): LatLngTuple[] {
  const coordinates: LatLngTuple[] = [];
  const factor = Math.pow(10, precision);
  let index = 0;
  let lat = 0;
  let lng = 0;

  while (index < encoded.length) {
    let byte: number;
    let shift = 0;
    let result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const latitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    shift = 0;
    result = 0;

    do {
      byte = encoded.charCodeAt(index++) - 63;
      result |= (byte & 0x1f) << shift;
      shift += 5;
    } while (byte >= 0x20);

    const longitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);

    lat += latitudeChange;
    lng += longitudeChange;

    coordinates.push([lat / factor, lng / factor]);
  }

  return coordinates;
}

    

Interactive Playground

Encode coordinates or decode polyline strings and see the results on the map:

Precision

Standard polyline encoding uses 5 decimal places (1e5), giving ~1.1 meter accuracy. Some systems use 6 decimal places (1e6) for ~11 cm accuracy. Ensure encoder and decoder use matching precision.

Was this helpful?