def get_bike_trip_path(start, end, client): """ Given a bike trip starting point, a bike trip ending point, and a Google Maps client, returns a list of coordinates corresponding with the path that that bike probably took, as reported by Google Maps. Parameters ---------- start: list The starting point coordinates, in [latitude, longitude] (or [y, x]) format. end: list The end point coordinates, in [latitude, longitude] (or [y, x]) format. client: googlemaps.Client A `googlemaps.Client` instance, as returned by e.g. `import_google_credentials()`. Returns ------- The list of [latitude, longitude] coordinates for the given bike trip. """ codec = PolylineCodec() req = client.directions(start, end, mode='bicycling') polylines = [step['polyline']['points'] for step in [leg['steps'] for leg in req[0]['legs']][0]] coords = [] for polyline in polylines: coords += codec.decode(polyline) return coords
def get_json(*paths): all_json = [] for path in paths: with open(path, 'r') as f: data = f.read() j = json.loads(data) pc = PC() for item in j: item['path'] = pc.decode(item['path']) all_json.extend(j) return all_json
def get_json(*paths): all_json = [] for path in paths: with open(path, 'r') as f: data = f.read() j = json.loads(data) pc = PC() for item in j: item['path'] = pc.decode(item['path']) all_json.extend(j) return all_json
class GooglePaths(): """ This tries to get all the coordinates along the start and end of a path for a user """ def __init__(self, startLatitude, startLongitude, endLatitude, endLongitude, pickupStruct, cabRideNumber): self.baseUrl = "https://maps.googleapis.com/maps/api/directions/json?" self.startLatitude = startLatitude self.startLongitude = startLongitude self.endLatitude = endLatitude self.endLongitude = endLongitude self.pickupTime = pickupStruct self.cabRideNumber = cabRideNumber self.apiKey = "AIzaSyCuzBdk6sIIrrJpgQmcJbwtfumumuRLStU" self.polylineCodec = PolylineCodec() def __makeRequest(self): requestUrl = self.baseUrl + "origin= " + self.startLatitude + "," + self.startLongitude + "&destination= " + self.endLatitude + "," + self.endLongitude + "&key= " + self.apiKey response = requests.request("GET", requestUrl) return response.json() def convertToLines(self, responseJson): polyline = responseJson["routes"][0]["overview_polyline"]["points"] points = self.polylineCodec.decode(polyline) stepsList =[] counter = 0 for lat, long in points: counter += 1 stepsList.append({"time": str(pickupTime + datetime.timedelta(seconds=counter+5)), "cabRideNumber": self.cabRideNumber, 'latitude': lat, 'longitude': long}) stepsListFinal = [stepsList[0]] length = len(stepsList) sample = [] if len(stepsList)-2 > 20: sample = random.sample(stepsList[1: (length-2)], length/6) stepsListFinal = stepsListFinal + sample + [stepsList[length -1]] return stepsListFinal def getPaths(self): self.responseJson = self.__makeRequest() self.lines = self.convertToLines(self.responseJson) return self.lines
def get_rebalancing_trip_path_time_estimate_tuple(start, end, client): """ Given a re-balancing trip starting point, a re-balancing trip ending point, and a Google Maps client, returns a list of coordinates corresponding with the path that van probably took, as reported by Google Maps, as well as a time estimate. The need to return a tuple containing not just the path (as in the case of very similar `bike_tripper`) stems from the fact that whereas for bikes we have a precise time in transit, we have no such information for rebalancing van trips, meaning that we have to calculate the time taken and timing of such trips ourselves. Parameters ---------- start: list The starting point coordinates, in [latitude, longitude] (or [y, x]) format. end: list The end point coordinates, in [latitude, longitude] (or [y, x]) format. client: googlemaps.Client A `googlemaps.Client` instance, as returned by e.g. `import_google_credentials()`. Returns ------- The list of [latitude, longitude] coordinates for the given bike trip. """ codec = PolylineCodec() req = client.directions(start, end, mode='driving') # Get the time estimates. # Raw time estimate results are strings of the form "1 min", "5 mins", "1 hour 5 mins", "2 hours 5 mins", etc. time_estimates_raw = [step['duration']['text'] for step in [leg['steps'] for leg in req[0]['legs']][0]] time_estimate_mins = 0 for time_estimate_raw in time_estimates_raw: # Can we really get an hour+ estimate biking within the city? Possibly not but I won't risk it. if "min" in time_estimate_raw and "hour" not in time_estimate_raw: time_estimate_mins += int(time_estimate_raw.split(" ")[0]) elif "hour" in time_estimate_raw: time_estimate_mins += 60 * int(time_estimate_raw.split(" ")[0]) if "min" in time_estimate_raw: time_estimate_mins += int(time_estimate_raw.split(" ")[2]) else: # Uh-oh. pass # Get the polylines. polylines = [step['polyline']['points'] for step in [leg['steps'] for leg in req[0]['legs']][0]] coords = [] for polyline in polylines: coords += codec.decode(polyline) # Return return coords, time_estimate_mins
def gpolyfiles2shp(pattern, ofname=None): files = glob(pattern) gpx = GpxRoute() with ThreadPoolExecutor(max_workers=4) as pool: futures2poly = {pool.submit(get_content, fname): fname for fname in files} for future in as_completed(futures2poly): fname = futures2poly[future] print('Handling %r' % fname) if future.exception() is not None: print('%r generated an exception: %s' % (fname, future.exception())) continue pcodec = PolylineCodec() polyxy = pcodec.decode(future.result()) gpx_route = new_gpx_route(polyxy, name=fname) gpx.routes.append(gpx_route) with open(ofname, 'wb') as ofile: ofile.write(gpx.to_xml()) print(ofname)
def gpoly2shp( ifname, ofname=None, geom_path='routes/route/polyline-definition/polyline', time_path='routes/route/summary/time', length_path='routes/route/summary/length', ): response = get_content(ifname) pcodec = PolylineCodec() polyxy = pcodec.decode(get_item(response, geom_path)) length = int(get_item(response, length_path)) time = int(get_item(response, time_path)) schema = { 'geometry': 'LineString', 'properties': { 'seconds': 'int', 'meters': 'int', 'x_start': 'float', 'y_start': 'float', 'x_end': 'float', 'y_end': 'float', 'cat': 'str', }, } fname, extension = splitext(ifname) ofname = ofname or join(dirname(fname), '{}.shp'.format(basename(fname))) with fiona.open(ofname, mode='w', driver='ESRI Shapefile', schema=schema) as lyr: lyr.write({ 'geometry': mapping(LineString(polyxy)), 'properties': { 'seconds': time, 'meters': length, } }) print(ofname)
def gpoly2gpx(ifname, output_dir=None, json_path='routes/route/polyline-definition/polyline'): response = get_content(ifname) pcodec = PolylineCodec() item = get_item(response, json_path) if item is None: logging.error( 'Bad input from file {ifname}' '`\n`--> response {response}' .format(**locals())) sys.exit(1) polyxy = pcodec.decode(item) gpx = GpxRoute() gpx_route = new_gpx_route(polyxy) gpx.routes.append(gpx_route) fname, extension = splitext(ifname) output_dir = output_dir or dirname(fname) ofname = join(output_dir, '{}.gpx'.format(basename(fname))) with open(ofname, 'wb') as ofile: ofile.write(gpx.to_xml()) print(ofname)
class PolylineCodecTestCase(unittest.TestCase): def setUp(self): self.codec = PolylineCodec() def test_decode_multiple_points(self): d = self.codec.decode('gu`wFnfys@???nKgE??gE?????oK????fE??fE') self.assertEqual(d, [ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654) ]) def test_decode_multiple_points_precision(self): d = self.codec.decode('o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@', 6) self.assertEqual(d, [ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654) ]) def test_decode_official_example(self): d = self.codec.decode('_p~iF~ps|U_ulLnnqC_mqNvxq`@') self.assertEqual(d, [ (38.500, -120.200), (40.700, -120.950), (43.252, -126.453) ]) def test_decode_official_example_precision(self): d = self.codec.decode('_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI', 6) self.assertEqual(d, [ (38.500, -120.200), (40.700, -120.950), (43.252, -126.453) ]) def test_decode_single_point(self): d = self.codec.decode('gu`wFf`ys@') self.assertEqual(d, [ (40.641, -8.653) ]) def test_decode_single_point_precision(self): d = self.codec.decode('o}oolAnkcoO', 6) self.assertEqual(d, [ (40.641, -8.653) ]) def test_encode_multiple_points(self): e = self.codec.encode([ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654) ]) self.assertEqual(e, 'gu`wFnfys@???nKgE??gE?????oK????fE??fE') def test_encode_multiple_points_precision(self): e = self.codec.encode([ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654) ], 6) self.assertEqual(e, 'o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@') def test_encode_official_example(self): e = self.codec.encode([ (38.500, -120.200), (40.700, -120.950), (43.252, -126.453) ]) self.assertEqual(e, '_p~iF~ps|U_ulLnnqC_mqNvxq`@') def test_encode_official_example_precision(self): e = self.codec.encode([ (38.500, -120.200), (40.700, -120.950), (43.252, -126.453) ], 6) self.assertEqual(e, '_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI') def test_encode_single_point(self): e = self.codec.encode([ (40.641, -8.653) ]) self.assertEqual(e, 'gu`wFf`ys@') def test_encode_single_point_precision(self): e = self.codec.encode([ (40.641, -8.653) ], 6) self.assertEqual(e, 'o}oolAnkcoO') def test_a_variety_of_precisions(self): """uses a generator to create a variety of lat-lon's across the global and tests a range of precision settings from 4 to 8""" def generator(): while True: coords = [] for i in range(2, randint(4, 10)): lat, lon = uniform(-180.0, 180.0), uniform(-180.0, 180.0) xy = (round(lat, 5), round(lon, 5)) coords.append(xy) yield coords patience = 3 # seconds. waypoints, okays = 0, 0 g = generator() start = time.time() while time.time() < start + patience: precision = randint(4, 8) wp = next(g) waypoints += len(wp) polyline = self.codec.encode(wp, precision) wp2 = self.codec.decode(polyline, precision) if wp == wp2: okays += len(wp2) else: for idx, _ in enumerate(wp): dx, dy = abs(wp[idx][0] - wp2[idx][0]), abs(wp[idx][1] - wp2[idx][1]) if dx > 10 ** -(precision - 1) or dy > 10 ** -(precision - 1): print("idx={}, dx={}, dy={}".format(idx, dx, dy)) else: okays += 1 assert okays == waypoints print("encoded and decoded {0:.2f}% correctly for {1} waypoints @ {2} wp/sec".format( 100 * okays / float(waypoints), waypoints, round(waypoints / patience, 0)))
class PolylineCodecTestCase(unittest.TestCase): def setUp(self): self.codec = PolylineCodec() def test_decode_multiple_points(self): d = self.codec.decode('gu`wFnfys@???nKgE??gE?????oK????fE??fE') self.assertEqual(d, [(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)]) def test_decode_multiple_points_precision(self): d = self.codec.decode('o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@', 6) self.assertEqual(d, [(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)]) def test_decode_official_example(self): d = self.codec.decode('_p~iF~ps|U_ulLnnqC_mqNvxq`@') self.assertEqual(d, [(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) def test_decode_official_example_precision(self): d = self.codec.decode('_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI', 6) self.assertEqual(d, [(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) def test_decode_single_point(self): d = self.codec.decode('gu`wFf`ys@') self.assertEqual(d, [(40.641, -8.653)]) def test_decode_single_point_precision(self): d = self.codec.decode('o}oolAnkcoO', 6) self.assertEqual(d, [(40.641, -8.653)]) def test_encode_multiple_points(self): e = self.codec.encode([(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)]) self.assertEqual(e, 'gu`wFnfys@???nKgE??gE?????oK????fE??fE') def test_encode_multiple_points_precision(self): e = self.codec.encode([(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)], 6) self.assertEqual(e, 'o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@') def test_encode_official_example(self): e = self.codec.encode([(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) self.assertEqual(e, '_p~iF~ps|U_ulLnnqC_mqNvxq`@') def test_encode_official_example_precision(self): e = self.codec.encode([(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)], 6) self.assertEqual(e, '_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI') def test_encode_single_point(self): e = self.codec.encode([(40.641, -8.653)]) self.assertEqual(e, 'gu`wFf`ys@') def test_encode_single_point_precision(self): e = self.codec.encode([(40.641, -8.653)], 6) self.assertEqual(e, 'o}oolAnkcoO') def test_a_variety_of_precisions(self): """uses a generator to create a variety of lat-lon's across the global and tests a range of precision settings from 4 to 8""" def generator(): while True: coords = [] for i in range(2, randint(4, 10)): lat, lon = uniform(-180.0, 180.0), uniform(-180.0, 180.0) xy = (round(lat, 5), round(lon, 5)) coords.append(xy) yield coords patience = 3 # seconds. waypoints, okays = 0, 0 g = generator() start = time.time() while time.time() < start + patience: precision = randint(4, 8) wp = next(g) waypoints += len(wp) polyline = self.codec.encode(wp, precision) wp2 = self.codec.decode(polyline, precision) if wp == wp2: okays += len(wp2) else: for idx, _ in enumerate(wp): dx, dy = abs(wp[idx][0] - wp2[idx][0]), abs(wp[idx][1] - wp2[idx][1]) if dx > 10**-(precision - 1) or dy > 10**-(precision - 1): print("idx={}, dx={}, dy={}".format(idx, dx, dy)) else: okays += 1 assert okays == waypoints print( "encoded and decoded {0:.2f}% correctly for {1} waypoints @ {2} wp/sec" .format(100 * okays / float(waypoints), waypoints, round(waypoints / patience, 0)))
gmaps = googlemaps.Client(key='') dirs = [] for i in cbike.index: xa = cbike['start station longitude'][i] ya = cbike['start station latitude'][i] xb = cbike['end station longitude'][i] yb = cbike['end station latitude'][i] directions = gmaps.directions((ya, xa), (yb, xb), mode='bicycling') #print directions codec = PolylineCodec() path = [] for s in directions[0]['legs'][0]['steps']: path += codec.decode(s['polyline']['points']) # swap lat and lon pp = zip(*path) path = zip(pp[1], pp[0]) if len(path) > 1: lines = geometry.LineString(path) kml = simplekml.Kml() ls = kml.newlinestring(name='sample') ls.coords = lines.coords kml.save("data/paths/path500_" + str(i) + ".kml")
gmaps = googlemaps.Client(key='') dirs = [] for i in cbike.index: xa = cbike['start station longitude'][i] ya = cbike['start station latitude'][i] xb = cbike['end station longitude'][i] yb = cbike['end station latitude'][i] directions = gmaps.directions((ya,xa), (yb,xb), mode='bicycling') #print directions codec = PolylineCodec() path = [] for s in directions[0]['legs'][0]['steps']: path += codec.decode(s['polyline']['points']) # swap lat and lon pp = zip(*path) path = zip(pp[1], pp[0]) if len(path) > 1: lines = geometry.LineString(path) kml = simplekml.Kml() ls = kml.newlinestring(name='sample') ls.coords = lines.coords kml.save("data/paths/path500_" + str(i) + ".kml")
class PolylineCodecTestCase(unittest.TestCase): def setUp(self): self.codec = PolylineCodec() def test_decode_multiple_points(self): d = self.codec.decode('gu`wFnfys@???nKgE??gE?????oK????fE??fE') self.assertEqual(d, [(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)]) def test_decode_multiple_points_precision(self): d = self.codec.decode('o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@', 6) self.assertEqual(d, [(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)]) def test_decode_official_example(self): d = self.codec.decode('_p~iF~ps|U_ulLnnqC_mqNvxq`@') self.assertEqual(d, [(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) def test_decode_official_example_precision(self): d = self.codec.decode('_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI', 6) self.assertEqual(d, [(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) def test_decode_single_point(self): d = self.codec.decode('gu`wFf`ys@') self.assertEqual(d, [(40.641, -8.653)]) def test_decode_single_point_precision(self): d = self.codec.decode('o}oolAnkcoO', 6) self.assertEqual(d, [(40.641, -8.653)]) def test_encode_multiple_points(self): e = self.codec.encode([(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)]) self.assertEqual(e, 'gu`wFnfys@???nKgE??gE?????oK????fE??fE') def test_encode_multiple_points_precision(self): e = self.codec.encode([(40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654)], 6) self.assertEqual(e, 'o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@') def test_encode_official_example(self): e = self.codec.encode([(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) self.assertEqual(e, '_p~iF~ps|U_ulLnnqC_mqNvxq`@') def test_encode_official_example_precision(self): e = self.codec.encode([(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)], 6) self.assertEqual(e, '_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI') def test_encode_single_point(self): e = self.codec.encode([(40.641, -8.653)]) self.assertEqual(e, 'gu`wFf`ys@') def test_encode_single_point_precision(self): e = self.codec.encode([(40.641, -8.653)], 6) self.assertEqual(e, 'o}oolAnkcoO')
class PolylineCodecTestCase(unittest.TestCase): def setUp(self): self.codec = PolylineCodec() def test_decode_multiple_points(self): d = self.codec.decode("gu`wFnfys@???nKgE??gE?????oK????fE??fE") self.assertEqual( d, [ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654), ], ) def test_decode_multiple_points_precision(self): d = self.codec.decode("o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@", 6) self.assertEqual( d, [ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654), ], ) def test_decode_official_example(self): d = self.codec.decode("_p~iF~ps|U_ulLnnqC_mqNvxq`@") self.assertEqual(d, [(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) def test_decode_official_example_precision(self): d = self.codec.decode("_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI", 6) self.assertEqual(d, [(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) def test_decode_single_point(self): d = self.codec.decode("gu`wFf`ys@") self.assertEqual(d, [(40.641, -8.653)]) def test_decode_single_point_precision(self): d = self.codec.decode("o}oolAnkcoO", 6) self.assertEqual(d, [(40.641, -8.653)]) def test_encode_multiple_points(self): e = self.codec.encode( [ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654), ] ) self.assertEqual(e, "gu`wFnfys@???nKgE??gE?????oK????fE??fE") def test_encode_multiple_points_precision(self): e = self.codec.encode( [ (40.641, -8.654), (40.641, -8.654), (40.641, -8.656), (40.642, -8.656), (40.642, -8.655), (40.642, -8.655), (40.642, -8.655), (40.642, -8.653), (40.642, -8.653), (40.642, -8.653), (40.641, -8.653), (40.641, -8.654), ], 6, ) self.assertEqual(e, "o}oolA~ieoO???~{Bo}@??o}@?????_|B????n}@??n}@") def test_encode_official_example(self): e = self.codec.encode([(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)]) self.assertEqual(e, "_p~iF~ps|U_ulLnnqC_mqNvxq`@") def test_encode_official_example_precision(self): e = self.codec.encode([(38.500, -120.200), (40.700, -120.950), (43.252, -126.453)], 6) self.assertEqual(e, "_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI") def test_encode_single_point(self): e = self.codec.encode([(40.641, -8.653)]) self.assertEqual(e, "gu`wFf`ys@") def test_encode_single_point_precision(self): e = self.codec.encode([(40.641, -8.653)], 6) self.assertEqual(e, "o}oolAnkcoO")