Private
Public Access
1
0
Files
rowsandall/rowers/courses.py
Sander Roosendaal 38aedc02ca bug fix
2018-02-25 09:18:13 +01:00

291 lines
7.3 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
import geocoder
from matplotlib import path
import xml.etree.ElementTree as et
import pandas as pd
import numpy as np
import dataprep
from rowers.utils import geo_distance
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
from rowers.models import (
Rower, Workout,
GeoPoint,GeoPolygon, GeoCourse,
course_length,course_coord_center,course_coord_maxmin,
polygon_coord_center
)
# low level methods
class InvalidTrajectoryError(Exception):
def __init__(self,value):
self.value=value
def __str__(self):
return repr(self.value)
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_path(latitude,longitude, p):
return p.contains_points([(latitude,longitude)])[0]
def time_in_path(df,p,maxmin='max'):
if df.empty:
return 0
latitude = df.latitude
longitude = df.longitude
f = lambda x: coordinate_in_path(x['latitude'],x['longitude'],p)
df['inpolygon'] = df.apply(f,axis=1)
if maxmin=='max':
b = (~df['inpolygon']).shift(-1)+df['inpolygon']
else:
b = (~df['inpolygon']).shift(1)+df['inpolygon']
if len(df[b==2]):
return df[b==2]['time'].min(),df[b==2]['cum_dist'].min()
raise InvalidTrajectoryError("Trajectory doesn't go through path")
return 0
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)
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:
latitude = point['latitude']
longitude = point['longitude']
g = geocoder.google([latitude,longitude],method='reverse')
if g.ok:
address = g.raw['address_components']
country = 'unknown'
for a in address:
if 'country' in a['types']:
country = a['long_name']
else:
country = 'unknown'
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_first(data,paths):
entrytime = data['time'].max()
entrydistance = data['cum_dist'].max()
coursecompleted = False
try:
entrytime,entrydistance = time_in_path(data,paths[0],maxmin='max')
coursecompleted = True
except InvalidTrajectoryError:
entrytime = data['time'].max()
entrydistance = data['cum_dist'].max()
coursecompleted = False
return entrytime, entrydistance, coursecompleted
def coursetime_paths(data,paths,finalmaxmin='min'):
entrytime = data['time'].max()
entrydistance = data['cum_dist'].max()
coursecompleted = False
# corner case - empty list of paths
if len(paths) == 0:
return 0,True
# end - just the Finish polygon
if len(paths) == 1:
try:
(
entrytime,
entrydistance
) = time_in_path(data,paths[0],maxmin=finalmaxmin)
coursecompleted = True
except InvalidTrajectoryError:
entrytime = data['time'].max()
entrydistance = data['cum_dist'].max()
coursecompleted = False
return entrytime,entrydistance,coursecompleted
if len(paths) > 1:
try:
time,dist = time_in_path(data, paths[0])
data = data[data['time']>time]
data['time'] = data['time']-time
data['cum_dist'] = data['cum_dist']-dist
(
timenext,
distnext,
coursecompleted
) = coursetime_paths(data,paths[1:])
return time+timenext, dist+distnext,coursecompleted
except InvalidTrajectoryError:
entrytime = data['time'].max()
entrydistance = data['cum_dist'].max()
coursecompleted = False
return entrytime, entrydistance, coursecompleted
def get_time_course(ws,course):
coursetimeseconds = 0.0
coursecompleted = 0
w = ws[0]
columns = ['time',' latitude',' longitude','cum_dist']
rowdata = dataprep.getsmallrowdata_db(
columns,
ids = [w.id],
doclean=False,
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)
paths = []
for polygon in polygons:
path = polygon_to_path(polygon)
paths.append(path)
(
coursetimeseconds,
coursemeters,
coursecompleted,
) = coursetime_paths(rowdata,paths)
(
coursetimefirst,
coursemetersfirst,
firstcompleted
) = coursetime_first(
rowdata,paths)
coursetimeseconds = coursetimeseconds-coursetimefirst
coursemeters = coursemeters-coursemetersfirst
return coursetimeseconds,coursemeters,coursecompleted