from rowers.courseutils import coursetime_paths, coursetime_first, time_in_path from rowers.models import ( Rower, Workout, GeoPoint, GeoPolygon, GeoCourse, course_length, course_coord_center, course_coord_maxmin, course_coord_crewnerd_navigation, 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 math 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 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 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: 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 get_polar_angle(point, reference_point): """ Calculate the polar angle of a point with respect to a reference point. """ try: delta_x = point.longitude - reference_point.longitude delta_y = point.latitude - reference_point.latitude except AttributeError: delta_x = point['longitude'] - reference_point.longitude delta_y = point['latitude'] - reference_point.latitude return math.atan2(delta_y, delta_x) class Coordinate: def __init__(self, latitude, longitude): self.latitude = latitude self.longitude = longitude def get_coordinates_centerpoint(coordinates): try: centroid_latitude = sum(coord.latitude for coord in coordinates) / len(coordinates) centroid_longitude = sum(coord.longitude for coord in coordinates) / len(coordinates) centroid = Coordinate(centroid_latitude, centroid_longitude) except AttributeError: centroid_latitude = sum(coord['latitude'] for coord in coordinates) / len(coordinates) centroid_longitude = sum(coord['longitude'] for coord in coordinates) / len(coordinates) centroid = Coordinate(centroid_latitude, centroid_longitude) return centroid def sort_coordinates_ccw(coordinates): """ Sort coordinates in counterclockwise order. """ # Find the reference point (centroid) centroid = get_coordinates_centerpoint(coordinates) # Sort coordinates based on polar angle with respect to the centroid sorted_coords = sorted(coordinates, key=lambda coord: get_polar_angle(coord, centroid)) return sorted_coords 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]), }) points = sort_coordinates_ccw(points) polygons.append({ 'name': name, 'points': points }) return polygons def crewnerdify(polygons): polygon_names = [] polygon_names.append("Start") for i in range(1,len(polygons)-1): polygon_name = 'WP{n}'.format(n=polygons[i].order_in_course) polygon_names.append(polygon_name) polygon_names.append("Finish") return polygon_names def removewhitespace(s): regels = s.split('\n') regels = [regel for regel in regels if regel.strip()] return "\n".join(regels) def getcoursefolder(course, document, cn=False): folder2 = SubElement(document, 'Folder', id="{id}".format(id=course.id)) coursename = SubElement(folder2, 'name') coursename.text = course.name openst = SubElement(folder2, 'open') openst.text = '1' coursedescription = SubElement(folder2, 'description') if len(removewhitespace(course.notes)): coursedescription.text = "Rowsandall.com\n" + removewhitespace(course.notes) else: coursedescription.text = "Rowsandall.com " + course.name polygons = GeoPolygon.objects.filter( course=course).order_by("order_in_course") polygon_names = [polygon.name for polygon in polygons] if cn: polygon_names = crewnerdify(polygons) for index, polygon in enumerate(polygons): placemark = SubElement(folder2, 'Placemark') polygonname = SubElement(placemark, 'name') polygonname.text = polygon_names[index] polygondescription = SubElement(placemark, 'description') polygondescription.text = polygon.name polygonstyle = SubElement(placemark, 'styleUrl') polygonstyle.text = "#default0" 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") points = sort_coordinates_ccw(points) 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 folder2 def getstyle(document, id): style = SubElement(document,'Style', id=id) iconstyle = SubElement(style, 'IconStyle') scale = SubElement(iconstyle, 'scale') scale.text = "1.2" linestyle = SubElement(style, 'LineStyle') linestylecolor = SubElement(linestyle, 'color') linestylecolor.text = "ff00ffff" polystyle = SubElement(style, 'PolyStyle') polystylecolor = SubElement(polystyle, 'color') polystylecolor.text = "ff7fffff" return style def getstylemap(document, id): stylemap = SubElement(document, 'StyleMap', id=id) pair1 = SubElement(stylemap, 'Pair') pair1key = SubElement(pair1, 'key') pair1key.text = "normal" pair1styleurl = SubElement(pair1, 'styleUrl') pair1styleurl.text = "#default" pair2 = SubElement(stylemap, 'Pair') pair2key = SubElement(pair2, 'key') pair2key.text = "highlight" pair2styleurl = SubElement(pair2, 'styleUrl') pair2styleurl.text = "#hl" return stylemap def coursestokml(courseids, cn=False): courses = GeoCourse.objects.filter(id__in=courseids) 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' opendoc = SubElement(document,'open') opendoc.text = '1' style = getstyle(document, "default") stylemap = getstylemap(document, 'default0') stylehl = getstyle(document, "hl") for course in courses: coursefolder = getcoursefolder(course, document, cn=cn) return prettify(top) def coursetokml(course,cn=False): 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' opendoc = SubElement(document,'open') opendoc.text = '1' style = getstyle(document, "default") stylemap = getstylemap(document, 'default0') stylehl = getstyle(document, "hl") coursefolder = getcoursefolder(course, document, cn=cn) 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 replacecourse(course1, course2): ps = PlannedSession.objects.filter(course=course1) for p in ps: p.course = course2 p.save() course1.delete() return 1