]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/Selection.java
Version 14, October 2012
[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 _prevNumPoints = 0;
16         private int _startIndex = -1, _endIndex = -1;
17         private int _currentPhotoIndex = -1;
18         private int _currentAudioIndex = -1;
19         private AltitudeRange _altitudeRange = null;
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                 _numSegments = 0;
68                 final int numPoints = _track.getNumPoints();
69                 // Recheck if the number of points has changed
70                 if (numPoints != _prevNumPoints) {
71                         _prevNumPoints = numPoints;
72                         check();
73                 }
74                 if (numPoints > 0 && hasRangeSelected())
75                 {
76                         _altitudeRange = new AltitudeRange();
77                         Altitude altitude = null;
78                         Timestamp time = null, startTime = null, endTime = null;
79                         Timestamp previousTime = null;
80                         DataPoint lastPoint = null, currPoint = null;
81                         _angDistance = 0.0; _angMovingDistance = 0.0;
82                         _totalSeconds = 0L; _movingSeconds = 0L;
83                         // Loop over points in selection
84                         for (int i=_startIndex; i<=_endIndex; i++)
85                         {
86                                 currPoint = _track.getPoint(i);
87                                 altitude = currPoint.getAltitude();
88                                 // Ignore waypoints in altitude calculations
89                                 if (!currPoint.isWaypoint() && altitude.isValid())
90                                 {
91                                         _altitudeRange.addValue(altitude);
92                                 }
93                                 // Store the first and last timestamp in the range
94                                 time = currPoint.getTimestamp();
95                                 if (time.isValid())
96                                 {
97                                         if (startTime == null || startTime.isAfter(time)) startTime = time;
98                                         if (endTime == null || time.isAfter(endTime)) endTime = time;
99                                         // add moving time
100                                         if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
101                                                 _movingSeconds += time.getSecondsSince(previousTime);
102                                         }
103                                         previousTime = time;
104                                 }
105                                 // Calculate distances, again ignoring waypoints
106                                 if (!currPoint.isWaypoint())
107                                 {
108                                         if (lastPoint != null)
109                                         {
110                                                 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
111                                                 _angDistance += radians;
112                                                 if (currPoint.getSegmentStart()) {
113                                                         _numSegments++;
114                                                 }
115                                                 else {
116                                                         _angMovingDistance += radians;
117                                                 }
118                                         }
119                                         lastPoint = currPoint;
120                                         // If it's a track point then there must be at least one segment
121                                         if (_numSegments == 0) {_numSegments = 1;}
122                                 }
123                         }
124                         if (endTime != null) {
125                                 _totalSeconds = endTime.getSecondsSince(startTime);
126                         }
127                 }
128                 _valid = true;
129         }
130
131
132         /**
133          * @return start index
134          */
135         public int getStart()
136         {
137                 if (!_valid) recalculate();
138                 return _startIndex;
139         }
140
141
142         /**
143          * @return end index
144          */
145         public int getEnd()
146         {
147                 if (!_valid) recalculate();
148                 return _endIndex;
149         }
150
151         /**
152          * @return altitude range
153          */
154         public AltitudeRange getAltitudeRange()
155         {
156                 if (!_valid) recalculate();
157                 return _altitudeRange;
158         }
159
160
161         /**
162          * @return number of seconds spanned by selection
163          */
164         public long getNumSeconds()
165         {
166                 if (!_valid) recalculate();
167                 return _totalSeconds;
168         }
169
170         /**
171          * @return number of seconds spanned by segments within selection
172          */
173         public long getMovingSeconds()
174         {
175                 if (!_valid) recalculate();
176                 return _movingSeconds;
177         }
178
179         /**
180          * @return distance of Selection in specified units
181          */
182         public double getDistance()
183         {
184                 return Distance.convertRadiansToDistance(_angDistance);
185         }
186
187         /**
188          * @return moving distance of Selection in current units
189          */
190         public double getMovingDistance()
191         {
192                 return Distance.convertRadiansToDistance(_angMovingDistance);
193         }
194
195         /**
196          * @return number of segments in selection
197          */
198         public int getNumSegments()
199         {
200                 return _numSegments;
201         }
202
203         /**
204          * Clear selected point, range, photo and audio
205          */
206         public void clearAll()
207         {
208                 _currentPoint = -1;
209                 selectRange(-1, -1);
210                 _currentPhotoIndex = -1;
211                 _currentAudioIndex = -1;
212                 check();
213         }
214
215
216         /**
217          * Select range from start to end
218          * @param inStartIndex index of start of range
219          * @param inEndIndex index of end of range
220          */
221         public void selectRange(int inStartIndex, int inEndIndex)
222         {
223                 _startIndex = inStartIndex;
224                 _endIndex = inEndIndex;
225                 markInvalid();
226                 check();
227         }
228
229
230         /**
231          * Select the range from the current point
232          */
233         public void selectRangeStart()
234         {
235                 selectRangeStart(_currentPoint);
236         }
237
238
239         /**
240          * Set the index for the start of the range selection
241          * @param inStartIndex start index
242          */
243         private void selectRangeStart(int inStartIndex)
244         {
245                 if (inStartIndex < 0)
246                 {
247                         _startIndex = _endIndex = -1;
248                 }
249                 else
250                 {
251                         _startIndex = inStartIndex;
252                         // Move end of selection to max if necessary
253                         if (_endIndex <= _startIndex)
254                         {
255                                 _endIndex = _track.getNumPoints() - 1;
256                         }
257                 }
258                 markInvalid();
259                 UpdateMessageBroker.informSubscribers();
260         }
261
262
263         /**
264          * Select the range up to the current point
265          */
266         public void selectRangeEnd()
267         {
268                 selectRangeEnd(_currentPoint);
269         }
270
271
272         /**
273          * Set the index for the end of the range selection
274          * @param inEndIndex end index
275          */
276         public void selectRangeEnd(int inEndIndex)
277         {
278                 if (inEndIndex < 0)
279                 {
280                         _startIndex = _endIndex = -1;
281                 }
282                 else
283                 {
284                         _endIndex = inEndIndex;
285                         // Move start of selection to min if necessary
286                         if (_startIndex > _endIndex || _startIndex < 0) {
287                                 _startIndex = 0;
288                         }
289                 }
290                 markInvalid();
291                 UpdateMessageBroker.informSubscribers();
292         }
293
294
295         /**
296          * Modify the selection given that the selected range has been deleted
297          */
298         public void modifyRangeDeleted()
299         {
300                 // Modify current point, if any
301                 if (_currentPoint > _endIndex)
302                 {
303                         _currentPoint -= (_endIndex - _startIndex);
304                 }
305                 else if (_currentPoint > _startIndex)
306                 {
307                         _currentPoint = _startIndex;
308                 }
309                 // Clear selected range
310                 _startIndex = _endIndex = -1;
311                 // Check for consistency and fire update
312                 check();
313         }
314
315
316         /**
317          * Modify the selection when a point is deleted
318          */
319         public void modifyPointDeleted()
320         {
321                 // current point index doesn't change, just gets checked
322                 // range needs to get altered if deleted point is inside or before
323                 if (hasRangeSelected() && _currentPoint <= _endIndex)
324                 {
325                         _endIndex--;
326                         if (_currentPoint < _startIndex)
327                                 _startIndex--;
328                         markInvalid();
329                 }
330                 check();
331         }
332
333
334         /**
335          * Select the specified photo and point
336          * @param inPointIndex index of selected point
337          * @param inPhotoIndex index of selected photo in PhotoList
338          * @param inAudioIndex index of selected audio item
339          */
340         public void selectPointPhotoAudio(int inPointIndex, int inPhotoIndex, int inAudioIndex)
341         {
342                 _currentPoint = inPointIndex;
343                 _currentPhotoIndex = inPhotoIndex;
344                 _currentAudioIndex = inAudioIndex;
345                 check();
346         }
347
348
349         /**
350          * @return currently selected photo index
351          */
352         public int getCurrentPhotoIndex()
353         {
354                 return _currentPhotoIndex;
355         }
356
357         /**
358          * @return currently selected audio index
359          */
360         public int getCurrentAudioIndex()
361         {
362                 return _currentAudioIndex;
363         }
364
365         /**
366          * Check that the selection still makes sense
367          * and fire update message to listeners
368          */
369         private void check()
370         {
371                 if (_track != null && _track.getNumPoints() > 0)
372                 {
373                         int maxIndex = _track.getNumPoints() - 1;
374                         if (_currentPoint > maxIndex)
375                         {
376                                 _currentPoint = maxIndex;
377                         }
378                         if (_endIndex > maxIndex)
379                         {
380                                 _endIndex = maxIndex;
381                         }
382                         if (_startIndex > maxIndex)
383                         {
384                                 _startIndex = maxIndex;
385                         }
386                 }
387                 else
388                 {
389                         // track is empty, clear selections
390                         _currentPoint = _startIndex = _endIndex = -1;
391                 }
392                 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
393         }
394 }