from rowers.courseutils import coursetime_paths, coursetime_first, time_in_path import pandas as pd 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.utils import geo_distance import rowers.dataprep as dataprep from timezonefinder import TimezoneFinder import numpy as np # 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=" ") 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"} 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