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