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