]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/Selection.java
Version 6, October 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 _totalSeconds = 0L, _movingSeconds = 0L;
21         private double _angDistance = -1.0, _angMovingDistance = -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                         Timestamp previousTime = null;
121                         DataPoint lastPoint = null, currPoint = null;
122                         _angDistance = 0.0; _angMovingDistance = 0.0;
123                         _totalSeconds = 0L; _movingSeconds = 0L;
124                         int altValue = 0;
125                         int lastAltValue = 0;
126                         boolean foundAlt = false;
127                         for (int i=_startIndex; i<=_endIndex; i++)
128                         {
129                                 currPoint = _track.getPoint(i);
130                                 altitude = currPoint.getAltitude();
131                                 // Ignore waypoints in altitude calculations
132                                 if (!currPoint.isWaypoint() && altitude.isValid())
133                                 {
134                                         altValue = altitude.getValue(_altitudeFormat);
135                                         if (_altitudeFormat == Altitude.FORMAT_NONE)
136                                                 _altitudeFormat = altitude.getFormat();
137                                         _altitudeRange.addValue(altValue);
138                                         if (foundAlt)
139                                         {
140                                                 if (altValue > lastAltValue)
141                                                         _climb += (altValue - lastAltValue);
142                                                 else
143                                                         _descent += (lastAltValue - altValue);
144                                         }
145                                         lastAltValue = altValue;
146                                         foundAlt = true;
147                                 }
148                                 // Store the first and last timestamp in the range
149                                 time = currPoint.getTimestamp();
150                                 if (time.isValid())
151                                 {
152                                         if (startTime == null || startTime.isAfter(time)) startTime = time;
153                                         if (endTime == null || time.isAfter(endTime)) endTime = time;
154                                         // add moving time
155                                         if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
156                                                 _movingSeconds += time.getSecondsSince(previousTime);
157                                         }
158                                         previousTime = time;
159                                 }
160                                 // Calculate distances, again ignoring waypoints
161                                 if (!currPoint.isWaypoint())
162                                 {
163                                         if (lastPoint != null)
164                                         {
165                                                 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
166                                                 _angDistance += radians;
167                                                 if (!currPoint.getSegmentStart()) {
168                                                         _angMovingDistance += radians;
169                                                 }
170                                         }
171                                         lastPoint = currPoint;
172                                 }
173                         }
174                         if (endTime != null) {
175                                 _totalSeconds = endTime.getSecondsSince(startTime);
176                         }
177                 }
178                 _valid = true;
179         }
180
181
182         /**
183          * @return start index
184          */
185         public int getStart()
186         {
187                 if (!_valid) recalculate();
188                 return _startIndex;
189         }
190
191
192         /**
193          * @return end index
194          */
195         public int getEnd()
196         {
197                 if (!_valid) recalculate();
198                 return _endIndex;
199         }
200
201
202         /**
203          * @return the altitude format, ie feet or metres
204          */
205         public int getAltitudeFormat()
206         {
207                 return _altitudeFormat;
208         }
209
210         /**
211          * @return altitude range
212          */
213         public IntegerRange getAltitudeRange()
214         {
215                 if (!_valid) recalculate();
216                 return _altitudeRange;
217         }
218
219
220         /**
221          * @return climb
222          */
223         public int getClimb()
224         {
225                 if (!_valid) recalculate();
226                 return _climb;
227         }
228
229         /**
230          * @return descent
231          */
232         public int getDescent()
233         {
234                 if (!_valid) recalculate();
235                 return _descent;
236         }
237
238
239         /**
240          * @return number of seconds spanned by selection
241          */
242         public long getNumSeconds()
243         {
244                 if (!_valid) recalculate();
245                 return _totalSeconds;
246         }
247
248         /**
249          * @return number of seconds spanned by segments within selection
250          */
251         public long getMovingSeconds()
252         {
253                 if (!_valid) recalculate();
254                 return _movingSeconds;
255         }
256
257         /**
258          * @param inUnits distance units to use, from class Distance
259          * @return distance of Selection in specified units
260          */
261         public double getDistance(int inUnits)
262         {
263                 return Distance.convertRadiansToDistance(_angDistance, inUnits);
264         }
265
266         /**
267          * @param inUnits distance units to use, from class Distance
268          * @return moving distance of Selection in specified units
269          */
270         public double getMovingDistance(int inUnits)
271         {
272                 return Distance.convertRadiansToDistance(_angMovingDistance, inUnits);
273         }
274
275         /**
276          * Clear selected point and range
277          */
278         public void clearAll()
279         {
280                 _currentPoint = -1;
281                 deselectRange();
282                 deselectPhoto();
283         }
284
285
286         /**
287          * Deselect range
288          */
289         public void deselectRange()
290         {
291                 _startIndex = _endIndex = -1;
292                 reset();
293                 check();
294         }
295
296
297         /**
298          * Select the range from the current point
299          */
300         public void selectRangeStart()
301         {
302                 selectRangeStart(_currentPoint);
303         }
304
305
306         /**
307          * Set the index for the start of the range selection
308          * @param inStartIndex start index
309          */
310         public void selectRangeStart(int inStartIndex)
311         {
312                 if (inStartIndex < 0)
313                 {
314                         _startIndex = _endIndex = -1;
315                 }
316                 else
317                 {
318                         _startIndex = inStartIndex;
319                         // Move end of selection to max if necessary
320                         if (_endIndex <= _startIndex)
321                         {
322                                 _endIndex = _track.getNumPoints() - 1;
323                         }
324                 }
325                 reset();
326                 UpdateMessageBroker.informSubscribers();
327         }
328
329
330         /**
331          * Select the range up to the current point
332          */
333         public void selectRangeEnd()
334         {
335                 selectRangeEnd(_currentPoint);
336         }
337
338
339         /**
340          * Set the index for the end of the range selection
341          * @param inEndIndex end index
342          */
343         public void selectRangeEnd(int inEndIndex)
344         {
345                 if (inEndIndex < 0)
346                 {
347                         _startIndex = _endIndex = -1;
348                 }
349                 else
350                 {
351                         _endIndex = inEndIndex;
352                         // Move start of selection to min if necessary
353                         if (_startIndex > _endIndex || _startIndex < 0)
354                         {
355                                 _startIndex = 0;
356                         }
357                 }
358                 reset();
359                 UpdateMessageBroker.informSubscribers();
360         }
361
362
363         /**
364          * Modify the selection given that the selected range has been deleted
365          */
366         public void modifyRangeDeleted()
367         {
368                 // Modify current point, if any
369                 if (_currentPoint > _endIndex)
370                 {
371                         _currentPoint -= (_endIndex - _startIndex);
372                 }
373                 else if (_currentPoint > _startIndex)
374                 {
375                         _currentPoint = _startIndex;
376                 }
377                 // Clear selected range
378                 _startIndex = _endIndex = -1;
379                 // Check for consistency and fire update
380                 check();
381         }
382
383
384         /**
385          * Modify the selection when a point is deleted
386          */
387         public void modifyPointDeleted()
388         {
389                 // current point index doesn't change, just gets checked
390                 // range needs to get altered if deleted point is inside or before
391                 if (hasRangeSelected() && _currentPoint <= _endIndex)
392                 {
393                         _endIndex--;
394                         if (_currentPoint < _startIndex)
395                                 _startIndex--;
396                         reset();
397                 }
398                 check();
399         }
400
401
402         /**
403          * Deselect photo
404          */
405         public void deselectPhoto()
406         {
407                 _currentPhotoIndex = -1;
408                 check();
409         }
410
411
412         /**
413          * Select the specified photo and point
414          * @param inPhotoIndex index of selected photo in PhotoList
415          * @param inPointIndex index of selected point
416          */
417         public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
418         {
419                 _currentPhotoIndex = inPhotoIndex;
420                 if (inPointIndex > -1)
421                 {
422                         // select associated point, if any
423                         selectPoint(inPointIndex);
424                 }
425                 else
426                 {
427                         // Check if not already done
428                         check();
429                 }
430         }
431
432
433         /**
434          * @return currently selected photo index
435          */
436         public int getCurrentPhotoIndex()
437         {
438                 return _currentPhotoIndex;
439         }
440
441         /**
442          * Check that the selection still makes sense
443          * and fire update message to listeners
444          */
445         private void check()
446         {
447                 if (_track != null)
448                 {
449                         if (_track.getNumPoints() > 0)
450                         {
451                                 int maxIndex = _track.getNumPoints() - 1;
452                                 if (_currentPoint > maxIndex)
453                                 {
454                                         _currentPoint = maxIndex;
455                                 }
456                                 if (_endIndex > maxIndex)
457                                 {
458                                         _endIndex = maxIndex;
459                                 }
460                                 if (_startIndex > maxIndex)
461                                 {
462                                         _startIndex = maxIndex;
463                                 }
464                         }
465                         else
466                         {
467                                 // track is empty, clear selections
468                                 _currentPoint = _startIndex = _endIndex = -1;
469                         }
470                 }
471                 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
472         }
473 }