From 4d04882c184cc0ccfbbff2db0a6e5637da157bbd Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Tue, 1 Mar 2016 23:05:24 +0100 Subject: [PATCH] Polyline decoder --- .gitignore | 3 ++ .../cartodb_services/tools/__init__.py | 3 +- .../cartodb_services/tools/polyline.py | 51 +++++++++++++++++++ .../cartodb_services/test/test_polyline.py | 39 ++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 server/lib/python/cartodb_services/cartodb_services/tools/polyline.py create mode 100644 server/lib/python/cartodb_services/test/test_polyline.py diff --git a/.gitignore b/.gitignore index dde3895..f33df99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ .DS_Store *.pyc +cartodb_services.egg-info/ +build/ +dist/ diff --git a/server/lib/python/cartodb_services/cartodb_services/tools/__init__.py b/server/lib/python/cartodb_services/cartodb_services/tools/__init__.py index 200dcd4..dbf91b5 100644 --- a/server/lib/python/cartodb_services/cartodb_services/tools/__init__.py +++ b/server/lib/python/cartodb_services/cartodb_services/tools/__init__.py @@ -1,2 +1,3 @@ from redis_tools import RedisConnection -from coordinates import Coordinate \ No newline at end of file +from coordinates import Coordinate +from polyline import PolyLine diff --git a/server/lib/python/cartodb_services/cartodb_services/tools/polyline.py b/server/lib/python/cartodb_services/cartodb_services/tools/polyline.py new file mode 100644 index 0000000..a903e57 --- /dev/null +++ b/server/lib/python/cartodb_services/cartodb_services/tools/polyline.py @@ -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 diff --git a/server/lib/python/cartodb_services/test/test_polyline.py b/server/lib/python/cartodb_services/test/test_polyline.py new file mode 100644 index 0000000..9d5be45 --- /dev/null +++ b/server/lib/python/cartodb_services/test/test_polyline.py @@ -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 + +