Polyline Encoding

The rapidgeo.polyline module provides Google Polyline Algorithm encoding and decoding with optional simplification support.

The Google Polyline Algorithm is a lossy compression format for storing sequences of coordinates as ASCII strings. It’s commonly used in mapping applications like Google Maps.

Core Functions

Google Polyline Algorithm encoding/decoding with simplification support

rapidgeo.polyline.encode(coordinates, precision=5)

Encode a sequence of coordinates into a Google Polyline Algorithm string.

Compresses coordinate sequences using variable-length encoding and delta compression. Commonly used for GPS tracks, routes, and mapping applications.

Parameters:
  • coordinates (List[LngLat]) – Sequence of coordinates to encode

  • precision (int, optional) – Decimal places of precision (1-11). Defaults to 5. - 5: ~1 meter accuracy (standard) - 6: ~10 centimeter accuracy (high precision)

Returns:

Encoded polyline string

Return type:

str

Raises:

ValueError – If precision is invalid or coordinates cause overflow

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.polyline import encode
>>> coords = [LngLat(-120.2, 38.5), LngLat(-120.95, 40.7)]
>>> polyline = encode(coords, 5)
>>> print(polyline)
'_p~iF~ps|U_ulLnnqC_mqNvxq`@'
rapidgeo.polyline.decode(polyline, precision=5)

Decode a Google Polyline Algorithm string back into coordinates.

Reverses the polyline encoding process to reconstruct the original coordinate sequence. The precision must match what was used during encoding.

Parameters:
  • polyline (str) – Encoded polyline string

  • precision (int, optional) – Decimal places used during encoding. Defaults to 5.

Returns:

Decoded coordinate sequence

Return type:

List[LngLat]

Raises:

ValueError – If polyline is malformed or precision is invalid

Examples

>>> from rapidgeo.polyline import decode
>>> polyline = '_p~iF~ps|U_ulLnnqC_mqNvxq`@'
>>> coords = decode(polyline, 5)
>>> print(f"First coord: {coords[0].lng}, {coords[0].lat}")
First coord: -120.2, 38.5
rapidgeo.polyline.encode_simplified(coordinates, tolerance_m, method='great_circle', precision=5)

Encode coordinates with line simplification into a Google Polyline string.

Combines Douglas-Peucker line simplification with polyline encoding in one step. This reduces coordinate count while maintaining essential shape, then compresses the result using Google’s polyline algorithm.

Parameters:
  • coordinates (List[LngLat]) – Sequence of coordinates to simplify and encode

  • tolerance_m (float) – Simplification tolerance in meters. Higher values = more simplification.

  • method (str, optional) – Distance calculation method. Defaults to “great_circle”. - “great_circle”: Accurate geographic distance (recommended) - “planar”: Fast approximation for small areas - “euclidean”: Fastest, treat coordinates as flat plane

  • precision (int, optional) – Decimal places of precision (1-11). Defaults to 5.

Returns:

Simplified and encoded polyline string

Return type:

str

Raises:

ValueError – If tolerance is negative, method is unknown, or precision is invalid

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.polyline import encode_simplified
>>> # GPS track with noise - simplify to 10 meter tolerance
>>> track = [LngLat(-120.2, 38.5), LngLat(-120.201, 38.501), LngLat(-120.95, 40.7)]
>>> simplified = encode_simplified(track, tolerance_m=10.0)
>>> # Result has fewer points than original track
rapidgeo.polyline.simplify_polyline(polyline, tolerance_m, method='great_circle', precision=5)

Simplify an already-encoded Google Polyline string.

Decodes a polyline string, applies Douglas-Peucker simplification, then re-encodes it. Useful when you have polyline data from external sources that needs simplification without converting back to coordinate arrays.

Parameters:
  • polyline (str) – Encoded polyline string to simplify

  • tolerance_m (float) – Simplification tolerance in meters. Higher values = more simplification.

  • method (str, optional) – Distance calculation method. Defaults to “great_circle”. - “great_circle”: Accurate geographic distance (recommended) - “planar”: Fast approximation for small areas - “euclidean”: Fastest, treat coordinates as flat plane

  • precision (int, optional) – Decimal places of precision (1-11). Defaults to 5.

Returns:

Simplified polyline string with same precision as input

Return type:

str

Raises:

ValueError – If polyline is malformed, tolerance is negative, method is unknown, or precision is invalid

Examples

>>> from rapidgeo.polyline import simplify_polyline
>>> # Simplify detailed polyline from mapping API to reduce size
>>> detailed = '_p~iF~ps|U_ulLnnqC_c~vLvxq`@'
>>> simplified = simplify_polyline(detailed, tolerance_m=50.0)
>>> # Result string is shorter with fewer encoded points
rapidgeo.polyline.encode_batch(coordinates_list, precision=5)

Encode multiple sequences of coordinates into Google Polyline Algorithm strings.

Batch processing version of encode() that efficiently handles multiple coordinate sequences in parallel. Useful for encoding many routes, tracks, or boundaries at once.

Parameters:
  • coordinates_list (List[List[LngLat]]) – List of coordinate sequences to encode

  • precision (int, optional) – Decimal places of precision (1-11). Defaults to 5. - 5: ~1 meter accuracy (standard) - 6: ~10 centimeter accuracy (high precision)

Returns:

List of encoded polyline strings, one for each input sequence

Return type:

List[str]

Raises:

ValueError – If precision is invalid or any coordinates cause overflow

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.polyline import encode_batch
>>> routes = [
...     [LngLat(-120.2, 38.5), LngLat(-120.95, 40.7)],
...     [LngLat(-121.0, 39.0), LngLat(-122.0, 40.0)]
... ]
>>> polylines = encode_batch(routes, 5)
>>> len(polylines)
2
rapidgeo.polyline.decode_batch(polylines, precision=5)

Decode multiple Google Polyline Algorithm strings back into coordinate sequences.

Batch processing version of decode() that efficiently handles multiple polyline strings in parallel. Useful for decoding many encoded routes, tracks, or boundaries at once.

Parameters:
  • polylines (List[str]) – List of encoded polyline strings to decode

  • precision (int, optional) – Decimal places used during encoding. Defaults to 5. Must match the precision used when the polylines were originally encoded.

Returns:

List of decoded coordinate sequences, one for each input polyline

Return type:

List[List[LngLat]]

Raises:

ValueError – If any polyline is malformed or precision is invalid

Examples

>>> from rapidgeo.polyline import decode_batch
>>> polylines = [
...     '_p~iF~ps|U_ulLnnqC_mqNvxq`@',
...     'u{~vFvyys@fS]'
... ]
>>> routes = decode_batch(polylines, 5)
>>> len(routes)
2
>>> len(routes[0])  # Number of points in first route
3
rapidgeo.polyline.encode_simplified_batch(coordinates_list, tolerance_m, method='great_circle', precision=5)

Encode multiple coordinate sequences with line simplification into Google Polyline strings.

Batch processing version of encode_simplified() that efficiently handles multiple coordinate sequences in parallel. Combines Douglas-Peucker line simplification with polyline encoding for each sequence. Useful for processing many GPS tracks, routes, or boundaries with noise reduction.

Parameters:
  • coordinates_list (List[List[LngLat]]) – List of coordinate sequences to simplify and encode

  • tolerance_m (float) – Simplification tolerance in meters. Higher values = more simplification. Applied uniformly to all sequences in the batch.

  • method (str, optional) – Distance calculation method. Defaults to “great_circle”. - “great_circle”: Accurate geographic distance (recommended) - “planar”: Fast approximation for small areas - “euclidean”: Fastest, treat coordinates as flat plane

  • precision (int, optional) – Decimal places of precision (1-11). Defaults to 5.

Returns:

List of simplified and encoded polyline strings, one for each input sequence

Return type:

List[str]

Raises:

ValueError – If tolerance is negative, method is unknown, or precision is invalid

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.polyline import encode_simplified_batch
>>> # Multiple GPS tracks with noise - simplify all to 10 meter tolerance
>>> tracks = [
...     [LngLat(-120.2, 38.5), LngLat(-120.201, 38.501), LngLat(-120.95, 40.7)],
...     [LngLat(-121.0, 39.0), LngLat(-121.001, 39.001), LngLat(-122.0, 40.0)]
... ]
>>> simplified = encode_simplified_batch(tracks, tolerance_m=10.0)
>>> len(simplified)
2
>>> # Each result has fewer points than original tracks
rapidgeo.polyline.encode_column(coordinates_column, precision=5)

Encode an entire pandas column/Series of coordinates to polylines

This is the fastest way to convert coordinate data to polylines. Takes a pandas Series or any iterable of coordinate arrays and returns all polylines in one shot. Uses Rayon parallelization internally for maximum performance.

Parameters:
  • coordinates_column – pandas Series, list, or iterable of coordinate arrays

  • precision (int, optional) – Decimal places of precision (1-11). Defaults to 5.

Returns:

List of encoded polyline strings, one per input coordinate array

Return type:

List[str]

Examples

>>> df['polylines'] = rapidgeo.polyline.encode_column(df['coordinates'])
>>> # processes entire column at once with parallel encoding

Basic Usage

Encoding:

from rapidgeo.distance import LngLat
from rapidgeo.polyline import encode, decode

# Define a simple path
path = [
    LngLat.new_deg(-122.4194, 37.7749),  # San Francisco
    LngLat.new_deg(-87.6298, 41.8781),   # Chicago
    LngLat.new_deg(-74.0060, 40.7128),   # New York City
]

# Encode to polyline string
polyline_str = encode(path, precision=5)
print(f"Encoded: {polyline_str}")

# Decode back to coordinates
decoded_path = decode(polyline_str, precision=5)
print(f"Decoded {len(decoded_path)} points")

Precision Levels:

  • precision=5: Standard precision (~1 meter accuracy)

  • precision=6: High precision (~0.1 meter accuracy)

  • precision=7: Very high precision (~0.01 meter accuracy)

Higher precision results in longer encoded strings but better coordinate accuracy.

Simplification

Polylines can be simplified during encoding to reduce size while maintaining shape:

from rapidgeo.polyline import encode_simplified

# Create a detailed path with many points
detailed_path = [
    LngLat.new_deg(-122.4194, 37.7749),
    LngLat.new_deg(-122.4180, 37.7755),  # Close intermediate point
    LngLat.new_deg(-122.4160, 37.7765),  # Another close point
    LngLat.new_deg(-87.6298, 41.8781),   # Far point - will be kept
]

# Encode with simplification (1km tolerance)
simplified = encode_simplified(detailed_path, tolerance_m=1000.0, precision=5)
print(f"Simplified polyline: {simplified}")

# You can also simplify an existing polyline
from rapidgeo.polyline import simplify_polyline

original = encode(detailed_path, precision=5)
simplified = simplify_polyline(original, tolerance_m=1000.0, precision=5)

Batch Operations

Process multiple polylines efficiently:

from rapidgeo.polyline import encode_batch, decode_batch, encode_simplified_batch

# Multiple paths to process
paths = [
    [LngLat.new_deg(-122.4, 37.7), LngLat.new_deg(-122.3, 37.8)],
    [LngLat.new_deg(-74.0, 40.7), LngLat.new_deg(-74.1, 40.8)],
]

# Batch encode
encoded_polylines = encode_batch(paths, precision=5)
print(f"Encoded {len(encoded_polylines)} polylines")

# Batch decode
decoded_paths = decode_batch(encoded_polylines, precision=5)
print(f"Decoded {len(decoded_paths)} paths")

# Batch encode with simplification
simplified_polylines = encode_simplified_batch(
    paths, tolerance_m=100.0, precision=5
)

Real-World Example

Here’s a complete example showing how you might use polylines in a web mapping application:

from rapidgeo.distance import LngLat
from rapidgeo.polyline import encode_simplified, decode
from rapidgeo.distance.batch import path_length_haversine

# GPS track data (e.g., from a mobile app)
gps_track = [
    LngLat.new_deg(-122.4194, 37.7749),
    LngLat.new_deg(-122.4180, 37.7755),
    LngLat.new_deg(-122.4160, 37.7765),
    LngLat.new_deg(-122.4140, 37.7775),
    # ... many more points
    LngLat.new_deg(-122.4000, 37.7900),
]

# Calculate original track length
original_length = path_length_haversine(gps_track)
print(f"Original track: {len(gps_track)} points, {original_length/1000:.2f} km")

# Encode with simplification for web transmission
# 10m tolerance reduces data size while preserving route shape
polyline_str = encode_simplified(gps_track, tolerance_m=10.0, precision=5)
print(f"Encoded polyline: {len(polyline_str)} characters")

# On the client side, decode the polyline
simplified_track = decode(polyline_str, precision=5)
simplified_length = path_length_haversine(simplified_track)

print(f"Simplified track: {len(simplified_track)} points, {simplified_length/1000:.2f} km")
print(f"Size reduction: {(1 - len(simplified_track)/len(gps_track))*100:.1f}%")

Algorithm Details

Encoding Process:

  1. Convert coordinates to integers by multiplying by 10^precision

  2. Calculate deltas between consecutive points

  3. Apply zigzag encoding to handle negative numbers

  4. Convert to base32 representation using specific character set

Precision vs. Size:

  • Higher precision = more accurate coordinates but longer strings

  • Lower precision = smaller strings but coordinate quantization

  • Choose precision based on your accuracy requirements

Simplification:

  • Uses Douglas-Peucker algorithm during encoding

  • Tolerance specified in meters (real-world distance)

  • Points are retained if they deviate more than tolerance from the simplified line

Implementation Notes

Processing:

  • Batch operations handle multiple polylines efficiently

  • Simplification uses Douglas-Peucker algorithm

  • Memory usage scales with input size

Precision Trade-offs:

  • Higher precision = more accurate coordinates, longer strings

  • Lower precision = shorter strings, some coordinate rounding

  • Choose based on your accuracy requirements