Private
Public Access
1
0
Files
rowsandall/rowers/courses.py
Sander Roosendaal 03edc5a57f some refinements
2021-10-08 17:11:23 +02:00

355 lines
9.5 KiB
Python

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# 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
from xml.etree.ElementTree import Element, SubElement, Comment, tostring
from xml.dom import minidom
from rowers.models import VirtualRace
# distance of course from lat_lon in km
def howfaris(lat_lon,course):
coords = course.coord
distance = geo_distance(lat_lon[0],lat_lon[1],coords[0],coords[1])[0]
return distance
#whatisnear = 150
# get nearest races
def getnearestraces(lat_lon,races,whatisnear=150):
newlist = []
counter = 0
for race in races:
if race.course is None: # pragma: no cover
newlist.append(race)
else:
c = race.course
coords = c.coord
distance = howfaris(lat_lon,c)
if distance < whatisnear:
newlist.append(race)
counter += 1
if counter>0:
races = newlist
else:
courseraces = races.exclude(course__isnull=True)
orders = [(c.id,howfaris(lat_lon,c.course)) for c in courseraces]
orders = sorted(orders,key = lambda tup:tup[1])
ids = [id for id,distance in orders[0:4]]
for id, distance in orders[5:]: # pragma: no cover
if distance<whatisnear:
ids.append(id)
for id in ids:
newlist.append(VirtualRace.objects.get(id=id))
races = newlist
return races
def getnearestcourses(lat_lon,courses,whatisnear=150,strict=False):
newlist = []
counter = 0
for c in courses:
coords = c.coord
distance = howfaris(lat_lon,c)
if distance < whatisnear:
newlist.append(c)
counter += 1
if counter>0:
courses = newlist
elif strict:
courses = newlist
else:
orders = [(c.id,howfaris(lat_lon,c)) for c in courses]
orders = sorted(orders,key = lambda tup:tup[1])
ids = [id for id,distance in orders[0:4]]
for id, distance in orders[5:]:
if distance<whatisnear: # pragma: no cover
ids.append(id)
for id in ids:
newlist.append(GeoCourse.objects.get(id=id))
courses = newlist
return courses
def prettify(elem):
"""Return a pretty-printed XML string for the Element.
"""
rough_string = tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent=" ")
import pandas as pd
import numpy as np
from timezonefinder import TimezoneFinder
import rowers.dataprep as dataprep
from rowers.utils import geo_distance
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
xmlns_uris_dict = {'gx': 'http://www.google.com/kml/ext/2.2',
'kml': 'http://www.google.com/kml/ext/2.2',
'atom': "http://www.w3.org/2005/Atom",
'': "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,PlannedSession,
polygon_to_path,coordinate_in_path
)
from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path
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: # pragma: no cover
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 coursetokml(course):
top = Element('kml')
for prefix, uri in xmlns_uris_dict.items():
if prefix != '':
top.attrib['xmlns:' + prefix] = uri
else:
top.attrib['xmlns'] = uri
document = SubElement(top,'Document')
name = SubElement(document, 'name')
name.text = 'Courses.kml'
folder = SubElement(document,'Folder')
foldername = SubElement(folder,'name')
foldername.text = 'Courses'
folder2 = SubElement(folder,'Folder')
coursename = SubElement(folder2,'name')
coursename.text = course.name
open = SubElement(folder2,'open')
open.text = '1'
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
polygonsxml = []
for polygon in polygons:
placemark = SubElement(folder2,'Placemark')
polygonname = SubElement(placemark,'name')
polygonname.text = polygon.name
p = SubElement(placemark,'Polygon')
tessellate = SubElement(p,'tessellate')
tessellate.text = '1'
boundary = SubElement(p,'outerBoundaryIs')
ring = SubElement(boundary,'LinearRing')
coordinates = SubElement(ring,'coordinates')
coordinates.text = ''
points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
for point in points:
coordinates.text += '{lon},{lat},0 '.format(
lat = point.latitude,
lon = point.longitude,
)
coordinates.text += '{lon},{lat},0'.format(
lat = points[0].latitude,
lon = points[0].longitude,
)
return prettify(top)
def kmltocourse(f):
doc = et.parse(f)
courses = doc.findall('.//opengis:Folder[opengis:Placemark]',ns)
if not courses: # pragma: no cover
courses = doc.findall('.//opengis:Document[opengis:Placemark]',ns)
if not courses:
courses = doc.findall('.//opengis:Placemark',ns)
if courses:
return crewnerdcourse(courses)
polygonpms = doc.findall('.//opengis:Placemark[opengis:Polygon]',ns) # pragma: no cover
return get_polygons(polygonpms) # pragma: no cover
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.osm([latitude,longitude],method='reverse')
if g.ok:
country = g.json['country']
else: # pragma: no cover
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
c.distance = int(course_length(c))
c.save()
return c
def get_time_course(ws,course): # pragma: no cover
coursetimeseconds = 0.0
coursecompleted = False
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)
rowdata['dt'] = rowdata['time'].apply(
lambda x: timedelta(seconds=x)
)
rowdata = rowdata.resample('100ms',on='dt').mean()
rowdata = rowdata.interpolate()
# create path
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_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
def replacecourse(course1,course2):
ps = PlannedSession.objects.filter(course=course1)
for p in ps:
p.course = course2
p.save()
course1.delete()
return 1