]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/Selection.java
Version 4, January 2008
[GpsPrune.git] / tim / prune / data / Selection.java
1 package tim.prune.data;
2
3 import tim.prune.DataSubscriber;
4 import tim.prune.UpdateMessageBroker;
5
6 /**
7  * Class to represent a selected portion of a Track
8  * and its properties
9  */
10 public class Selection
11 {
12         private Track _track = null;
13         private UpdateMessageBroker _broker = null;
14         private int _currentPoint = -1;
15         private boolean _valid = false;
16         private int _startIndex = -1, _endIndex = -1;
17         private int _currentPhotoIndex = -1;
18         private IntegerRange _altitudeRange = null;
19         private int _climb = -1, _descent = -1;
20         private int _altitudeFormat = Altitude.FORMAT_NONE;
21         private long _seconds = 0L;
22         private double _angDistance = -1.0; //, _averageSpeed = -1.0;
23
24
25         /**
26          * Constructor
27          * @param inTrack track object
28          * @param inBroker broker object
29          */
30         public Selection(Track inTrack, UpdateMessageBroker inBroker)
31         {
32                 _track = inTrack;
33                 _broker = inBroker;
34         }
35
36
37         /**
38          * Reset selection to be recalculated
39          */
40         private void reset()
41         {
42                 _valid = false;
43         }
44
45
46         /**
47          * Select the point at the given index
48          * @param inIndex index number of selected point
49          */
50         public void selectPoint(int inIndex)
51         {
52                 if (inIndex >= -1)
53                 {
54                         _currentPoint = inIndex;
55                         check();
56                 }
57         }
58
59         /**
60          * Select the specified point and range in one go
61          * @param inPointIndex point selection
62          * @param inStart range start
63          * @param inEnd range end
64          */
65         public void select(int inPointIndex, int inStart, int inEnd)
66         {
67                 _currentPoint = inPointIndex;
68                 _startIndex = inStart;
69                 _endIndex = inEnd;
70                 reset();
71                 check();
72         }
73
74
75         /**
76          * Select the previous point
77          */
78         public void selectPreviousPoint()
79         {
80                 if (_currentPoint > 0)
81                         selectPoint(_currentPoint - 1);
82         }
83
84         /**
85          * Select the next point
86          */
87         public void selectNextPoint()
88         {
89                 selectPoint(_currentPoint + 1);
90         }
91
92         /**
93          * @return the current point index
94          */
95         public int getCurrentPointIndex()
96         {
97                 return _currentPoint;
98         }
99
100
101         /**
102          * @return true if range is selected
103          */
104         public boolean hasRangeSelected()
105         {
106                 return _startIndex >= 0 && _endIndex > _startIndex;
107         }
108
109
110         /**
111          * Recalculate all selection details
112          */
113         private void recalculate()
114         {
115                 _altitudeFormat = Altitude.FORMAT_NONE;
116                 if (_track.getNumPoints() > 0 && hasRangeSelected())
117                 {
118                         _altitudeRange = new IntegerRange();
119                         _climb = 0;
120                         _descent = 0;
121                         Altitude altitude = null;
122                         Timestamp time = null, startTime = null, endTime = null;
123                         DataPoint lastPoint = null, currPoint = null;
124                         _angDistance = 0.0;
125                         int altValue = 0;
126                         int lastAltValue = 0;
127                         boolean foundAlt = false;
128                         for (int i=_startIndex; i<=_endIndex; i++)
129                         {
130                                 currPoint = _track.getPoint(i);
131                                 altitude = currPoint.getAltitude();
132                                 // Ignore waypoints in altitude calculations
133                                 if (!currPoint.isWaypoint() && altitude.isValid())
134                                 {
135                                         altValue = altitude.getValue(_altitudeFormat);
136                                         if (_altitudeFormat == Altitude.FORMAT_NONE)
137                                                 _altitudeFormat = altitude.getFormat();
138                                         _altitudeRange.addValue(altValue);
139                                         if (foundAlt)
140                                         {
141                                                 if (altValue > lastAltValue)
142                                                         _climb += (altValue - lastAltValue);
143                                                 else
144                                                         _descent += (lastAltValue - altValue);
145                                         }
146                                         lastAltValue = altValue;
147                                         foundAlt = true;
148                                 }
149                                 // Store the first and last timestamp in the range
150                                 time = currPoint.getTimestamp();
151                                 if (time.isValid())
152                                 {
153                                         if (startTime == null) startTime = time;
154                                         endTime = time;
155                                 }
156                                 // Calculate distances, again ignoring waypoints
157                                 if (!currPoint.isWaypoint())
158                                 {
159                                         if (lastPoint != null)
160                                         {
161                                                 _angDistance += DataPoint.calculateRadiansBetween(lastPoint, currPoint);
162                                         }
163                                         lastPoint = currPoint;
164                                 }
165                         }
166                         if (endTime != null)
167                         {
168                                 _seconds = endTime.getSecondsSince(startTime);
169                         }
170                         else
171                         {
172                                 _seconds = 0L;
173                         }
174                 }
175                 _valid = true;
176         }
177
178
179         /**
180          * @return start index
181          */
182         public int getStart()
183         {
184                 if (!_valid) recalculate();
185                 return _startIndex;
186         }
187
188
189         /**
190          * @return end index
191          */
192         public int getEnd()
193         {
194                 if (!_valid) recalculate();
195                 return _endIndex;
196         }
197
198
199         /**
200          * @return the altitude format, ie feet or metres
201          */
202         public int getAltitudeFormat()
203         {
204                 return _altitudeFormat;
205         }
206
207         /**
208          * @return altitude range
209          */
210         public IntegerRange getAltitudeRange()
211         {
212                 if (!_valid) recalculate();
213                 return _altitudeRange;
214         }
215
216
217         /**
218          * @return climb
219          */
220         public int getClimb()
221         {
222                 if (!_valid) recalculate();
223                 return _climb;
224         }
225
226         /**
227          * @return descent
228          */
229         public int getDescent()
230         {
231                 if (!_valid) recalculate();
232                 return _descent;
233         }
234
235
236         /**
237          * @return number of seconds spanned by selection
238          */
239         public long getNumSeconds()
240         {
241                 if (!_valid) recalculate();
242                 return _seconds;
243         }
244
245
246         /**
247          * @param inUnits distance units to use, from class Distance
248          * @return distance of Selection in specified units
249          */
250         public double getDistance(int inUnits)
251         {
252                 return Distance.convertRadiansToDistance(_angDistance, inUnits);
253         }
254
255
256         /**
257          * Clear selected point and range
258          */
259         public void clearAll()
260         {
261                 _currentPoint = -1;
262                 deselectRange();
263                 deselectPhoto();
264         }
265
266
267         /**
268          * Deselect range
269          */
270         public void deselectRange()
271         {
272                 _startIndex = _endIndex = -1;
273                 reset();
274                 check();
275         }
276
277
278         /**
279          * Select the range from the current point
280          */
281         public void selectRangeStart()
282         {
283                 selectRangeStart(_currentPoint);
284         }
285
286
287         /**
288          * Set the index for the start of the range selection
289          * @param inStartIndex start index
290          */
291         public void selectRangeStart(int inStartIndex)
292         {
293                 if (inStartIndex < 0)
294                 {
295                         _startIndex = _endIndex = -1;
296                 }
297                 else
298                 {
299                         _startIndex = inStartIndex;
300                         // Move end of selection to max if necessary
301                         if (_endIndex <= _startIndex)
302                         {
303                                 _endIndex = _track.getNumPoints() - 1;
304                         }
305                 }
306                 reset();
307                 _broker.informSubscribers();
308         }
309
310
311         /**
312          * Select the range up to the current point
313          */
314         public void selectRangeEnd()
315         {
316                 selectRangeEnd(_currentPoint);
317         }
318
319
320         /**
321          * Set the index for the end of the range selection
322          * @param inEndIndex end index
323          */
324         public void selectRangeEnd(int inEndIndex)
325         {
326                 if (inEndIndex < 0)
327                 {
328                         _startIndex = _endIndex = -1;
329                 }
330                 else
331                 {
332                         _endIndex = inEndIndex;
333                         // Move start of selection to min if necessary
334                         if (_startIndex > _endIndex || _startIndex < 0)
335                         {
336                                 _startIndex = 0;
337                         }
338                 }
339                 reset();
340                 _broker.informSubscribers();
341         }
342
343
344         /**
345          * Modify the selection given that the selected range has been deleted
346          */
347         public void modifyRangeDeleted()
348         {
349                 // Modify current point, if any
350                 if (_currentPoint > _endIndex)
351                 {
352                         _currentPoint -= (_endIndex - _startIndex);
353                 }
354                 else if (_currentPoint > _startIndex)
355                 {
356                         _currentPoint = _startIndex;
357                 }
358                 // Clear selected range
359                 _startIndex = _endIndex = -1;
360                 // Check for consistency and fire update
361                 check();
362         }
363
364
365         /**
366          * Modify the selection when a point is deleted
367          */
368         public void modifyPointDeleted()
369         {
370                 // current point index doesn't change, just gets checked
371                 // range needs to get altered if deleted point is inside or before
372                 if (hasRangeSelected() && _currentPoint <= _endIndex)
373                 {
374                         _endIndex--;
375                         if (_currentPoint < _startIndex)
376                                 _startIndex--;
377                         reset();
378                 }
379                 check();
380         }
381
382
383         /**
384          * Deselect photo
385          */
386         public void deselectPhoto()
387         {
388                 _currentPhotoIndex = -1;
389                 check();
390         }
391
392
393         /**
394          * Select the specified photo and point
395          * @param inPhotoIndex index of selected photo in PhotoList
396          * @param inPointIndex index of selected point
397          */
398         public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
399         {
400                 _currentPhotoIndex = inPhotoIndex;
401                 if (inPointIndex > -1)
402                 {
403                         // select associated point, if any
404                         selectPoint(inPointIndex);
405                 }
406                 else
407                 {
408                         // Check if not already done
409                         check();
410                 }
411         }
412
413
414         /**
415          * @return currently selected photo index
416          */
417         public int getCurrentPhotoIndex()
418         {
419                 return _currentPhotoIndex;
420         }
421
422
423         /**
424          * Check that the selection still makes sense
425          * and fire update message to listeners
426          */
427         private void check()
428         {
429                 if (_track != null)
430                 {
431                         if (_track.getNumPoints() > 0)
432                         {
433                                 int maxIndex = _track.getNumPoints() - 1;
434                                 if (_currentPoint > maxIndex)
435                                 {
436                                         _currentPoint = maxIndex;
437                                 }
438                                 if (_endIndex > maxIndex)
439                                 {
440                                         _endIndex = maxIndex;
441                                 }
442                                 if (_startIndex > maxIndex)
443                                 {
444                                         _startIndex = maxIndex;
445                                 }
446                         }
447                         else
448                         {
449                                 // track is empty, clear selections
450                                 _currentPoint = _startIndex = _endIndex = -1;
451                         }
452                 }
453                 _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
454         }
455 }