GetTogether/events/location.py

106 lines
3.5 KiB
Python

from django.utils import timezone
from django.conf import settings
from .models.locale import City
from .ipstack import get_ipstack_geocoder
import math
import pytz
import geocoder
KM_PER_DEGREE_LAT = 110.574
KM_PER_DEGREE_LNG = 111.320 # At the equator
DEFAULT_NEAR_DISTANCE = 100 # kilometeres
class TimezoneChoices():
def __iter__(self):
for tz in pytz.all_timezones:
yield (tz, tz)
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
def get_geoip(request):
client_ip = get_client_ip(request)
if client_ip == '127.0.0.1' or client_ip == 'localhost':
if settings.DEBUG:
client_ip = getattr(settings, 'DEBUG_IP', '8.8.8.8') # Try Debug ip
print("Client is localhost, using %s for geoip instead" % client_ip)
else:
raise Exception("Client is localhost")
g = get_ipstack_geocoder(client_ip)
return g
def get_bounding_box(center, radius):
minlat = center[0]-(radius/KM_PER_DEGREE_LAT)
maxlat = center[0]+(radius/KM_PER_DEGREE_LAT)
minlng = center[1]-(radius/(KM_PER_DEGREE_LNG*math.cos(math.radians(center[0]))))
maxlng = center[1]+(radius/(KM_PER_DEGREE_LNG*math.cos(math.radians(center[0]))))
return (minlat, maxlat, minlng, maxlng)
def distance(center1, center2):
avglat = (center2[0] + center1[0])/2
dlat = (center2[0] - center1[0]) * KM_PER_DEGREE_LAT
dlng = (center2[1] - center1[1]) * (KM_PER_DEGREE_LNG*math.cos(math.radians(avglat)))
dkm = math.sqrt((dlat*dlat) + (dlng*dlng))
return dkm
def city_distance_from(ll, city):
if ll is None:
return 0
if city is not None and city.latitude is not None and city.longitude is not None:
return distance((ll), (city.latitude, city.longitude))
else:
return 99999
def team_distance_from(ll, team):
if ll is None:
return 0
if team.city is not None:
return city_distance_from(ll, team.city)
else:
return 99999
def event_distance_from(ll, event):
if ll is None:
return 0
if event.place is not None and event.place.latitude is not None and event.place.longitude is not None:
return distance((ll), (event.place.latitude, event.place.longitude))
if event.team is not None:
return team_distance_from(ll, event.team)
else:
return 99999
def searchable_distance_from(ll, searchable):
if ll is None:
return 0
if searchable.latitude is not None and searchable.longitude is not None:
return distance((ll), (float(searchable.latitude), float(searchable.longitude)))
else:
return 99999
def get_nearest_city(ll, max_distance=100):
if ll is None:
return None
city = None
city_distance = 1 #km
while city is None and city_distance <= max_distance:
minlat = ll[0]-(city_distance/KM_PER_DEGREE_LAT)
maxlat = ll[0]+(city_distance/KM_PER_DEGREE_LAT)
minlng = ll[1]-(city_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(ll[0]))))
maxlng = ll[1]+(city_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(ll[0]))))
nearby_cities = City.objects.filter(latitude__gte=minlat, latitude__lte=maxlat, longitude__gte=minlng, longitude__lte=maxlng)
if len(nearby_cities) == 0:
city_distance += 1
else:
return sorted(nearby_cities, key=lambda city: city_distance_from(ll, city))[0]
return city