generated from mwc/lab_weather
226 lines
7.0 KiB
Python
226 lines
7.0 KiB
Python
#!/usr/bin/python
|
|
# coding: utf8
|
|
|
|
import re
|
|
import geocoder
|
|
from six import string_types
|
|
try:
|
|
from statistics import mean
|
|
except ImportError:
|
|
def mean(args):
|
|
return sum(args) / len(args)
|
|
|
|
|
|
class Location(object):
|
|
""" Location container """
|
|
lat = None
|
|
lng = None
|
|
|
|
def __init__(self, location, **kwargs):
|
|
self.location = location
|
|
self.kwargs = kwargs
|
|
self._check_input(location)
|
|
|
|
@property
|
|
def ok(self):
|
|
return bool(self.latlng)
|
|
|
|
@staticmethod
|
|
def _convert_float(number):
|
|
try:
|
|
return float(number)
|
|
except ValueError:
|
|
return None
|
|
|
|
def _check_input(self, location):
|
|
# Checking for a LatLng String
|
|
if isinstance(location, string_types):
|
|
expression = r"[-]?\d+[.]?[-]?[\d]+"
|
|
pattern = re.compile(expression)
|
|
match = pattern.findall(location)
|
|
if len(match) == 2:
|
|
lat, lng = match
|
|
self._check_for_list([lat, lng])
|
|
else:
|
|
# Check for string to Geocode using a provider
|
|
provider = self.kwargs.get('provider', 'osm')
|
|
g = geocoder.get(location, provider=provider)
|
|
if g.ok:
|
|
self.lat, self.lng = g.lat, g.lng
|
|
|
|
# Checking for List of Tuple
|
|
elif isinstance(location, (list, tuple)):
|
|
self._check_for_list(location)
|
|
|
|
# Checking for Dictionary
|
|
elif isinstance(location, dict):
|
|
self._check_for_dict(location)
|
|
|
|
# Checking for a Geocoder Class
|
|
elif hasattr(location, 'latlng'):
|
|
if location.latlng:
|
|
self.lat, self.lng = location.latlng
|
|
|
|
# Result into Error
|
|
else:
|
|
raise ValueError("Unknown location: %s" % location)
|
|
|
|
def _check_for_list(self, location):
|
|
# Standard LatLng list or tuple with 2 number values
|
|
if len(location) == 2:
|
|
lat = self._convert_float(location[0])
|
|
lng = self._convert_float(location[1])
|
|
condition_1 = isinstance(lat, float)
|
|
condition_2 = isinstance(lng, float)
|
|
|
|
# Check if input are Floats
|
|
if condition_1 and condition_2:
|
|
condition_3 = -90 <= lat <= 90
|
|
condition_4 = -180 <= lng <= 180
|
|
|
|
# Check if inputs are within the World Geographical
|
|
# boundary (90,180,-90,-180)
|
|
if condition_3 and condition_4:
|
|
self.lat = lat
|
|
self.lng = lng
|
|
return self.lat, self.lng
|
|
else:
|
|
raise ValueError(
|
|
"Coords are not within the world's geographical boundary")
|
|
else:
|
|
raise ValueError("Coordinates must be numbers")
|
|
|
|
def _check_for_dict(self, location):
|
|
# Standard LatLng list or tuple with 2 number values
|
|
if 'lat' in location and 'lng' in location:
|
|
lat = location['lat']
|
|
lng = location['lng']
|
|
self._check_for_list([lat, lng])
|
|
|
|
if 'y' in location and 'x' in location:
|
|
lat = location['y']
|
|
lng = location['x']
|
|
self._check_for_list([lat, lng])
|
|
|
|
@property
|
|
def latlng(self):
|
|
if isinstance(self.lat, float) and isinstance(self.lng, float):
|
|
return [self.lat, self.lng]
|
|
return []
|
|
|
|
@property
|
|
def latitude(self):
|
|
return self.lat
|
|
|
|
@property
|
|
def longitude(self):
|
|
return self.lng
|
|
|
|
@property
|
|
def xy(self):
|
|
if isinstance(self.lat, float) and isinstance(self.lng, float):
|
|
return [self.lng, self.lat]
|
|
return []
|
|
|
|
def __str__(self):
|
|
if self.ok:
|
|
return u'{0}, {1}'.format(self.lat, self.lng)
|
|
return u''
|
|
|
|
|
|
class BBox(object):
|
|
"""BBox container"""
|
|
|
|
DEGREES_TOLERANCE = 0.5
|
|
|
|
@classmethod
|
|
def factory(cls, arg):
|
|
# validate input first
|
|
if not isinstance(arg, (list, dict)):
|
|
raise ValueError(
|
|
"BBox factory only accept a dict or a list as argument")
|
|
# we have a dict... just check which fields are given
|
|
if isinstance(arg, dict):
|
|
if 'southwest' in arg:
|
|
return cls(bounds=arg)
|
|
elif 'bbox' in arg:
|
|
return cls(bbox=arg['bbox'])
|
|
elif 'bounds' in arg:
|
|
return cls(bounds=arg['bounds'])
|
|
elif 'lat' in arg:
|
|
return cls(lat=arg['lat'], lng=arg['lng'])
|
|
elif 'west' in arg:
|
|
return cls(west=arg['west'], south=arg['south'],
|
|
east=arg['east'], north=arg['north'])
|
|
else:
|
|
raise ValueError(
|
|
"Could not found valid values in dict to create a bbox")
|
|
# we have a list... guess what to call according to the number of parameters given:
|
|
if len(arg) == 2:
|
|
lat, lng = arg
|
|
return cls(lat=lat, lng=lng)
|
|
elif len(arg) == 4:
|
|
return cls(bbox=arg)
|
|
else:
|
|
raise ValueError(
|
|
"Could not found valid values in list to create a bbox")
|
|
|
|
def __init__(self, bbox=None, bounds=None,
|
|
lat=None, lng=None,
|
|
west=None, south=None, east=None, north=None):
|
|
if bounds is not None and bounds.get('southwest') and bounds.get('northeast'):
|
|
self.south, self.west = map(float, bounds['southwest'])
|
|
self.north, self.east = map(float, bounds['northeast'])
|
|
elif bbox is not None and all(bbox):
|
|
self.west, self.south, self.east, self.north = map(float, bbox)
|
|
elif lat is not None and lng is not None:
|
|
self.south = float(lat) - self.DEGREES_TOLERANCE
|
|
self.north = float(lat) + self.DEGREES_TOLERANCE
|
|
self.west = float(lng) - self.DEGREES_TOLERANCE
|
|
self.east = float(lng) + self.DEGREES_TOLERANCE
|
|
elif all([west, south, east, north]):
|
|
self.west, self.south, self.east, self.north = map(
|
|
float, [west, south, east, north])
|
|
else:
|
|
raise ValueError("Could not create BBox/Bounds from given arguments")
|
|
|
|
@property
|
|
def lat(self):
|
|
return mean([self.south, self.north])
|
|
|
|
@property
|
|
def lng(self):
|
|
return mean([self.west, self.east])
|
|
|
|
@property
|
|
def latlng(self):
|
|
if isinstance(self.lat, float) and isinstance(self.lng, float):
|
|
return [self.lat, self.lng]
|
|
return []
|
|
|
|
@property
|
|
def latitude(self):
|
|
return self.lat
|
|
|
|
@property
|
|
def longitude(self):
|
|
return self.lng
|
|
|
|
@property
|
|
def xy(self):
|
|
if isinstance(self.lat, float) and isinstance(self.lng, float):
|
|
return [self.lng, self.lat]
|
|
return []
|
|
|
|
@property
|
|
def as_dict(self):
|
|
return {
|
|
'northeast': [self.north, self.east],
|
|
'southwest': [self.south, self.west]
|
|
}
|
|
|
|
|
|
if __name__ == '__main__':
|
|
l = Location([0.0, 0.0])
|
|
print(l.lng)
|