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
|
||||
)
|
||||
|
||||
# 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)
|
||||
class PlannedSession(models.Model):
|
||||
|
||||
@@ -721,7 +828,7 @@ class PlannedSession(models.Model):
|
||||
max_length=150)
|
||||
|
||||
hasranking = models.BooleanField(default=False)
|
||||
|
||||
|
||||
class PlannedSessionForm(ModelForm):
|
||||
class Meta:
|
||||
model = PlannedSession
|
||||
@@ -737,6 +844,19 @@ class PlannedSessionForm(ModelForm):
|
||||
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
|
||||
class Workout(models.Model):
|
||||
@@ -1438,7 +1558,7 @@ class RowerForm(ModelForm):
|
||||
# optionally sends a tweet to our twitter account
|
||||
class SiteAnnouncement(models.Model):
|
||||
created = models.DateField(default=timezone.now)
|
||||
announcement = models.TextField(max_length=140)
|
||||
announcement = models.TextField(max_length=280)
|
||||
expires = models.DateField(default=timezone.now)
|
||||
modified = models.DateField(default=timezone.now)
|
||||
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