Private
Public Access
1
0
Files
rowsandall/rowers/courses.py
2018-02-21 18:32:18 +01:00

298 lines
7.4 KiB
Python

# All the Courses related methods
# Python
from django.utils import timezone
from datetime import datetime
from datetime import timedelta
import time
from django.db import IntegrityError
import uuid
from django.conf import settings
from matplotlib import path
import xml.etree.ElementTree as et
import pandas as pd
import numpy as np
import dataprep
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
from rowers.models import (
Rower, Workout,
GeoPoint,GeoPolygon, GeoCourse,
)
# low level methods
class InvalidTrajectoryError(Exception):
def __init__(self,value):
self.value=value
def __str__(self):
return repr(self.value)
def polygon_coord_center(polygon):
points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
latitudes = pd.Series([p.latitude for p in points])
longitudes = pd.Series([p.longitude for p in points])
return latitudes.mean(), longitudes.mean()
def course_coord_center(course):
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
latitudes = []
longitudes = []
for p in polygons:
latitude,longitude = polygon_coord_center(p)
latitudes.append(latitude)
longitudes.append(longitude)
latitude = pd.Series(latitudes).median()
longitude = pd.Series(longitudes).median()
coordinates = pd.DataFrame({
'latitude':latitudes,
'longitude':longitudes,
})
return latitude,longitude,coordinates
def course_coord_maxmin(course):
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
latitudes = []
longitudes = []
for p in polygons:
latitude,longitude = polygon_coord_center(p)
latitudes.append(latitude)
longitudes.append(longitude)
lat_min = pd.Series(latitudes).min()
lat_max = pd.Series(latitudes).max()
long_min = pd.Series(longitudes).min()
long_max = pd.Series(longitudes).max()
return lat_min,lat_max,long_min,long_max
def polygon_to_path(polygon):
points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
s = []
for point in points:
s.append([point.latitude,point.longitude])
p = path.Path(s[:-1])
return p
def coordinate_in_polygon(latitude,longitude, polygon):
p = polygon_to_path(polygon)
return p.contains_points([(latitude,longitude)])[0]
def time_in_polygon(df,polygon,maxmin='max'):
if df.empty:
return 0
# df has timestamp, latitude, longitude
p = polygon_to_path(polygon)
latitude = df.latitude
longitude = df.longitude
f = lambda x: coordinate_in_polygon(x['latitude'],x['longitude'],polygon)
df['inpolygon'] = df.apply(f,axis=1)
mask = df['inpolygon'] == True
if df[mask].empty:
print polygon.name
raise InvalidTrajectoryError("Trajectory doesn't go through {name}".format(name=polygon.name))
if maxmin == 'max':
time = df[mask]['time'].max()
else:
time = df[mask]['time'].min()
return time
def crewnerdcourse(doc):
courses = []
for course in doc:
name = course.findall('.//opengis:name',ns)[0].text
try:
description = course.findall('.//opengis:description',ns)[0].text
except IndexError:
description = ''
polygonpms = course.findall('.//opengis:Placemark[opengis:Polygon]',ns)
polygons = get_polygons(polygonpms)
courses.append({
'name':name,
'description':description,
'polygons':polygons
})
return courses
def get_polygons(polygonpms):
polygons = []
for pm in polygonpms:
name = pm.findall('.//opengis:name',ns)[0].text
coordinates = pm.findall('.//opengis:coordinates',ns)
if coordinates:
cc = coordinates[0].text
else:
cc = ''
pointstring = cc.split()
points = []
for s in pointstring:
coordinates = s.split(',')
points.append({
'longitude':float(coordinates[0]),
'latitude':float(coordinates[1]),
})
polygons.append({
'name':name,
'points':points
})
return polygons
def kmltocourse(f):
doc = et.parse(f)
courses = doc.findall('.//opengis:Folder[opengis:Placemark]',ns)
if courses:
return crewnerdcourse(courses)
polygonpms = doc.findall('.//opengis:Placemark[opengis:Polygon]',ns)
return get_polygons(polygonpms)
from geopy.geocoders import Nominatim
geolocator = Nominatim()
def createcourse(
manager,name,polygons,notes=''):
c = GeoCourse(manager=manager,name=name,notes=notes)
c.save()
i = 0
for p in polygons:
pp = GeoPolygon(course=c,order_in_course=i,name=p['name'])
pp.save()
j = 0
for point in p['points']:
if i==0 and j==0:
loc = geolocator.reverse((point['latitude'],point['longitude']))
country = loc.raw['address']['country']
if isinstance(country,unicode):
country = country.encode('utf8')
elif isinstance(country, str):
country = country.decode('utf8')
c.country = country
c.save()
obj = GeoPoint(
latitude = point['latitude'],
longitude = point['longitude'],
polygon = pp,
order_in_poly = j
)
obj.save()
j += 1
i += 1
return c
def coursetime_polygons(data,polygons):
entrytime = data['time'].max()
coursecompleted = False
# corner case - empty list of polygons
if len(polygons) == 0:
return 0,True
# end - just the Finish polygon
if len(polygons) == 1:
try:
entrytime = time_in_polygon(data,polygons[0],maxmin='min')
coursecompleted = True
print entrytime,polygons[0].name
except InvalidTrajectoryError:
entrytime = data['time'].max()
coursecompleted = False
return entrytime,coursecompleted
if len(polygons) > 1:
try:
time = time_in_polygon(data, polygons[0])
data = data[data['time']>time]
data['time'] = data['time']-time
print time,polygons[0].name
timenext, coursecompleted = coursetime_polygons(data,polygons[1:])
return time+timenext, coursecompleted
except InvalidTrajectoryError:
entrytime = data['time'].max()
coursecompleted = False
return entrytime, coursecompleted
def get_time_course(ws,course):
coursetimeseconds = 0.0
coursecompleted = 0
w = ws[0]
columns = ['time',' latitude',' longitude']
rowdata = dataprep.getsmallrowdata_db(
columns,
ids = [w.id],
doclean=True,
workstrokesonly=False
)
rowdata.rename(columns = {
' latitude':'latitude',
' longitude':'longitude',
}, inplace=True)
rowdata['time'] = rowdata['time']/1000.
rowdata.fillna(method='backfill',inplace=True)
rowdata['time'] = rowdata['time']-rowdata.ix[0,'time']
# we may want to expand the time (interpolate)
polygons = GeoPolygon.objects.filter(course=course)
coursetimeseconds,coursecompleted = coursetime_polygons(rowdata,polygons)
return coursetimeseconds,coursecompleted