1 package tim.prune.data;
3 import tim.prune.DataSubscriber;
4 import tim.prune.UpdateMessageBroker;
7 * Class to represent a selected portion of a Track
10 public class Selection
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;
27 * @param inTrack track object
29 public Selection(Track inTrack)
36 * Mark selection invalid so it will be recalculated
38 public void markInvalid()
45 * @return the current point index
47 public int getCurrentPointIndex()
54 * @return true if range is selected
56 public boolean hasRangeSelected()
58 return _startIndex >= 0 && _endIndex > _startIndex;
63 * Recalculate all selection details
65 private void recalculate()
68 final int numPoints = _track.getNumPoints();
69 // Recheck if the number of points has changed
70 if (numPoints != _prevNumPoints) {
71 _prevNumPoints = numPoints;
74 if (numPoints > 0 && hasRangeSelected())
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++)
86 currPoint = _track.getPoint(i);
87 altitude = currPoint.getAltitude();
88 // Ignore waypoints in altitude calculations
89 if (!currPoint.isWaypoint() && altitude.isValid())
91 _altitudeRange.addValue(altitude);
93 // Store the first and last timestamp in the range
94 time = currPoint.getTimestamp();
97 if (startTime == null || startTime.isAfter(time)) startTime = time;
98 if (endTime == null || time.isAfter(endTime)) endTime = time;
100 if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
101 _movingSeconds += time.getSecondsSince(previousTime);
105 // Calculate distances, again ignoring waypoints
106 if (!currPoint.isWaypoint())
108 if (lastPoint != null)
110 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
111 _angDistance += radians;
112 if (currPoint.getSegmentStart()) {
116 _angMovingDistance += radians;
119 lastPoint = currPoint;
120 // If it's a track point then there must be at least one segment
121 if (_numSegments == 0) {_numSegments = 1;}
124 if (endTime != null) {
125 _totalSeconds = endTime.getSecondsSince(startTime);
133 * @return start index
135 public int getStart()
137 if (!_valid) recalculate();
147 if (!_valid) recalculate();
152 * @return altitude range
154 public AltitudeRange getAltitudeRange()
156 if (!_valid) recalculate();
157 return _altitudeRange;
162 * @return number of seconds spanned by selection
164 public long getNumSeconds()
166 if (!_valid) recalculate();
167 return _totalSeconds;
171 * @return number of seconds spanned by segments within selection
173 public long getMovingSeconds()
175 if (!_valid) recalculate();
176 return _movingSeconds;
180 * @return distance of Selection in specified units
182 public double getDistance()
184 return Distance.convertRadiansToDistance(_angDistance);
188 * @return moving distance of Selection in current units
190 public double getMovingDistance()
192 return Distance.convertRadiansToDistance(_angMovingDistance);
196 * @return number of segments in selection
198 public int getNumSegments()
204 * Clear selected point, range, photo and audio
206 public void clearAll()
210 _currentPhotoIndex = -1;
211 _currentAudioIndex = -1;
217 * Select range from start to end
218 * @param inStartIndex index of start of range
219 * @param inEndIndex index of end of range
221 public void selectRange(int inStartIndex, int inEndIndex)
223 _startIndex = inStartIndex;
224 _endIndex = inEndIndex;
231 * Select the range from the current point
233 public void selectRangeStart()
235 selectRangeStart(_currentPoint);
240 * Set the index for the start of the range selection
241 * @param inStartIndex start index
243 private void selectRangeStart(int inStartIndex)
245 if (inStartIndex < 0)
247 _startIndex = _endIndex = -1;
251 _startIndex = inStartIndex;
252 // Move end of selection to max if necessary
253 if (_endIndex <= _startIndex)
255 _endIndex = _track.getNumPoints() - 1;
259 UpdateMessageBroker.informSubscribers();
264 * Select the range up to the current point
266 public void selectRangeEnd()
268 selectRangeEnd(_currentPoint);
273 * Set the index for the end of the range selection
274 * @param inEndIndex end index
276 public void selectRangeEnd(int inEndIndex)
280 _startIndex = _endIndex = -1;
284 _endIndex = inEndIndex;
285 // Move start of selection to min if necessary
286 if (_startIndex > _endIndex || _startIndex < 0) {
291 UpdateMessageBroker.informSubscribers();
296 * Modify the selection given that the selected range has been deleted
298 public void modifyRangeDeleted()
300 // Modify current point, if any
301 if (_currentPoint > _endIndex)
303 _currentPoint -= (_endIndex - _startIndex);
305 else if (_currentPoint > _startIndex)
307 _currentPoint = _startIndex;
309 // Clear selected range
310 _startIndex = _endIndex = -1;
311 // Check for consistency and fire update
317 * Modify the selection when a point is deleted
319 public void modifyPointDeleted()
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)
326 if (_currentPoint < _startIndex)
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
340 public void selectPointPhotoAudio(int inPointIndex, int inPhotoIndex, int inAudioIndex)
342 _currentPoint = inPointIndex;
343 _currentPhotoIndex = inPhotoIndex;
344 _currentAudioIndex = inAudioIndex;
350 * @return currently selected photo index
352 public int getCurrentPhotoIndex()
354 return _currentPhotoIndex;
358 * @return currently selected audio index
360 public int getCurrentAudioIndex()
362 return _currentAudioIndex;
366 * Check that the selection still makes sense
367 * and fire update message to listeners
371 if (_track != null && _track.getNumPoints() > 0)
373 int maxIndex = _track.getNumPoints() - 1;
374 if (_currentPoint > maxIndex)
376 _currentPoint = maxIndex;
378 if (_endIndex > maxIndex)
380 _endIndex = maxIndex;
382 if (_startIndex > maxIndex)
384 _startIndex = maxIndex;
389 // track is empty, clear selections
390 _currentPoint = _startIndex = _endIndex = -1;
392 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);