79 lines
2.4 KiB
Python
79 lines
2.4 KiB
Python
import unittest
|
|
from mock import Mock
|
|
from cartodb_services.mapzen import MapzenIsolines
|
|
from math import radians, cos, sin, asin, sqrt
|
|
|
|
"""
|
|
This file is basically a sanity test on the algorithm.
|
|
|
|
|
|
It uses a mocked client, which returns the cost based on a very simple model:
|
|
just proportional to the distance from origin to the target point.
|
|
"""
|
|
|
|
|
|
class MatrixClientMock():
|
|
|
|
def __init__(self, speed):
|
|
"""
|
|
Sets up the mock with a speed in km/h
|
|
"""
|
|
self._speed = speed
|
|
|
|
def one_to_many(self, locations, costing):
|
|
origin = locations[0]
|
|
distances = [self._distance(origin, l) for l in locations]
|
|
response = {
|
|
'one_to_many': [
|
|
[
|
|
{
|
|
'distance': distances[i] * self._speed,
|
|
'time': distances[i] / self._speed * 3600,
|
|
'to_index': i,
|
|
'from_index': 0
|
|
}
|
|
for i in xrange(0, len(distances))
|
|
]
|
|
],
|
|
'units': 'km',
|
|
'locations': [
|
|
locations
|
|
]
|
|
}
|
|
return response
|
|
|
|
def _distance(self, a, b):
|
|
"""
|
|
Calculate the great circle distance between two points
|
|
on the earth (specified in decimal degrees)
|
|
http://stackoverflow.com/questions/4913349/haversine-formula-in-python-bearing-and-distance-between-two-gps-points
|
|
|
|
Returns:
|
|
distance in meters
|
|
"""
|
|
|
|
# convert decimal degrees to radians
|
|
lon1, lat1, lon2, lat2 = map(radians, [a['lon'], a['lat'], b['lon'], b['lat']])
|
|
|
|
# haversine formula
|
|
dlon = lon2 - lon1
|
|
dlat = lat2 - lat1
|
|
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
|
|
c = 2 * asin(sqrt(a))
|
|
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
|
|
return c * r
|
|
|
|
|
|
class MapzenIsolinesTestCase(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
speed = 4 # in km/h
|
|
matrix_client = MatrixClientMock(speed)
|
|
self.mapzen_isolines = MapzenIsolines(matrix_client, Mock())
|
|
|
|
def test_calculate_isochrone(self):
|
|
origin = {"lat":40.744014,"lon":-73.990508}
|
|
transport_mode = 'walk'
|
|
isorange = 10 * 60 # 10 minutes
|
|
solution = self.mapzen_isolines.calculate_isochrone(origin, transport_mode, isorange)
|