defined basic models and some low level functions
This commit is contained in:
73
rowers/courses.py
Normal file
73
rowers/courses.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
from utils import myqueue
|
||||||
|
|
||||||
|
from matplotlib import path
|
||||||
|
|
||||||
|
import django_rq
|
||||||
|
queue = django_rq.get_queue('default')
|
||||||
|
queuelow = django_rq.get_queue('low')
|
||||||
|
queuehigh = django_rq.get_queue('low')
|
||||||
|
|
||||||
|
from rowers.models import (
|
||||||
|
Rower, Workout,
|
||||||
|
GeoPoint,GeoPolygon, GeoCourse,
|
||||||
|
)
|
||||||
|
|
||||||
|
# low level methods
|
||||||
|
class InvalidTrajectoryError(Exception):
|
||||||
|
def __init__(self,value):
|
||||||
|
self.value=value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return repr(self.value)
|
||||||
|
|
||||||
|
def polygon_to_path(polygon):
|
||||||
|
points = GeoPoint.objects.filter(polygon==polygon).order_by(order_in_polygon)
|
||||||
|
s = []
|
||||||
|
for point in points:
|
||||||
|
s.append([point.latitude,point.longitude])
|
||||||
|
|
||||||
|
p = path.Path(np.array(s))
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
def coordinate_in_polygon(latitude,longitude, polygon):
|
||||||
|
p = polygon_to_path(polygon)
|
||||||
|
|
||||||
|
retun p.contains_points([(latitude,longitude)])[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def time_in_polygon(df,polygon,maxmin='max'):
|
||||||
|
# df has timestamp, latitude, longitude
|
||||||
|
p = polygon_to_path(polygon)
|
||||||
|
|
||||||
|
latitude = df.latitude
|
||||||
|
longitude = df.longitude
|
||||||
|
|
||||||
|
f = lambda x: coordinate_in_polygon(x['latitude'],x['longitude'],polygon)
|
||||||
|
|
||||||
|
df['inpolygon'] = df.apply(f,axis=1)
|
||||||
|
|
||||||
|
mask = df['inpolygon'] == True
|
||||||
|
|
||||||
|
if df[mask].empty():
|
||||||
|
raise InvalidTrajectoryError
|
||||||
|
|
||||||
|
if maxmin == 'max':
|
||||||
|
time = df[mask]['time'].max()
|
||||||
|
else:
|
||||||
|
time = df[mask]['time'].min()
|
||||||
|
|
||||||
|
|
||||||
|
return time
|
||||||
124
rowers/models.py
124
rowers/models.py
@@ -643,6 +643,113 @@ timezones = (
|
|||||||
(x,x) for x in pytz.common_timezones
|
(x,x) for x in pytz.common_timezones
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# models related to geo data (points, polygon, courses)
|
||||||
|
|
||||||
|
class GeoCourse(models.Model):
|
||||||
|
manager = models.ForeignKey(Rower)
|
||||||
|
name = models.CharField(max_length=150,blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
class GeoPolygon(models.Model):
|
||||||
|
course = models.ForeignKey(GeoCourse, blank=True)
|
||||||
|
order_in_course = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
# Need error checking to insert new polygons into existing course (all later polygons
|
||||||
|
# increase there order_in_course number
|
||||||
|
|
||||||
|
class GeoPoint(models.Model):
|
||||||
|
latitude = models.FloatField(default=0)
|
||||||
|
longitude = models.FloatField(default=0)
|
||||||
|
polygon = models.ForeignKey(GeoPolygon,blank=True)
|
||||||
|
order_in_poly = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
# need error checking to "insert" new point into existing polygon? This affects order_in_poly
|
||||||
|
# of multiple GeoPoint instances
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# models related to training planning - draft
|
||||||
|
# Do we need a separate class TestTarget?
|
||||||
|
class TrainingTarget(models.Model):
|
||||||
|
rower = models.ForeignKey(Rower)
|
||||||
|
name = models.CharField(max_length=150,blank=True)
|
||||||
|
date = models.DateField(
|
||||||
|
default=timezone.now()+datetime.timedelta(days=182))
|
||||||
|
notes = models.TextField(max_length=300,blank=True)
|
||||||
|
|
||||||
|
# SportTracks has a TrainingGoal like this
|
||||||
|
#class TrainingGoal(models.Model):
|
||||||
|
# rower = models.ForeignKey(Rower)
|
||||||
|
# name = models.CharField(max_length=150,blank=True)
|
||||||
|
# startdate = models.DateField(default=timezone.now)
|
||||||
|
# enddate = models.DateField(
|
||||||
|
# default=timezone.now()+datetime.timedelta(days=28))
|
||||||
|
# goalmetric = models.CharField(max_length=150,default='rower',
|
||||||
|
# choices = modechoices)
|
||||||
|
# value = models.IntegerValue(default=1)
|
||||||
|
|
||||||
|
# I think we can use PlannedSession for that (in challenge mode)
|
||||||
|
# although such a TrainingGoal could have automatically calculated
|
||||||
|
# values without needing the user to assign
|
||||||
|
|
||||||
|
class TrainingPlan(models.Model):
|
||||||
|
rower = models.ForeignKey(Rower)
|
||||||
|
name = models.CharField(max_length=150,blank=True)
|
||||||
|
target = models.ForeignKey(TrainingTarget,blank=True)
|
||||||
|
startdate = models.DateField(default=timezone.now)
|
||||||
|
enddate = models.DateField(
|
||||||
|
default=timezone.now()+datetime.timedelta(days=182))
|
||||||
|
|
||||||
|
cycletypechoices = (
|
||||||
|
('filler','System Defined'),
|
||||||
|
('userdefined','User Defined')
|
||||||
|
)
|
||||||
|
|
||||||
|
class TrainingMacroCycle(models.Model):
|
||||||
|
plan = models.ForeignKey(TrainingPlan)
|
||||||
|
name = models.CharField(max_length=150,blank=True)
|
||||||
|
startdate = models.DateField(default=timezone.now)
|
||||||
|
enddate = models.DateField(
|
||||||
|
default=timezone.now()+datetime.timedelta(days=182))
|
||||||
|
notes = models.TextField(max_length=300,blank=True)
|
||||||
|
type = models.CharField(default='filler',
|
||||||
|
choices=cycletypechoices,
|
||||||
|
max_length=150)
|
||||||
|
|
||||||
|
class TrainingMesoCycle(models.Model):
|
||||||
|
plan = models.ForeignKey(TrainingMacroCycle)
|
||||||
|
name = models.CharField(max_length=150,blank=True)
|
||||||
|
startdate = models.DateField(default=timezone.now)
|
||||||
|
enddate = models.DateField(
|
||||||
|
default=timezone.now()+datetime.timedelta(days=182))
|
||||||
|
notes = models.TextField(max_length=300,blank=True)
|
||||||
|
type = models.CharField(default='filler',
|
||||||
|
choices=cycletypechoices,
|
||||||
|
max_length=150)
|
||||||
|
|
||||||
|
|
||||||
|
class TrainingMicroCycle(models.Model):
|
||||||
|
plan = models.ForeignKey(TrainingMesoCycle)
|
||||||
|
name = models.CharField(max_length=150,blank=True)
|
||||||
|
startdate = models.DateField(default=timezone.now)
|
||||||
|
enddate = models.DateField(
|
||||||
|
default=timezone.now()+datetime.timedelta(days=182))
|
||||||
|
notes = models.TextField(max_length=300,blank=True)
|
||||||
|
type = models.CharField(default='filler',
|
||||||
|
choices=cycletypechoices,
|
||||||
|
max_length=150)
|
||||||
|
|
||||||
|
|
||||||
|
# Needs some error checking
|
||||||
|
# - Microcycles should not overlap with other microcycles, same for MesoCycles, MacroCycles
|
||||||
|
# - When a TrainingPlan is created, it should create 1 "collector" Macro, Meso & MicroCycle - this is invisible for users who choose to not use cycles
|
||||||
|
# - When a new Microcycle is inserted, the "collector" cycle is automatically adjusted to "go out of the way" of the new MicroCycle - and similar for Macro & Meso
|
||||||
|
# - If the entire MesoCycle is filled with user defined MicroCycles - there are no "filler" MicroCycles
|
||||||
|
# - Sessions are automatically linked to the correct Cycles based on their start/end date - no need for a hard link
|
||||||
|
|
||||||
|
# Cycle error checking goes in forms
|
||||||
|
|
||||||
# model for Planned Session (Workout, Challenge, Test)
|
# model for Planned Session (Workout, Challenge, Test)
|
||||||
class PlannedSession(models.Model):
|
class PlannedSession(models.Model):
|
||||||
|
|
||||||
@@ -721,7 +828,7 @@ class PlannedSession(models.Model):
|
|||||||
max_length=150)
|
max_length=150)
|
||||||
|
|
||||||
hasranking = models.BooleanField(default=False)
|
hasranking = models.BooleanField(default=False)
|
||||||
|
|
||||||
class PlannedSessionForm(ModelForm):
|
class PlannedSessionForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlannedSession
|
model = PlannedSession
|
||||||
@@ -737,6 +844,19 @@ class PlannedSessionForm(ModelForm):
|
|||||||
timezone.now().year-1,timezone.now().year+1)),
|
timezone.now().year-1,timezone.now().year+1)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
|
||||||
|
name = self.name
|
||||||
|
startdate = self.startdate
|
||||||
|
enddate = self.enddate
|
||||||
|
|
||||||
|
stri = u'{n} {s} - {e}'.format(
|
||||||
|
s = startdate.strftime('%Y-%m-%d'),
|
||||||
|
e = enddate.strftime('%Y-%m-%d'),
|
||||||
|
n = name,
|
||||||
|
)
|
||||||
|
|
||||||
|
return stri
|
||||||
|
|
||||||
# Workout
|
# Workout
|
||||||
class Workout(models.Model):
|
class Workout(models.Model):
|
||||||
@@ -1438,7 +1558,7 @@ class RowerForm(ModelForm):
|
|||||||
# optionally sends a tweet to our twitter account
|
# optionally sends a tweet to our twitter account
|
||||||
class SiteAnnouncement(models.Model):
|
class SiteAnnouncement(models.Model):
|
||||||
created = models.DateField(default=timezone.now)
|
created = models.DateField(default=timezone.now)
|
||||||
announcement = models.TextField(max_length=140)
|
announcement = models.TextField(max_length=280)
|
||||||
expires = models.DateField(default=timezone.now)
|
expires = models.DateField(default=timezone.now)
|
||||||
modified = models.DateField(default=timezone.now)
|
modified = models.DateField(default=timezone.now)
|
||||||
dotweet = models.BooleanField(default=False)
|
dotweet = models.BooleanField(default=False)
|
||||||
|
|||||||
39
rowers/plannedsessions.py
Normal file
39
rowers/plannedsessions.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
from utils import myqueue
|
||||||
|
|
||||||
|
import django_rq
|
||||||
|
queue = django_rq.get_queue('default')
|
||||||
|
queuelow = django_rq.get_queue('low')
|
||||||
|
queuehigh = django_rq.get_queue('low')
|
||||||
|
|
||||||
|
from rowers.models import (
|
||||||
|
Rower, Workout,
|
||||||
|
GeoCourse, TrainingMicroCycle,TrainingMesoCycle,TrainingMacroCycle,
|
||||||
|
TrainingPlan,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Low Level functions - to be called by higher level methods
|
||||||
|
|
||||||
|
# dummies for now
|
||||||
|
def submit_workout(w,ps):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def remove_workout_plannedsession(w,ps):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def rank_results(ps):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def add_team(t,ps):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def add_rower(r,ps):
|
||||||
|
return 1
|
||||||
Reference in New Issue
Block a user