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;
26 * @param inTrack track object
28 public Selection(Track inTrack)
35 * Mark selection invalid so it will be recalculated
37 public void markInvalid()
44 * @return the current point index
46 public int getCurrentPointIndex()
53 * @return true if range is selected
55 public boolean hasRangeSelected()
57 return _startIndex >= 0 && _endIndex > _startIndex;
62 * Recalculate all selection details
64 private void recalculate()
66 final int numPoints = _track.getNumPoints();
67 // Recheck if the number of points has changed
68 if (numPoints != _prevNumPoints) {
69 _prevNumPoints = numPoints;
72 if (numPoints > 0 && hasRangeSelected())
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++)
84 currPoint = _track.getPoint(i);
85 altitude = currPoint.getAltitude();
86 // Ignore waypoints in altitude calculations
87 if (!currPoint.isWaypoint() && altitude.isValid())
89 _altitudeRange.addValue(altitude);
91 // Store the first and last timestamp in the range
92 time = currPoint.getTimestamp();
95 if (startTime == null || startTime.isAfter(time)) startTime = time;
96 if (endTime == null || time.isAfter(endTime)) endTime = time;
98 if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
99 _movingSeconds += time.getSecondsSince(previousTime);
103 // Calculate distances, again ignoring waypoints
104 if (!currPoint.isWaypoint())
106 if (lastPoint != null)
108 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
109 _angDistance += radians;
110 if (!currPoint.getSegmentStart()) {
111 _angMovingDistance += radians;
114 lastPoint = currPoint;
117 if (endTime != null) {
118 _totalSeconds = endTime.getSecondsSince(startTime);
126 * @return start index
128 public int getStart()
130 if (!_valid) recalculate();
140 if (!_valid) recalculate();
145 * @return altitude range
147 public AltitudeRange getAltitudeRange()
149 if (!_valid) recalculate();
150 return _altitudeRange;
155 * @return number of seconds spanned by selection
157 public long getNumSeconds()
159 if (!_valid) recalculate();
160 return _totalSeconds;
164 * @return number of seconds spanned by segments within selection
166 public long getMovingSeconds()
168 if (!_valid) recalculate();
169 return _movingSeconds;
173 * @return distance of Selection in specified units
175 public double getDistance()
177 return Distance.convertRadiansToDistance(_angDistance);
181 * @return moving distance of Selection in current units
183 public double getMovingDistance()
185 return Distance.convertRadiansToDistance(_angMovingDistance);
189 * Clear selected point, range, photo and audio
191 public void clearAll()
195 _currentPhotoIndex = -1;
196 _currentAudioIndex = -1;
202 * Select range from start to end
203 * @param inStartIndex index of start of range
204 * @param inEndIndex index of end of range
206 public void selectRange(int inStartIndex, int inEndIndex)
208 _startIndex = inStartIndex;
209 _endIndex = inEndIndex;
216 * Select the range from the current point
218 public void selectRangeStart()
220 selectRangeStart(_currentPoint);
225 * Set the index for the start of the range selection
226 * @param inStartIndex start index
228 private void selectRangeStart(int inStartIndex)
230 if (inStartIndex < 0)
232 _startIndex = _endIndex = -1;
236 _startIndex = inStartIndex;
237 // Move end of selection to max if necessary
238 if (_endIndex <= _startIndex)
240 _endIndex = _track.getNumPoints() - 1;
244 UpdateMessageBroker.informSubscribers();
249 * Select the range up to the current point
251 public void selectRangeEnd()
253 selectRangeEnd(_currentPoint);
258 * Set the index for the end of the range selection
259 * @param inEndIndex end index
261 public void selectRangeEnd(int inEndIndex)
265 _startIndex = _endIndex = -1;
269 _endIndex = inEndIndex;
270 // Move start of selection to min if necessary
271 if (_startIndex > _endIndex || _startIndex < 0) {
276 UpdateMessageBroker.informSubscribers();
281 * Modify the selection given that the selected range has been deleted
283 public void modifyRangeDeleted()
285 // Modify current point, if any
286 if (_currentPoint > _endIndex)
288 _currentPoint -= (_endIndex - _startIndex);
290 else if (_currentPoint > _startIndex)
292 _currentPoint = _startIndex;
294 // Clear selected range
295 _startIndex = _endIndex = -1;
296 // Check for consistency and fire update
302 * Modify the selection when a point is deleted
304 public void modifyPointDeleted()
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)
311 if (_currentPoint < _startIndex)
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
325 public void selectPointPhotoAudio(int inPointIndex, int inPhotoIndex, int inAudioIndex)
327 _currentPoint = inPointIndex;
328 _currentPhotoIndex = inPhotoIndex;
329 _currentAudioIndex = inAudioIndex;
335 * @return currently selected photo index
337 public int getCurrentPhotoIndex()
339 return _currentPhotoIndex;
343 * @return currently selected audio index
345 public int getCurrentAudioIndex()
347 return _currentAudioIndex;
351 * Check that the selection still makes sense
352 * and fire update message to listeners
356 if (_track != null && _track.getNumPoints() > 0)
358 int maxIndex = _track.getNumPoints() - 1;
359 if (_currentPoint > maxIndex)
361 _currentPoint = maxIndex;
363 if (_endIndex > maxIndex)
365 _endIndex = maxIndex;
367 if (_startIndex > maxIndex)
369 _startIndex = maxIndex;
374 // track is empty, clear selections
375 _currentPoint = _startIndex = _endIndex = -1;
377 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);