Polyline decoder
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
*.pyc
|
*.pyc
|
||||||
|
cartodb_services.egg-info/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
from redis_tools import RedisConnection
|
from redis_tools import RedisConnection
|
||||||
from coordinates import Coordinate
|
from coordinates import Coordinate
|
||||||
|
from polyline import PolyLine
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
from itertools import tee, izip
|
||||||
|
from math import trunc
|
||||||
|
|
||||||
|
|
||||||
|
class PolyLine:
|
||||||
|
""" Polyline decoder https://developers.google.com/maps/documentation/utilities/polylinealgorithm?csw=1 """
|
||||||
|
|
||||||
|
def decode(self, data):
|
||||||
|
coordinates = []
|
||||||
|
chunks = self._extract_chunks(data)
|
||||||
|
for chunk in chunks:
|
||||||
|
coordinate = self._process_chunk(chunk)
|
||||||
|
coordinate /= 1e5
|
||||||
|
print coordinate
|
||||||
|
if len(coordinates) > 1:
|
||||||
|
# We have to sum the previous with the offset in this chunk
|
||||||
|
coordinate += coordinates[-2]
|
||||||
|
coordinates.append(round(coordinate, 5))
|
||||||
|
|
||||||
|
print coordinates
|
||||||
|
|
||||||
|
return zip(coordinates, coordinates[1:])[::2]
|
||||||
|
|
||||||
|
def _extract_chunks(self, data):
|
||||||
|
chunks, chunk = [], []
|
||||||
|
for character in data:
|
||||||
|
byte = ord(character) - 63
|
||||||
|
if byte & 0x20 > 0:
|
||||||
|
byte &= 0x1F
|
||||||
|
chunk.append(byte)
|
||||||
|
else:
|
||||||
|
chunk.append(byte)
|
||||||
|
chunks.append(chunk)
|
||||||
|
chunk = []
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
def _process_chunk(self, chunk):
|
||||||
|
coordinate = self._get_coordinate(chunk)
|
||||||
|
# Check if the coordinate is negative
|
||||||
|
if coordinate & 0x1:
|
||||||
|
return ~(coordinate >> 1)
|
||||||
|
else:
|
||||||
|
return coordinate >> 1
|
||||||
|
|
||||||
|
def _get_coordinate(self, chunk):
|
||||||
|
coordinate = 0
|
||||||
|
for i, c in enumerate(chunk):
|
||||||
|
coordinate |= c << (i * 5)
|
||||||
|
|
||||||
|
return coordinate
|
||||||
39
server/lib/python/cartodb_services/test/test_polyline.py
Normal file
39
server/lib/python/cartodb_services/test/test_polyline.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
from cartodb_services.tools import PolyLine
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestPolyline(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.polyline = PolyLine()
|
||||||
|
|
||||||
|
def test_should_decode_a_chunk_correctly(self):
|
||||||
|
decoded_polyline = self.polyline.decode('`~oia@`~oia@')
|
||||||
|
original_value = [(-179.98321, -179.98321)]
|
||||||
|
|
||||||
|
assert decoded_polyline == original_value
|
||||||
|
|
||||||
|
def test_should_decode_polyline_correctly(self):
|
||||||
|
original_polyline_1 = [(38.5, -120.2),
|
||||||
|
(40.7, -120.95),
|
||||||
|
(43.252, -126.453)]
|
||||||
|
decoded_polyline_1 = self.polyline.decode('_p~iF~ps|U_ulLnnqC_mqNvxq`@')
|
||||||
|
|
||||||
|
assert decoded_polyline_1 == original_polyline_1
|
||||||
|
|
||||||
|
original_polyline_2 = [(17.95783,-5.58105),
|
||||||
|
(15.79225,2.90039),
|
||||||
|
(7.60211,-10.76660)]
|
||||||
|
decoded_polyline_2 = self.polyline.decode('mkrlBp`aa@z}eL_pwr@js~p@tilrA')
|
||||||
|
|
||||||
|
assert decoded_polyline_2 == original_polyline_2
|
||||||
|
|
||||||
|
original_polyline_3 = [(62.75473,-157.14844),
|
||||||
|
(65.07213,169.80469) ,
|
||||||
|
(48.92250,158.55469),
|
||||||
|
(44.33957,-150.46875)]
|
||||||
|
decoded_polyline_3 = self.polyline.decode('ax_~Jv`d~\wrcMa`qj}@dfqaBngtcAhb~Zncc}y@')
|
||||||
|
|
||||||
|
assert decoded_polyline_3 == original_polyline_3
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user