Source code for spatial
from dicts import *
from numeric import *
from strings import *
from math import radians, cos, sin, asin, sqrt
[docs]class LatLonCell(DictCell):
"""
Holds a Latitude and Longitude.
TODO: we should allow an address to be 'coerced' into a LatLonCell via a special
Geocoding operation, and then stored in 'to_addresscell'
"""
def __init__(self):
structure = {}
structure['lat'] = IntervalCell(-90.0, 90.0)
structure['lon'] = IntervalCell(-180.0, 180.0)
DictCell.__init__(self, structure)
self.to_addresscell = None # cached addresscell pointer
def __sub__(self, other):
"""
Overloads the - operator to call the haversine distance
function.
Requires that the lat/lon values are scalars, not intervals,
or it raises an exception. (We could generalize haversine to
work with intervals, but I couldn't think of a usecase)
"""
if self['lat'].low == self['lat'].high and \
self['lon'].low == self['lon'].high and \
other['lat'].low == other['lat'].high and \
other['lon'].low == other['lon'].high:
return self.haversine(other)
else:
raise Exception("Cannot compute distance of intervals")
[docs] def haversine(self, other):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians,\
[self.lon.low, self['lat'].low, other.lon.low,
other['lat'].low])
# 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))
# multiply by radius of the earth
# km = 6367 * c
miles = 3961 * c
return miles
[docs]class AddressCell(DictCell):
"""
Holds an Address
TODO: coerce to LatLonCell via inverse geocoding operation
"""
def __init__(self):
structure = {}
structure['street'] = StringCell()
structure['city'] = StringCell()
structure['state'] = StringCell()
structure['zip'] = StringCell()
structure['gps'] = LatLonCell()
DictCell.__init__(self, structure)
self.to_latlongcell = None # cached latlon cell pointer