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