/[cits3200i]/trunk/UWAPlugins/PlaybackPlugin/Source/PlaybackControl.cs


UCC Code Repository

Contents of /trunk/UWAPlugins/PlaybackPlugin/Source/PlaybackControl.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Thu Sep 30 03:22:02 2010 UTC (11 years, 2 months ago) by rvvs89
File size: 13918 byte(s)
Merging branch back into trunk.
1 using PlaybackPlugin.Properties;
2 using System;
3 using System.Collections.Generic;
4 using System.ComponentModel;
5 using System.Data;
6 using System.Drawing;
7 using System.Text;
8 using System.Timers;
9 using System.Windows.Forms;
10 using ZoneFiveSoftware.Common.Data;
11 using ZoneFiveSoftware.Common.Data.Fitness;
12 using ZoneFiveSoftware.Common.Visuals.Mapping;
13 using ZoneFiveSoftware.Common.Visuals.Util;
14 using ZoneFiveSoftware.Common.Data.GPS;
15
16 namespace PlaybackPlugin.Source
17 {
18 public partial class PlaybackControl : UserControl
19 {
20 private PlaybackState state = PlaybackState.Disabled;
21 private IActivity activity = null;
22 private System.Timers.Timer timer;
23 private DateTime startTime;
24 private DateTime endTime;
25 private DateTime currentTime;
26 private Nullable<DateTime> initialSelection = null;
27 private IRouteControl control;
28 private IRouteControlItem item;
29 private IGPSRoute route;
30 private EventHandler selectedItemsChangedHandler;
31 private IList<IRouteControlSelection> oldSelection;
32 private const double MOVE_SELECTION_THRESHOLD = 2000.0;
33 private const double PLAYBACKBAR_TICK_GRANULARITY = 100;
34 private const double REWIND_FACTOR = -5.0;
35 private const double FASTFORWARD_FACTOR = 5.0;
36 private const double STEP_SIZE = 1.0;
37
38 public PlaybackControl()
39 {
40 InitializeComponent();
41 if (PlaybackAnimationRouteControlLayer.Instances.Count == 0)
42 {
43 // HACK: make designer work properly
44 return;
45 }
46 CheckRouteValidity();
47 MarkSelectedRegion();
48 UpdateUI();
49 selectedItemsChangedHandler = new EventHandler(control_SelectedItemsChanged);
50 control.SelectedItemsChanged += selectedItemsChangedHandler;
51 timer = new System.Timers.Timer();
52 timer.Interval = 100.0;
53 timer.Elapsed += new ElapsedEventHandler(PlaybackTick);
54 timer.SynchronizingObject = this;
55 }
56
57 public IActivity Activity
58 {
59 get { return activity; }
60 set {
61 activity = value;
62 State = activity == null ? PlaybackState.Disabled : PlaybackState.Stopped;
63 }
64 }
65
66 public PlaybackState State
67 {
68 get { return state; }
69 set
70 {
71 state = value;
72 timer.Enabled = State == PlaybackState.Playing || State == PlaybackState.FastForwarding || State == PlaybackState.Rewinding;
73 UpdateUI();
74 }
75 }
76
77 private DateTime CurrentTime
78 {
79 get { return currentTime; }
80 set
81 {
82 currentTime = value;
83 currentTime = DateTimeMax(currentTime, startTime);
84 currentTime = DateTimeMin(currentTime, endTime);
85 UpdateUI();
86 }
87 }
88
89 public new void Dispose()
90 {
91 State = PlaybackState.Disabled;
92 control.SelectedItemsChanged -= selectedItemsChangedHandler;
93 control.SelectedItems = oldSelection;
94 timer.Stop();
95 timer.Dispose();
96 PlaybackAnimationRouteControlLayer.Instances[0].StartMarker.Visible = false;
97 PlaybackAnimationRouteControlLayer.Instances[0].EndMarker.Visible = false;
98 PlaybackAnimationRouteControlLayer.Instances[0].UpdateMarkers();
99 base.Dispose();
100 }
101
102 private void UpdateUI()
103 {
104 TimeSpan length = endTime - startTime;
105 TimeSpan progress = currentTime - startTime;
106 rewindButton.Enabled = State != PlaybackState.Disabled && State != PlaybackState.Stopped;
107 fastForwardButton.Enabled = State != PlaybackState.Disabled && State != PlaybackState.Stopped;
108 playButton.Enabled = State != PlaybackState.Disabled;
109 playButton.Image = State == PlaybackState.Playing || State == PlaybackState.FastForwarding || State == PlaybackState.Rewinding ? Resources.PauseIcon : Resources.PlayIcon;
110 loopButton.Enabled = State != PlaybackState.Disabled;
111 speedLabel.Enabled = State != PlaybackState.Disabled;
112 speedSpinner.Enabled = State != PlaybackState.Disabled;
113 statusStrip.Enabled = State != PlaybackState.Disabled;
114 playbackBar.Enabled = State != PlaybackState.Disabled;
115 playbackBar.Maximum = (int) (length.TotalMilliseconds / PLAYBACKBAR_TICK_GRANULARITY);
116 int ticks = Math.Min(playbackBar.Maximum, 10);
117 playbackBar.TickFrequency = playbackBar.Maximum / ticks;
118 playbackBar.Value = (int) (progress.TotalMilliseconds / PLAYBACKBAR_TICK_GRANULARITY);
119 statusLabel.Enabled = State != PlaybackState.Disabled;
120 statusLabel.Text = String.Format("{0}:{1:00}:{2:00} / {3}:{4:00}:{5:00}", progress.Hours, progress.Minutes, progress.Seconds, length.Hours, length.Minutes, length.Seconds);
121 control.SelectedItems = new List<IRouteControlSelection> { new PlaybackRouteControlSelection(item, currentTime) };
122 if (followButton.Checked)
123 {
124 control.MapControl.Center = route.GetInterpolatedValue(currentTime).Value;
125 }
126 }
127
128 private void CheckRouteValidity()
129 {
130 // TODO: Verify that the current route is one that can be played back (ie has valid time data)
131 // TODO: notify user that playback is impossible if the route does not have time data and throw exception
132 control = PlaybackAnimationRouteControlLayer.Instances[0].Control;
133 oldSelection = control.SelectedItems;
134 }
135
136 private static DateTime DateTimeMin(DateTime a, DateTime b)
137 {
138 return a < b ? a : b;
139 }
140
141 private static DateTime DateTimeMax(DateTime a, DateTime b)
142 {
143 return a > b ? a : b;
144 }
145
146 private static int RouteIndexFromDistance(IGPSRoute route, double distance)
147 {
148 // FIXME: add out parameter to output the remaining distance to improve accuracy
149 IEnumerator<ITimeValueEntry<IGPSPoint>> i = route.GetEnumerator();
150 int index = 0;
151 double count = 0.0;
152 i.MoveNext();
153 IGPSPoint prev = i.Current.Value;
154 while (i.MoveNext())
155 {
156 IGPSPoint cur = i.Current.Value;
157 count += prev.DistanceMetersToPoint(cur);
158 if (count < distance)
159 {
160 index++;
161 prev = cur;
162 }
163 else
164 {
165 return index;
166 }
167 }
168 return index;
169 }
170
171 private static DateTime RouteTimeFromDistance(IGPSRoute route, double distance)
172 {
173 int index = RouteIndexFromDistance(route, distance);
174 return route.StartTime.AddSeconds(route[index].ElapsedSeconds);
175 }
176
177 private void CalculateSelectedRegion(out DateTime start, out DateTime end)
178 {
179 // FIXME: account for multiple ranges within one selection
180 start = DateTime.MaxValue;
181 end = DateTime.MinValue;
182 for (int k = 0; k < control.SelectedItems.Count; k++)
183 {
184 IRouteControlSelection selection = control.SelectedItems[k];
185 if (selection == null || !selection.Item.DisplayRoute || selection.Item.Item == null)
186 {
187 return;
188 }
189 if (selection.DistanceMetersRanges != null && selection.DistanceMetersRanges.Count >= 1)
190 {
191 start = DateTimeMin(start, RouteTimeFromDistance(route, selection.DistanceMetersRanges[0].Lower));
192 end = DateTimeMax(end, RouteTimeFromDistance(route, selection.DistanceMetersRanges[0].Upper));
193 }
194 else if (selection.TimeRanges != null && selection.TimeRanges.Count >= 1)
195 {
196 start = DateTimeMin(start, selection.TimeRanges[0].Lower);
197 end = DateTimeMax(start, selection.TimeRanges[0].Upper);
198 }
199 }
200 if (start == DateTime.MaxValue)
201 {
202 start = DateTime.MinValue;
203 }
204 if (end == DateTime.MinValue)
205 {
206 end = DateTime.MaxValue;
207 }
208 }
209
210 private void MarkSelectedRegion()
211 {
212 item = control.Items[0];
213 route = item.Item.GPSRoute;
214 IList<IRouteControlSelection> selection = PlaybackAnimationRouteControlLayer.Instances[0].Control.SelectedItems;
215 CalculateSelectedRegion(out startTime, out endTime);
216 if (endTime == startTime)
217 {
218 initialSelection = startTime;
219 startTime = DateTime.MinValue;
220 endTime = DateTime.MaxValue;
221 }
222 else
223 {
224 initialSelection = null;
225 }
226 startTime = DateTimeMax(startTime, route.StartTime);
227 if (startTime > route.StartTime)
228 {
229 MapMarker startMarker = PlaybackAnimationRouteControlLayer.Instances[0].StartMarker;
230 startMarker.Location = route.GetInterpolatedValue(startTime).Value;
231 startMarker.Visible = true;
232 }
233 endTime = DateTimeMin(endTime, route.StartTime.AddSeconds(route.TotalElapsedSeconds));
234 if (endTime < route.StartTime.AddSeconds(route.TotalElapsedSeconds))
235 {
236 MapMarker endMarker = PlaybackAnimationRouteControlLayer.Instances[0].EndMarker;
237 endMarker.Location = route.GetInterpolatedValue(endTime).Value;
238 endMarker.Visible = true;
239 }
240 PlaybackAnimationRouteControlLayer.Instances[0].UpdateMarkers();
241 CurrentTime = initialSelection == null ? startTime : initialSelection.Value;
242 }
243
244 public enum PlaybackState
245 {
246 Disabled,
247 Stopped,
248 Paused,
249 Playing,
250 FastForwarding,
251 Rewinding
252 }
253
254 private void playButton_Click(object sender, EventArgs e)
255 {
256 if (State == PlaybackState.Stopped && CurrentTime >= endTime)
257 {
258 CurrentTime = startTime;
259 }
260 State = State == PlaybackState.Playing || State == PlaybackState.FastForwarding || State == PlaybackState.Rewinding ? PlaybackState.Paused : PlaybackState.Playing;
261 }
262
263 private void fastForwardButton_Click(object sender, EventArgs e)
264 {
265 if (State == PlaybackState.Paused)
266 {
267 CurrentTime = CurrentTime.AddSeconds(STEP_SIZE);
268 }
269 else
270 {
271 // TODO: implement fast-forward
272 }
273 }
274
275 private void rewindButton_Click(object sender, EventArgs e)
276 {
277 if (State == PlaybackState.Paused)
278 {
279 CurrentTime = CurrentTime.AddSeconds(-STEP_SIZE);
280 }
281 else
282 {
283 // TODO: implement rewind
284 }
285 }
286
287 private void playbackBar_Scroll(object sender, EventArgs e)
288 {
289 CurrentTime = startTime.AddMilliseconds(playbackBar.Value * PLAYBACKBAR_TICK_GRANULARITY);
290 }
291
292 private void PlaybackTick(object source, ElapsedEventArgs args)
293 {
294 CurrentTime = CurrentTime.AddMilliseconds((double) speedSpinner.Value * timer.Interval);
295 if (CurrentTime >= endTime)
296 {
297 if (loopButton.Checked)
298 {
299 CurrentTime = startTime;
300 }
301 else
302 {
303 State = PlaybackState.Stopped;
304 }
305 }
306 }
307
308 private void control_SelectedItemsChanged(object sender, EventArgs e)
309 {
310 // FIXME: account for multiple ranges within one selection
311 DateTime selectedTime = DateTime.MinValue;
312 for (int k = 0; k < control.SelectedItems.Count; k++)
313 {
314 IRouteControlSelection selection = control.SelectedItems[k];
315 if (selection == null || !selection.Item.DisplayRoute || selection.Item.Item == null)
316 {
317 return;
318 }
319 if (selection.DistanceMetersRanges != null && selection.DistanceMetersRanges.Count >= 1)
320 {
321 selectedTime = RouteTimeFromDistance(route, selection.DistanceMetersRanges[0].Lower);
322 }
323 else if (selection.TimeRanges != null && selection.TimeRanges.Count >= 1)
324 {
325 selectedTime = selection.TimeRanges[0].Lower;
326 }
327 if (selectedTime != DateTime.MinValue)
328 {
329 break;
330 }
331 }
332 if (selectedTime == DateTime.MinValue)
333 {
334 return;
335 }
336 TimeSpan diff = currentTime < selectedTime ? selectedTime - currentTime : currentTime - selectedTime;
337 if (diff.TotalMilliseconds > MOVE_SELECTION_THRESHOLD)
338 {
339 CurrentTime = selectedTime;
340 }
341 }
342 }
343 }

Managed by UCC Webmasters ViewVC Help
Powered by ViewVC 1.1.26