diff --git a/rowers/courses.py b/rowers/courses.py index 7fa3d8f9..3b21f110 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -22,6 +22,7 @@ import time from django.db import IntegrityError import uuid from django.conf import settings +import math import geocoder @@ -120,6 +121,50 @@ xmlns_uris_dict = {'gx': 'http://www.google.com/kml/ext/2.2', '': "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: @@ -162,6 +207,8 @@ def get_polygons(polygonpms): 'latitude': float(coordinates[1]), }) + points = sort_coordinates_ccw(points) + polygons.append({ 'name': name, 'points': points @@ -206,6 +253,7 @@ def coursetokml(course): 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, diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 4d5ff824..064a2033 100644 Binary files a/rowers/tests/testdata/testdata.tcx.gz and b/rowers/tests/testdata/testdata.tcx.gz differ diff --git a/rowers/urls.py b/rowers/urls.py index 6824aa6f..e179b99b 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -251,6 +251,7 @@ urlpatterns = [ name='strokedatajson_v3'), re_path(r'^api/TCX/workouts/$', views.strokedata_tcx, name='strokedata_tcx'), + re_path(r'^api/courses/$', views.course_list, name='course_list'), re_path(r'^500v/$', views.error500_view, name='error500_view'), re_path(r'^500q/$', views.servererror_view, name='servererror_view'), path('502/', TemplateView.as_view(template_name='502.html'), name='502'), diff --git a/rowers/views/apiviews.py b/rowers/views/apiviews.py index 4b07edbc..bdbb2782 100644 --- a/rowers/views/apiviews.py +++ b/rowers/views/apiviews.py @@ -235,6 +235,46 @@ def part_of_day(hour): else: return "Night" +# KML API views +""" +- Get a list of courses + - Nearby a certain coordinate + - Filtered by +- Get a (KML) course (in response.content rather than as attachment) +- Get multiple courses as one KML in response.content + - GET with parameters? +Optional, not for CN +- Create one or more new courses from KML + - Should check for duplicates (Placemark ID) +- Update one or more new courses from KML +""" +@api_view(["GET"]) +def course_list(request): + if request.method != 'GET': + dologging('apilog.log','{m} request to KML endpoint'.format(m=request.method)) + return HttpResponseNotAllower("Method not supported") + + courses = GeoCourse.objects.all() + courselist = [] + for c in courses: + d = { + 'id': c.id, + 'name':c.name, + 'country':c.country, + 'distance':c.distance, + 'notes':c.notes, + 'location':(c.coord[0], c.coord[1]), + } + courselist.append(d) + + response_dict = {'courses': courselist} + + print(response_dict) + + return JsonResponse(response_dict, content_type='application/json; charset=utf8') + +# Stroke data views + @csrf_exempt @login_required() @api_view(["POST"])