From 0f1f64220d43cc3e094db0f82e590ec0cadf05d6 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 10 May 2018 17:09:46 +0200 Subject: [PATCH 01/11] removed print statement --- rowers/interactiveplots.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index c9cd7d25..efbb5dbf 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2208,8 +2208,6 @@ def interactive_chart(id=0,promember=0): script, div = components(plot) - print div,"aap" - return [script,div] def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', From 7f3f41dab043a1b3329451beb0dff19de4b11bd3 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 11 May 2018 13:45:17 +0200 Subject: [PATCH 02/11] some form checks on race creation --- rowers/.#plannedsessions.py | 1 + rowers/models.py | 84 ++++++++++++++++++++++++++++++++++++- rowers/views.py | 1 - 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 rowers/.#plannedsessions.py diff --git a/rowers/.#plannedsessions.py b/rowers/.#plannedsessions.py new file mode 100644 index 00000000..25407209 --- /dev/null +++ b/rowers/.#plannedsessions.py @@ -0,0 +1 @@ +e408191@CZ27LT9RCGN72.63076:1525965015 \ No newline at end of file diff --git a/rowers/models.py b/rowers/models.py index db5795ed..bbcde970 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -29,6 +29,7 @@ import datetime from django.core.exceptions import ValidationError from rowers.rows import validate_file_extension from collections import OrderedDict +from timezonefinder import TimezoneFinder import types @@ -1104,6 +1105,35 @@ class VirtualRace(PlannedSession): return stri + + def save(self, *args, **kwargs): + # test race window logic + + start_time = self.start_time + start_date = self.startdate + startdatetime = datetime.datetime.combine(start_date,start_time) + startdatetime = pytz.timezone(self.timezone).localize( + startdatetime + ) + + end_time = self.end_time + end_date = self.enddate + enddatetime = datetime.datetime.combine(end_date,end_time) + enddatetime = pytz.timezone(self.timezone).localize( + enddatetime + ) + + if startdatetime > enddatetime: + self.start_time = end_time + self.startdate = end_date + self.end_time = start_time + self.enddate = start_date + enddatetime = startdatetime + + if self.evaluation_closure < enddatetime: + self.evaluation_closure = enddatetime + timezone.timedelta(days=1) + + super(VirtualRace,self).save(*args, **kwargs) # Date input utility @@ -1142,7 +1172,27 @@ class PlannedSessionForm(ModelForm): def __init__(self,*args,**kwargs): super(PlannedSessionForm, self).__init__(*args, **kwargs) self.fields['course'].queryset = GeoCourse.objects.all().order_by("country","name") - + +def get_course_timezone(course): + polygons = GeoPolygon.objects.filter(course = course) + points = GeoPoint.objects.filter(polygon = polygons[0]) + lat = points[0].latitude + lon = points[0].longitude + + tf = TimezoneFinder() + try: + timezone_str = tf.timezone_at(lng=lon,lat=lat) + except ValueError: + timezone_str = 'UTC' + + if timezone_str is None: + timezone_str = tf.closest_timezone_at(lng=lon,lat=lat) + if timezone_str is None: + timezone_str = 'UTC' + + return timezone_str + + class VirtualRaceForm(ModelForm): course = forms.ModelChoiceField(queryset = GeoCourse.objects, empty_label=None) registration_closure = forms.SplitDateTimeField(widget=AdminSplitDateTime(),required=False) @@ -1187,6 +1237,38 @@ class VirtualRaceForm(ModelForm): self.fields['course'].queryset = GeoCourse.objects.all().order_by("country","name") + def clean(self): + cd = self.cleaned_data + course = cd['course'] + geocourse = GeoCourse.objects.get(id=course.id) + timezone_str = get_course_timezone(geocourse) + + start_time = cd['start_time'] + start_date = cd['startdate'] + startdatetime = datetime.datetime.combine(start_date,start_time) + startdatetime = pytz.timezone(timezone_str).localize( + startdatetime + ) + + end_time = cd['end_time'] + end_date = cd['enddate'] + enddatetime = datetime.datetime.combine(end_date,end_time) + enddatetime = pytz.timezone(timezone_str).localize( + enddatetime + ) + + + if startdatetime > enddatetime: + raise forms.ValidationError("The Start of the Race Window should be before the End of the Race Window") + + if cd['evaluation_closure'] <= enddatetime: + raise forms.ValidationError("Evaluation closure deadline should be after the Race Window closes") + + if cd['evaluation_closure'] <= timezone.now(): + raise forms.ValidationError("Evaluation closure cannot be in the past") + + + return cleaned_data class PlannedSessionFormSmall(ModelForm): diff --git a/rowers/views.py b/rowers/views.py index 20dba719..69835e92 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -13588,7 +13588,6 @@ def virtualevent_create_view(request): startdatetime = datetime.datetime.combine(startdate,start_time) enddatetime = datetime.datetime.combine(enddate,end_time) - print enddatetime startdatetime = pytz.timezone(timezone_str).localize( startdatetime From 385254342d5fe636a572596b1d2cd92b17cf89ba Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 11 May 2018 16:41:56 +0200 Subject: [PATCH 03/11] first attempt --- rowers/.#plannedsessions.py | 1 - rowers/courses.py | 55 ++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) delete mode 100644 rowers/.#plannedsessions.py diff --git a/rowers/.#plannedsessions.py b/rowers/.#plannedsessions.py deleted file mode 100644 index 25407209..00000000 --- a/rowers/.#plannedsessions.py +++ /dev/null @@ -1 +0,0 @@ -e408191@CZ27LT9RCGN72.63076:1525965015 \ No newline at end of file diff --git a/rowers/courses.py b/rowers/courses.py index 171e906e..06de3b98 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -31,6 +31,8 @@ from rowers.models import ( polygon_coord_center,PlannedSession ) +from utils import geo_distance + # low level methods class InvalidTrajectoryError(Exception): def __init__(self,value): @@ -39,6 +41,57 @@ class InvalidTrajectoryError(Exception): def __str__(self): return repr(self.value) +def get_dir_vector(polygon1,polygon2): + lat1,lon1 = polygon_coord_center(polygon1) + lat2,lon2 = polygon_coord_center(polygon2) + + return [[lat1,lon1],[lat2,lon2]] + +def get_delta(vector,polygon): + x = pd.Series(range(10000))/9999. + lat1 = vector[0][0] + lon1 = vector[0][1] + lat2 = vector[1][0] + lon2 = vector[1][0] + + lat = x.apply(lambda x:lat1+x*(lat2-lat1)) + lon = x.apply(lambda x:lon1+x*(lon2-lon1)) + + totdist,bearing = geo_distance(lat1,lon1,lat2,lon2) + + dist = x*totdist + + p = polygon_to_path(polygon) + + f = lambda x: coordinate_in_path(x['lat'],x['lon'],p) + + df = pd.DataFrame({'x':x, + 'lat':lat, + 'lon':lon, + 'dist':dist, + }) + + df['inpolygon'] = df.apply(f,axis=1) + + b = (~df['inpolygon']).shift(1)+df['inpolygon'] + + if len(df[b==2]): + return df[b==2]['dist'].min() + + else: + return 0 + + + + + +def get_delta_start(course): + polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") + vector = get_dir_vector(polygons[0],polygons[1]) + delta = get_delta(vector,polygons[0]) + + return delta + def get_course_timezone(course): polygons = GeoPolygon.objects.filter(course = course) points = GeoPoint.objects.filter(polygon = polygons[0]) @@ -293,7 +346,7 @@ def get_time_course(ws,course): rowdata = rowdata.resample('100ms',on='dt').mean() rowdata = rowdata.interpolate() - polygons = GeoPolygon.objects.filter(course=course) + polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") paths = [] for polygon in polygons: path = polygon_to_path(polygon) From 9e0f4f8aeab4375a680f18f4e3266c3373434ed9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 11:01:54 +0200 Subject: [PATCH 04/11] typo in session create --- rowers/templates/plannedsessioncreate.html | 2 +- rowers/templates/plannedsessionedit.html | 5 +++-- rowers/urls.py | 2 +- rowers/views.py | 8 +++++++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/rowers/templates/plannedsessioncreate.html b/rowers/templates/plannedsessioncreate.html index 1d48baba..d803e32c 100644 --- a/rowers/templates/plannedsessioncreate.html +++ b/rowers/templates/plannedsessioncreate.html @@ -103,7 +103,7 @@ Edit - Clone + Clone diff --git a/rowers/templates/plannedsessionedit.html b/rowers/templates/plannedsessionedit.html index e1bbedb3..deb11173 100644 --- a/rowers/templates/plannedsessionedit.html +++ b/rowers/templates/plannedsessionedit.html @@ -96,8 +96,9 @@ Edit - Clone - + Clone + Delete diff --git a/rowers/urls.py b/rowers/urls.py index b207fa47..23117eac 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -463,9 +463,9 @@ urlpatterns = [ url(r'^sessions/multicreate/(?P[\w\ ]+.*)$', views.plannedsession_multicreate_view), - url(r'^sessions/(?P\d+)/edit$',views.plannedsession_edit_view), url(r'^sessions/(?P\d+)/edit/(?P[\w\ ]+.*)/rower/(?P\d+)$',views.plannedsession_edit_view), url(r'^sessions/(?P\d+)/edit/(?P[\w\ ]+.*)$',views.plannedsession_edit_view), + url(r'^sessions/(?P\d+)/edit$',views.plannedsession_edit_view), url(r'^sessions/(?P\d+)/clone$',views.plannedsession_clone_view), url(r'^sessions/(?P\d+)/clone/(?P[\w\ ]+.*)/rower/(?P\d+)$',views.plannedsession_clone_view), diff --git a/rowers/views.py b/rowers/views.py index e3f056f7..29b1e8bc 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -10819,7 +10819,13 @@ def workout_split_view(request,id=id): splitsecond += splittime.second splitsecond += splittime.microsecond/1.e6 splitmode = form.cleaned_data['splitmode'] - ids,mesgs = dataprep.split_workout(r,row,splitsecond,splitmode) + try: + ids,mesgs = dataprep.split_workout( + r,row,splitsecond,splitmode + ) + except IndexError: + messages.error("Something went wrong in Split") + for message in mesgs: messages.info(request,message) From 7434a242aaa05af0d1b7e35f1817364cae55b4ef Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 13:01:26 +0200 Subject: [PATCH 05/11] adding course length to info --- rowers/.#plannedsessions.py | 1 - rowers/templates/list_courses.html | 4 ++++ rowers/templatetags/rowerfilters.py | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) delete mode 100644 rowers/.#plannedsessions.py diff --git a/rowers/.#plannedsessions.py b/rowers/.#plannedsessions.py deleted file mode 100644 index 25407209..00000000 --- a/rowers/.#plannedsessions.py +++ /dev/null @@ -1 +0,0 @@ -e408191@CZ27LT9RCGN72.63076:1525965015 \ No newline at end of file diff --git a/rowers/templates/list_courses.html b/rowers/templates/list_courses.html index 597931f9..5505a2ef 100644 --- a/rowers/templates/list_courses.html +++ b/rowers/templates/list_courses.html @@ -28,6 +28,7 @@ Country Name + Distance @@ -41,6 +42,9 @@ {{ course.name }} {% endif %} + + {{ course|courselength }} m + diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 88342bea..80e888a7 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -7,6 +7,7 @@ import json import datetime register = template.Library() from rowers.utils import calculate_age +from rowers.models import course_length from rowers.plannedsessions import ( race_can_register, race_can_submit,race_rower_status ) @@ -75,7 +76,10 @@ def deltatimeprint(d): else: return strfdeltah(d) - +@register.filter +def courselength(course): + return course_length(course) + @register.filter(is_safe=True) def jsdict(dict,key): s = dict.get(key) From c1b05a579b08161c5fabafb9b7885e76ec682901 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 15:16:27 +0200 Subject: [PATCH 06/11] better page title virtualevent --- rowers/templates/virtualevent.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 8fe2c290..36d75779 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -2,7 +2,7 @@ {% load staticfiles %} {% load rowerfilters %} -{% block title %}New Virtual Race{% endblock %} +{% block title %}Rowsandall Virtual Race{% endblock %} {% block content %} From 22f412c85a0a8612b101ba1d929fb058dc2dae2a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 18:15:05 +0200 Subject: [PATCH 07/11] save --- rowers/courses.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rowers/courses.py b/rowers/courses.py index 06de3b98..3f2b84e2 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -81,10 +81,7 @@ def get_delta(vector,polygon): else: return 0 - - - - + def get_delta_start(course): polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") vector = get_dir_vector(polygons[0],polygons[1]) From 34ccc51c37808a469902960925afd439f6f7cea4 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 21:14:09 +0200 Subject: [PATCH 08/11] some improvements --- rowers/courses.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/rowers/courses.py b/rowers/courses.py index 3f2b84e2..a1532e98 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -45,19 +45,20 @@ def get_dir_vector(polygon1,polygon2): lat1,lon1 = polygon_coord_center(polygon1) lat2,lon2 = polygon_coord_center(polygon2) - return [[lat1,lon1],[lat2,lon2]] + return [lat2-lat1,lon2-lon1] def get_delta(vector,polygon): x = pd.Series(range(10000))/9999. - lat1 = vector[0][0] - lon1 = vector[0][1] - lat2 = vector[1][0] - lon2 = vector[1][0] + vlat = vector[0] + vlon = vector[1] - lat = x.apply(lambda x:lat1+x*(lat2-lat1)) - lon = x.apply(lambda x:lon1+x*(lon2-lon1)) + lat1,lon1 = polygon_coord_center(polygon) + + lat = x.apply(lambda x:lat1+x*vlat) + lon = x.apply(lambda x:lon1+x*vlon) - totdist,bearing = geo_distance(lat1,lon1,lat2,lon2) + totdist,bearing = geo_distance(lat1,lon1,lat1+vlat,lon1+vlat) + print totdist dist = x*totdist @@ -73,10 +74,12 @@ def get_delta(vector,polygon): df['inpolygon'] = df.apply(f,axis=1) - b = (~df['inpolygon']).shift(1)+df['inpolygon'] + + b = (~df['inpolygon']).shift(-1)+df['inpolygon'] + if len(df[b==2]): - return df[b==2]['dist'].min() + return 1.0e3*df[b==2]['dist'].min() else: return 0 From 2a73239bca215be533b2fe47fa966cb22119d941 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 21:39:15 +0200 Subject: [PATCH 09/11] more precise course length --- rowers/courses.py | 66 ++------------------------------------ rowers/models.py | 80 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/rowers/courses.py b/rowers/courses.py index a1532e98..16c3f7cd 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -28,7 +28,8 @@ from rowers.models import ( Rower, Workout, GeoPoint,GeoPolygon, GeoCourse, course_length,course_coord_center,course_coord_maxmin, - polygon_coord_center,PlannedSession + polygon_coord_center,PlannedSession, + polygon_to_path,coordinate_in_path ) from utils import geo_distance @@ -41,56 +42,6 @@ class InvalidTrajectoryError(Exception): def __str__(self): return repr(self.value) -def get_dir_vector(polygon1,polygon2): - lat1,lon1 = polygon_coord_center(polygon1) - lat2,lon2 = polygon_coord_center(polygon2) - - return [lat2-lat1,lon2-lon1] - -def get_delta(vector,polygon): - x = pd.Series(range(10000))/9999. - vlat = vector[0] - vlon = vector[1] - - lat1,lon1 = polygon_coord_center(polygon) - - lat = x.apply(lambda x:lat1+x*vlat) - lon = x.apply(lambda x:lon1+x*vlon) - - totdist,bearing = geo_distance(lat1,lon1,lat1+vlat,lon1+vlat) - print totdist - - dist = x*totdist - - p = polygon_to_path(polygon) - - f = lambda x: coordinate_in_path(x['lat'],x['lon'],p) - - df = pd.DataFrame({'x':x, - 'lat':lat, - 'lon':lon, - 'dist':dist, - }) - - df['inpolygon'] = df.apply(f,axis=1) - - - b = (~df['inpolygon']).shift(-1)+df['inpolygon'] - - - if len(df[b==2]): - return 1.0e3*df[b==2]['dist'].min() - - else: - return 0 - - -def get_delta_start(course): - polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") - vector = get_dir_vector(polygons[0],polygons[1]) - delta = get_delta(vector,polygons[0]) - - return delta def get_course_timezone(course): polygons = GeoPolygon.objects.filter(course = course) @@ -111,19 +62,6 @@ def get_course_timezone(course): return timezone_str -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] diff --git a/rowers/models.py b/rowers/models.py index bbcde970..2a8b8fcc 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -32,7 +32,7 @@ from collections import OrderedDict from timezonefinder import TimezoneFinder import types - +from matplotlib import path from rowsandall_app.settings import ( TWEET_ACCESS_TOKEN_KEY, @@ -363,6 +363,19 @@ def polygon_coord_center(polygon): +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 course_coord_center(course): @@ -407,6 +420,62 @@ def course_coord_maxmin(course): return lat_min,lat_max,long_min,long_max +def get_dir_vector(polygon1,polygon2): + lat1,lon1 = polygon_coord_center(polygon1) + lat2,lon2 = polygon_coord_center(polygon2) + + return [lat2-lat1,lon2-lon1] + +def get_delta(vector,polygon): + x = pd.Series(range(10000))/9999. + vlat = vector[0] + vlon = vector[1] + + lat1,lon1 = polygon_coord_center(polygon) + + lat = x.apply(lambda x:lat1+x*vlat) + lon = x.apply(lambda x:lon1+x*vlon) + + totdist,bearing = geo_distance(lat1,lon1,lat1+vlat,lon1+vlon) + + dist = x*totdist + + p = polygon_to_path(polygon) + + f = lambda x: coordinate_in_path(x['lat'],x['lon'],p) + + df = pd.DataFrame({'x':x, + 'lat':lat, + 'lon':lon, + 'dist':dist, + }) + + df['inpolygon'] = df.apply(f,axis=1) + + + b = (~df['inpolygon']).shift(-1)+df['inpolygon'] + + + if len(df[b==2]): + return 1.0e3*df[b==2]['dist'].min() + + else: + return 0 + + +def get_delta_start(course): + polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") + vector = get_dir_vector(polygons[0],polygons[1]) + delta = get_delta(vector,polygons[0]) + + return delta + +def get_delta_finish(course): + polygons = GeoPolygon.objects.filter(course=course).order_by("-order_in_course") + vector = get_dir_vector(polygons[0],polygons[1]) + delta = get_delta(vector,polygons[0]) + + return delta def course_length(course): polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") @@ -421,7 +490,14 @@ def course_length(course): totaldist += 1000.*dist[0] - return int(totaldist) + vector = get_dir_vector(polygons[0],polygons[1]) + deltastart = get_delta(vector,polygons[0]) + + polygons = polygons.reverse() + vector = get_dir_vector(polygons[0],polygons[1]) + deltafinish = get_delta(vector,polygons[0]) + + return int(totaldist-deltastart-deltafinish) sexcategories = ( ('male','male'), From 16754ca19057932cd69281d86f2239afcbd5cea7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 14 May 2018 21:46:42 +0200 Subject: [PATCH 10/11] added unicode method to GeoPolygon model --- rowers/models.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 2a8b8fcc..eb6bad4d 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -842,9 +842,10 @@ class GeoCourse(models.Model): name = self.name country = self.country - return u'{country} - {name}'.format( + return u'{country} - {name} - {d}m'.format( name=name, - country=country + country=country, + d = course_length(self) ) class GeoCourseEditForm(ModelForm): @@ -861,6 +862,16 @@ class GeoPolygon(models.Model): course = models.ForeignKey(GeoCourse, blank=True) order_in_course = models.IntegerField(default=0) + def __unicode__(self): + name = self.name + coursename = self.course.name + + return u'{coursename} - {name}'.format( + name=name, + course=coursename + ) + + # Need error checking to insert new polygons into existing course (all later polygons # increase there order_in_course number From 26b6a6e29c4393b8c68589933adda0c4e4315a45 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 15 May 2018 10:17:55 +0200 Subject: [PATCH 11/11] courses defined by spline and other improvements --- rowers/interactiveplots.py | 4 +++ rowers/models.py | 50 ++++++++++++++++++++++++++++++++++---- rowers/utils.py | 5 ++-- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index efbb5dbf..74a2cce2 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -43,6 +43,8 @@ from courses import ( polygon_coord_center ) +from rowers.models import course_spline + import datetime import math import numpy as np @@ -853,6 +855,8 @@ def course_map(course): latmean,lonmean,coordinates = course_coord_center(course) lat_min, lat_max, long_min, long_max = course_coord_maxmin(course) + coordinates = course_spline(coordinates) + scoordinates = "[" for index,row in coordinates.iterrows(): diff --git a/rowers/models.py b/rowers/models.py index eb6bad4d..6a15539b 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -18,6 +18,9 @@ import twitter import re import pytz +from scipy.interpolate import splprep, splev, CubicSpline +import numpy as np + from django.conf import settings from sqlalchemy import create_engine import sqlalchemy as sa @@ -376,7 +379,33 @@ def polygon_to_path(polygon): def coordinate_in_path(latitude,longitude, p): return p.contains_points([(latitude,longitude)])[0] + +def course_spline(coordinates): + latitudes = coordinates['latitude'].values + longitudes = coordinates['longitude'].values + # spline parameters + s = 1.0 + k = min([5,len(latitudes)-1]) + nest = -1 + + t = np.linspace(0,1,len(latitudes)) + tnew = np.linspace(0,1,100) + + latnew = CubicSpline(t,latitudes,bc_type='clamped')(tnew) + lonnew = CubicSpline(t,longitudes,bc_type='clamped')(tnew) +# latnew = CubicSpline(t,latitudes,bc_type='natural')(tnew) +# lonnew = CubicSpline(t,longitudes,bc_type='natural')(tnew) + +# tckp,u = splprep([t,latitudes,longitudes],s=s,k=k,nest=nest) +# tnew,latnew,lonnew = splev(np.linspace(0,1,100),tckp) + + newcoordinates = pd.DataFrame({ + 'latitude':latnew, + 'longitude':lonnew, + }) + + return newcoordinates def course_coord_center(course): @@ -393,10 +422,12 @@ def course_coord_center(course): latitude = pd.Series(latitudes).median() longitude = pd.Series(longitudes).median() + coordinates = pd.DataFrame({ 'latitude':latitudes, 'longitude':longitudes, }) + return latitude,longitude,coordinates @@ -868,7 +899,7 @@ class GeoPolygon(models.Model): return u'{coursename} - {name}'.format( name=name, - course=coursename + coursename=coursename ) @@ -1157,9 +1188,12 @@ registerchoices = ( class VirtualRace(PlannedSession): # has_registration = models.BooleanField(default=False) - registration_form = models.CharField(max_length=100, - default='windowstart', - choices=registerchoices) + registration_form = models.CharField( + max_length=100, + default='windowstart', + choices=registerchoices, + verbose_name='Registration Closure Quick Selector' + ) registration_closure = models.DateTimeField(blank=True,null=True) evaluation_closure = models.DateTimeField(blank=True,null=True) start_time = models.TimeField(blank=True,null=True) @@ -1348,6 +1382,12 @@ class VirtualRaceForm(ModelForm): if startdatetime > enddatetime: raise forms.ValidationError("The Start of the Race Window should be before the End of the Race Window") + try: + evaluation_closure = cd['evaluation_closure'] + except KeyError: + evaluation_closure = enddatetime+datetime.timedelta(days=1) + cd['evaluation_closure'] = evaluation_closure + if cd['evaluation_closure'] <= enddatetime: raise forms.ValidationError("Evaluation closure deadline should be after the Race Window closes") @@ -1355,7 +1395,7 @@ class VirtualRaceForm(ModelForm): raise forms.ValidationError("Evaluation closure cannot be in the past") - return cleaned_data + return cd class PlannedSessionFormSmall(ModelForm): diff --git a/rowers/utils.py b/rowers/utils.py index c3c1eaca..d9c7ec54 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -253,8 +253,9 @@ def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio): pwr *= ratio - delta = delta.values - cpvalues = cpvalues.values + delta = delta.values.astype(int) + cpvalues = cpvalues.values.astype(int) + pwr = pwr.astype(int) res = np.sum(cpvalues>pwr) res2 = np.sum(cpvalues>pwr2)