/[cits3200i]/branches/gps-running-clean-r116/HighScorePlugin/Source/HighScore.cs


UCC Code Repository

Contents of /branches/gps-running-clean-r116/HighScorePlugin/Source/HighScore.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations) (download)
Sun Sep 5 15:48:34 2010 UTC (11 years, 3 months ago) by rvvs89
File size: 24333 byte(s)
Branching a local copy of the HEAD revision of the gps-running project on Google Code.
We will probably have to use this project as a template for our own plugins if we want to support SportTracks 2.1.
1 /*
2 Copyright (C) 2007, 2008 Kristian Bisgaard Lassen
3 Copyright (C) 2010 Kristian Helkjaer Lassen
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 using System;
20 using System.Collections.Generic;
21 using System.Text;
22 using ZoneFiveSoftware.Common.Data.Fitness;
23 using System.Diagnostics;
24 using ZoneFiveSoftware.Common.Visuals.Fitness;
25 using ZoneFiveSoftware.Common.Data.GPS;
26 using ZoneFiveSoftware.Common.Data;
27 using System.Data;
28 using System.Windows.Forms;
29 using GpsRunningPlugin.Properties;
30 using ZoneFiveSoftware.Common.Data.Measurement;
31 using ZoneFiveSoftware.Common.Visuals;
32 using GpsRunningPlugin.Util;
33
34 namespace GpsRunningPlugin.Source
35 {
36 class HighScore
37 {
38 private HighScore() { }
39
40 public static IList<IList<Object>> getFastestTimesOfDistances(IList<IActivity> activities, IList<double> distances, System.Windows.Forms.ProgressBar progress)
41 {
42 IList<Goal> goals = new List<Goal>();
43 foreach (double distance in distances)
44 {
45 goals.Add(new PointGoal(distance, false,
46 GoalParameter.Time, GoalParameter.Distance));
47 }
48
49 Result[] results = calculate(activities, goals, progress);
50 IList<IList<Object>> objects = new List<IList<Object>>();
51 foreach (Result result in results)
52 {
53 if (result != null)
54 {
55 IList<Object> s = new List<Object>();
56 objects.Add(s);
57 s.Add(result.Activity);
58 s.Add(result.Seconds);
59 s.Add(result.MeterStart);
60 s.Add(result.MeterEnd);
61 s.Add(result.TimeStart);
62 }
63 }
64 return objects;
65 }
66
67 public static Result[] calculate(IList<IActivity> activities, IList<Goal> goals, System.Windows.Forms.ProgressBar progress)
68 {
69 Result[] results = new Result[goals.Count];
70 progress.Minimum = 0;
71 progress.Maximum = activities.Count;
72 progress.Value = 0;
73 if (activities != null && activities.Count > 0)
74 {
75 foreach (IActivity activity in activities)
76 {
77 if (null != activity && activity.HasStartTime)
78 {
79 if (Settings.IgnoreManualData)
80 {
81 if (!activity.UseEnteredData)
82 calculate(activity, goals, results);
83 }
84 else calculate(activity, goals, results);
85 }
86 progress.Value++;
87 }
88 }
89 return results;
90 }
91
92 private static void calculate(IActivity activity, IList<Goal> goals, IList<Result> results)
93 {
94 ActivityInfo info = ActivityInfoCache.Instance.GetInfo(activity);
95 double[] distance, time, elevation, pulse, speed;
96 int increment = 5;
97 restart:
98 {
99 IList<LapDetailInfo> laps = info.DistanceLapDetailInfo(20 + increment);
100 int length = laps.Count + 1;//info.MovingDistanceMetersTrack.Count;
101 distance = new double[length];
102 distance[0] = 0;
103 time = new double[length];
104 time[0] = 0;
105 elevation = new double[length];
106 pulse = new double[length];
107 speed = new double[length];
108 DateTime dateTime = activity.StartTime;
109 ITimeValueEntry<float> value = info.SmoothedElevationTrack.GetInterpolatedValue(dateTime);
110 if (value != null)
111 elevation[0] = value.Value;
112 else
113 elevation[0] = 0;
114 value = info.SmoothedHeartRateTrack.GetInterpolatedValue(dateTime);
115 if (info.SmoothedHeartRateTrack.Max > 0 &&
116 value != null)
117 pulse[0] = value.Value;
118 else
119 pulse[0] = 0;
120 value = info.SmoothedSpeedTrack.GetInterpolatedValue(dateTime);
121 if (value != null)
122 speed[0] = value.Value;
123 else
124 speed[0] = 0;
125 //double d = 0;
126 //TimeSpan t;
127 //foreach (LapDetailInfo lap in laps)
128 //{
129 // d += lap.LapDistanceMeters;
130 // t = lap.StartElapsed;
131 //}
132 int index = 1;
133 foreach (LapDetailInfo lap in laps)
134 {
135 distance[index] = lap.EndDistanceMeters;
136 time[index] = lap.EndElapsed.TotalSeconds;
137 if (time[index] < time[index - 1])
138 {
139 time[index] = time[index - 1];
140 increment += 5;
141 goto restart;
142 }
143 dateTime = lap.EndTime;
144 value = info.SmoothedElevationTrack.GetInterpolatedValue(dateTime);
145 if (value != null)
146 elevation[index] = value.Value;
147 else
148 elevation[index] = 0;
149 value = info.SmoothedHeartRateTrack.GetInterpolatedValue(dateTime);
150 if (info.SmoothedHeartRateTrack.Max > 0 &&
151 value != null)
152 pulse[index] = value.Value;
153 else
154 pulse[index] = 0;
155 value = info.SmoothedSpeedTrack.GetInterpolatedValue(dateTime);
156 if (value != null)
157 speed[index] = value.Value;
158 else
159 speed[index] = 0;
160 index++;
161 }
162 }
163 //foreach (TimeValueEntry<float> pair in info.MovingDistanceMetersTrack)
164 //{
165 // distance[index] = pair.Value;
166 // time[index] = pair.ElapsedSeconds;
167 // DateTime dateTime = info.MovingDistanceMetersTrack.StartTime.AddSeconds(time[index]);//activity.StartTime.AddSeconds(pair.ElapsedSeconds);
168 // ITimeValueEntry<float> value = info.SmoothedElevationTrack.GetInterpolatedValue(dateTime);
169 // if (value != null)
170 // elevation[index] = value.Value;
171 // else
172 // elevation[index] = 0;
173 // value = info.SmoothedHeartRateTrack.GetInterpolatedValue(dateTime);
174 // if (info.SmoothedHeartRateTrack.Max > 0 &&
175 // value != null)
176 // pulse[index] = value.Value;
177 // else
178 // pulse[index] = 0;
179 // value = info.SmoothedSpeedTrack.GetInterpolatedValue(dateTime);
180 // if (value != null)
181 // speed[index] = value.Value;
182 // else
183 // speed[index] = 0;
184 // index++;
185 //}
186
187 //pad(elevation);
188 //pad(pulse);
189 //pad(speed);
190
191 //int test = 0;
192
193 for (int i = 0; i < goals.Count; i++)
194 {
195 Result result = null;
196 switch (goals[i].Image)
197 {
198 case GoalParameter.PulseZone:
199 case GoalParameter.SpeedZone:
200 case GoalParameter.PulseZoneSpeedZone:
201 if (info.SmoothedHeartRateTrack.Count > 0)
202 result = calculate(activity, (IntervalsGoal)goals[i],
203 getRightType(goals[i].Domain, distance, time, elevation),
204 getRightType(goals[i].Image, pulse, speed),
205 time, distance, elevation, pulse);
206 break;
207 default:
208 result = calculate(activity, (PointGoal)goals[i],
209 getRightType(goals[i].Domain, distance, time, elevation),
210 getRightType(goals[i].Image, distance, time, elevation),
211 time, distance, elevation, pulse);
212 break;
213 }
214 if (result != null && (results[i] == null ||
215 ((goals[i].UpperBound && result.DomainDiff > results[i].DomainDiff) ||
216 (!goals[i].UpperBound && result.DomainDiff < results[i].DomainDiff))))
217
218 results[i] = result;
219 }
220 }
221
222 private static void pad(double[] ds)
223 {
224 int index = 0;
225 while (index < ds.Length && ds[index] == 0) index++;
226 if (index >= ds.Length) return;
227 double v = ds[index];
228 while (index >= 0) ds[index--] = v;
229 index = ds.Length - 1;
230 while (index >= 0 && ds[index] == 0) index--;
231 v = ds[index];
232 while (index < ds.Length) ds[index++] = v;
233 }
234
235 private static double[] getRightType(GoalParameter goalParameter,
236 double[] distance, double[] time, double[] elevation)
237 {
238 switch (goalParameter)
239 {
240 case GoalParameter.Distance: return distance;
241 case GoalParameter.Time: return time;
242 case GoalParameter.Elevation: return elevation;
243 }
244 return null;
245 }
246
247 public static IList<double[]> getRightType(GoalParameter goalParamter,
248 double[] pulse, double[] speed)
249 {
250 IList<double[]> result = new List<double[]>();
251 switch (goalParamter)
252 {
253 case GoalParameter.PulseZone:
254 result.Add(pulse); break;
255 case GoalParameter.SpeedZone:
256 result.Add(speed); break;
257 case GoalParameter.PulseZoneSpeedZone:
258 result.Add(pulse); result.Add(speed); break;
259 }
260 return result;
261 }
262
263 private static Result calculate(IActivity activity, IntervalsGoal goal,
264 double[] domain, IList<double[]> image,
265 double[] time, double[] distance, double[] elevation, double[] pulse)
266 {
267 bool foundAny = false;
268 int back = 0, front = 0;
269 int bestBack = 0, bestFront = 0;
270 double domainStart = 0, domainEnd = 0;
271 double distanceStart = 0, distanceEnd = 0;
272 double elevationStart = 0, elevationEnd = 0;
273 double timeStart = 0, timeEnd = 0;
274
275 double best;
276 if (goal.UpperBound) best = double.MinValue;
277 else best = double.MaxValue;
278
279 int length = image[0].Length;
280
281 while (front < length)
282 {
283 bool inWindow = true;
284 for (int i = 0; i < image.Count; i++)
285 {
286 if (image[i][back] < goal.Intervals[i][0] ||
287 image[i][front] > goal.Intervals[i][1])
288 {
289 inWindow = false;
290 break;
291 }
292 }
293 if (inWindow)
294 {
295 double domainDiff = domain[front] - domain[back];
296 if ((goal.UpperBound && best < domainDiff) ||
297 (!goal.UpperBound && best > domainDiff))
298 {
299 foundAny = true;
300 best = domainDiff;
301 bestBack = back;
302 bestFront = front;
303 domainStart = domain[back];
304 domainEnd = domain[front];
305 timeStart = time[back];
306 timeEnd = time[front];
307 distanceStart = distance[back];
308 distanceEnd = distance[front];
309 elevationStart = elevation[back];
310 elevationEnd = elevation[front];
311 }
312 if (back == front ||
313 (front < length - 1 && isInZone(image, goal, front + 1)))
314 front++;
315 else back++;
316 }
317 else
318 {
319 if (back == front)
320 {
321 if (front < length - 1 && !isInZone(image, goal, front + 1))
322 back++;
323 front++;
324 }
325 else back++;
326 }
327 }
328
329 if (foundAny)
330 {
331 return new Result(goal, activity, domainStart, domainEnd, (int)timeStart, (int)timeEnd,
332 distanceStart, distanceEnd, elevationStart, elevationEnd,
333 averagePulse(pulse, time, bestBack, bestFront));
334 }
335 return null;
336 }
337
338 private static double averagePulse(double[] pulse, double[] time, int back, int front)
339 {
340 double result = 0;
341 for (int i = back; i < front; i++)
342 result += (pulse[i] + (pulse[i + 1] - pulse[i]) / 2) * (time[i + 1] - time[i]);
343 result = result / (time[front] - time[back]);
344 return result;
345 }
346
347 private static bool isInZone(IList<double[]> image, IntervalsGoal goal, int index)
348 {
349 for (int i = 0; i < image.Count; i++)
350 {
351 if (image[i][index] < goal.Intervals[i][0] ||
352 image[i][index] > goal.Intervals[i][1])
353 {
354 return false;
355 }
356 }
357 return true;
358 }
359
360 private static Result calculate(IActivity activity, PointGoal goal,
361 double[] domain, double[] image,
362 double[] time, double[] distance, double[] elevation, double[] pulse)
363 {
364 bool foundAny = false;
365 int back = 0, front = 0;
366 int bestBack = 0, bestFront = 0;
367 double domainStart = 0, domainEnd = 0;
368 double distanceStart = 0, distanceEnd = 0;
369 double elevationStart = 0, elevationEnd = 0;
370 double timeStart = 0, timeEnd = 0;
371
372 double best;
373 if (goal.UpperBound) best = double.MinValue;
374 else best = double.MaxValue;
375
376 while (front < image.Length && back < image.Length)
377 {
378 if (image[front] - image[back] >= goal.Value)
379 {
380 double domainDiff = domain[front] - domain[back];
381 if ((goal.UpperBound && best < domainDiff) ||
382 (!goal.UpperBound && best > domainDiff))
383 {
384 foundAny = true;
385 best = domainDiff;
386 bestBack = back;
387 bestFront = front;
388 domainStart = domain[back];
389 domainEnd = domain[front];
390 timeStart = time[back];
391 timeEnd = time[front];
392 distanceStart = distance[back];
393 distanceEnd = distance[front];
394 elevationStart = elevation[back];
395 elevationEnd = elevation[front];
396 }
397 back++;
398 }
399 else
400 {
401 front++;
402 }
403 }
404 if (foundAny)
405 return new Result(goal, activity, domainStart, domainEnd,
406 (int) timeStart, (int) timeEnd, distanceStart, distanceEnd, elevationStart, elevationEnd,
407 averagePulse(pulse, time, bestBack, bestFront));
408 return null;
409 }
410
411 public static void generateGoals(GoalParameter domain, GoalParameter image, bool upperBound,
412 IList<Goal> goals)
413 {
414 switch (image)
415 {
416 case GoalParameter.Distance:
417 foreach (double distance in Settings.distances.Keys)
418 {
419 goals.Add(new PointGoal(distance, upperBound,
420 domain, GoalParameter.Distance));
421 }
422 break;
423 case GoalParameter.Time:
424 foreach (int time in Settings.times.Keys)
425 {
426 goals.Add(new PointGoal(time, upperBound,
427 domain, GoalParameter.Time));
428 }
429 break;
430 case GoalParameter.Elevation:
431 foreach (double elevation in Settings.elevations.Keys)
432 {
433 goals.Add(new PointGoal(elevation, upperBound,
434 domain, GoalParameter.Elevation));
435 }
436 break;
437 case GoalParameter.PulseZone:
438 foreach (double min in Settings.pulseZones.Keys)
439 foreach (double max in Settings.pulseZones[min].Keys)
440 {
441 IList<IList<double>> intervals = new List<IList<double>>();
442 IList<double> interval = new List<double>();
443 interval.Add(min);
444 interval.Add(max);
445 intervals.Add(interval);
446 goals.Add(new IntervalsGoal(intervals, upperBound,
447 domain, GoalParameter.PulseZone));
448 }
449 break;
450 case GoalParameter.SpeedZone:
451 foreach (double min in Settings.speedZones.Keys)
452 foreach (double max in Settings.speedZones[min].Keys)
453 {
454 IList<IList<double>> intervals = new List<IList<double>>();
455 IList<double> interval = new List<double>();
456 interval.Add(min);
457 interval.Add(max);
458 intervals.Add(interval);
459 goals.Add(new IntervalsGoal(intervals, upperBound,
460 domain, GoalParameter.SpeedZone));
461 }
462 break;
463 case GoalParameter.PulseZoneSpeedZone:
464 foreach (double minPulse in Settings.pulseZones.Keys)
465 foreach (double maxPulse in Settings.pulseZones[minPulse].Keys)
466 foreach (double minSpeed in Settings.speedZones.Keys)
467 foreach (double maxSpeed in Settings.speedZones[minSpeed].Keys)
468 {
469 IList<IList<double>> intervals = new List<IList<double>>();
470 IList<double> interval = new List<double>();
471 interval.Add(minPulse);
472 interval.Add(maxPulse);
473 intervals.Add(interval);
474 interval = new List<double>();
475 interval.Add(minSpeed);
476 interval.Add(maxSpeed);
477 intervals.Add(interval);
478 goals.Add(new IntervalsGoal(intervals, upperBound,
479 domain, GoalParameter.PulseZoneSpeedZone));
480 }
481 break;
482 }
483 }
484
485 public static IList<Goal> generateGoals()
486 {
487 IList<Goal> goals = new List<Goal>();
488 generateGoals(Settings.Domain, Settings.Image, Settings.UpperBound, goals);
489 return goals;
490 }
491
492 public static DataTable generateTable(IList<Result> results, String speedUnit,
493 bool includeLocationAndDate, GoalParameter domain, GoalParameter image, bool upperBound)
494 {
495 IApplication app = Plugin.GetApplication();
496 DataTable table = new DataTable();
497 table.Columns.Add(UnitUtil.Distance.LabelAxis);
498 table.Columns.Add(CommonResources.Text.LabelTime);
499 table.Columns.Add(UnitUtil.PaceOrSpeed.LabelAxis(speedUnit.Equals(CommonResources.Text.LabelPace)));
500 table.Columns.Add(CommonResources.Text.LabelStartTime);
501 table.Columns.Add(CommonResources.Text.LabelStart + UnitUtil.Distance.LabelAbbr2);
502 table.Columns.Add(CommonResources.Text.LabelElevation + " (+/- " + UnitUtil.Elevation.LabelAbbr + ")");
503 table.Columns.Add(CommonResources.Text.LabelAvgHR + UnitUtil.HeartRate.LabelAbbr2);
504 if (includeLocationAndDate)
505 {
506 table.Columns.Add(CommonResources.Text.LabelDate);
507 table.Columns.Add(CommonResources.Text.LabelLocation);
508 }
509 table.Columns.Add(HighScoreViewer.ActivityIdColumn);
510 foreach (Result result in results)
511 {
512 if (result != null && result.Goal.Domain.Equals(domain) &&
513 result.Goal.Image.Equals(image)
514 && result.Goal.UpperBound == upperBound)
515 {
516 DataRow row = table.NewRow();
517 row[0] = UnitUtil.Distance.ToString(result.Meters);
518 row[1] = UnitUtil.Time.ToString(result.Seconds);
519 if (result.Seconds > 0 && result.Meters > 0)
520 {
521 double speedMS = result.Meters / result.Seconds;
522 row[2] = UnitUtil.PaceOrSpeed.ToString(speedUnit.Equals(CommonResources.Text.LabelPace), speedMS);
523 }
524 else {
525 row[2] = "-";
526 }
527 row[3] = UnitUtil.Time.ToString(result.TimeStart);
528 row[4] = UnitUtil.Distance.ToString(result.MeterStart);
529 row[5] = UnitUtil.Elevation.ToString(result.Elevations);
530 if (result.AveragePulse.Equals(double.NaN))
531 row[6] = "-";
532 else
533 row[6] = Math.Round(result.AveragePulse);
534 if (includeLocationAndDate)
535 {
536 row[7] = result.Activity.StartTime.ToShortDateString();
537 row[8] = result.Activity.Location;
538 }
539 row[HighScoreViewer.ActivityIdColumn] = result.Activity.ReferenceId;
540 table.Rows.Add(row);
541 }
542 }
543 return table;
544 }
545 }
546 }

Managed by UCC Webmasters ViewVC Help
Powered by ViewVC 1.1.26