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 _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;
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()
67 _altitudeFormat = Altitude.Format.NO_FORMAT;
69 if (_track.getNumPoints() > 0 && hasRangeSelected())
71 _altitudeRange = new IntegerRange();
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;
82 boolean foundAlt = false;
83 for (int i=_startIndex; i<=_endIndex; i++)
85 currPoint = _track.getPoint(i);
86 altitude = currPoint.getAltitude();
87 // Ignore waypoints in altitude calculations
88 if (!currPoint.isWaypoint() && altitude.isValid())
90 altValue = altitude.getValue(_altitudeFormat);
91 if (_altitudeFormat == Altitude.Format.NO_FORMAT)
92 _altitudeFormat = altitude.getFormat();
93 _altitudeRange.addValue(altValue);
96 if (altValue > lastAltValue)
97 _climb += (altValue - lastAltValue);
99 _descent += (lastAltValue - altValue);
101 lastAltValue = altValue;
104 // Store the first and last timestamp in the range
105 time = currPoint.getTimestamp();
108 if (startTime == null || startTime.isAfter(time)) startTime = time;
109 if (endTime == null || time.isAfter(endTime)) endTime = time;
111 if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
112 _movingSeconds += time.getSecondsSince(previousTime);
116 // Calculate distances, again ignoring waypoints
117 if (!currPoint.isWaypoint())
119 if (lastPoint != null)
121 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
122 _angDistance += radians;
123 if (currPoint.getSegmentStart()) {
127 _angMovingDistance += radians;
130 lastPoint = currPoint;
131 // If it's a track point then there must be at least one segment
132 if (_numSegments == 0) {_numSegments = 1;}
135 if (endTime != null) {
136 _totalSeconds = endTime.getSecondsSince(startTime);
144 * @return start index
146 public int getStart()
148 if (!_valid) recalculate();
158 if (!_valid) recalculate();
164 * @return the altitude format, ie feet or metres
166 public Altitude.Format getAltitudeFormat()
168 return _altitudeFormat;
172 * @return altitude range
174 public IntegerRange getAltitudeRange()
176 if (!_valid) recalculate();
177 return _altitudeRange;
184 public int getClimb()
186 if (!_valid) recalculate();
193 public int getDescent()
195 if (!_valid) recalculate();
201 * @return number of seconds spanned by selection
203 public long getNumSeconds()
205 if (!_valid) recalculate();
206 return _totalSeconds;
210 * @return number of seconds spanned by segments within selection
212 public long getMovingSeconds()
214 if (!_valid) recalculate();
215 return _movingSeconds;
219 * @param inUnits distance units to use, from class Distance
220 * @return distance of Selection in specified units
222 public double getDistance(Distance.Units inUnits)
224 return Distance.convertRadiansToDistance(_angDistance, inUnits);
228 * @param inUnits distance units to use, from class Distance
229 * @return moving distance of Selection in specified units
231 public double getMovingDistance(Distance.Units inUnits)
233 return Distance.convertRadiansToDistance(_angMovingDistance, inUnits);
237 * @return number of segments in selection
239 public int getNumSegments()
245 * Clear selected point, range and photo
247 public void clearAll()
251 _currentPhotoIndex = -1;
257 * Select range from start to end
258 * @param inStartIndex index of start of range
259 * @param inEndIndex index of end of range
261 public void selectRange(int inStartIndex, int inEndIndex)
263 _startIndex = inStartIndex;
264 _endIndex = inEndIndex;
271 * Select the range from the current point
273 public void selectRangeStart()
275 selectRangeStart(_currentPoint);
280 * Set the index for the start of the range selection
281 * @param inStartIndex start index
283 private void selectRangeStart(int inStartIndex)
285 if (inStartIndex < 0)
287 _startIndex = _endIndex = -1;
291 _startIndex = inStartIndex;
292 // Move end of selection to max if necessary
293 if (_endIndex <= _startIndex)
295 _endIndex = _track.getNumPoints() - 1;
299 UpdateMessageBroker.informSubscribers();
304 * Select the range up to the current point
306 public void selectRangeEnd()
308 selectRangeEnd(_currentPoint);
313 * Set the index for the end of the range selection
314 * @param inEndIndex end index
316 public void selectRangeEnd(int inEndIndex)
320 _startIndex = _endIndex = -1;
324 _endIndex = inEndIndex;
325 // Move start of selection to min if necessary
326 if (_startIndex > _endIndex || _startIndex < 0) {
331 UpdateMessageBroker.informSubscribers();
336 * Modify the selection given that the selected range has been deleted
338 public void modifyRangeDeleted()
340 // Modify current point, if any
341 if (_currentPoint > _endIndex)
343 _currentPoint -= (_endIndex - _startIndex);
345 else if (_currentPoint > _startIndex)
347 _currentPoint = _startIndex;
349 // Clear selected range
350 _startIndex = _endIndex = -1;
351 // Check for consistency and fire update
357 * Modify the selection when a point is deleted
359 public void modifyPointDeleted()
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)
366 if (_currentPoint < _startIndex)
375 * Select the specified photo and point
376 * @param inPhotoIndex index of selected photo in PhotoList
377 * @param inPointIndex index of selected point
379 public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
381 _currentPhotoIndex = inPhotoIndex;
382 _currentPoint = inPointIndex;
388 * @return currently selected photo index
390 public int getCurrentPhotoIndex()
392 return _currentPhotoIndex;
396 * Check that the selection still makes sense
397 * and fire update message to listeners
403 if (_track.getNumPoints() > 0)
405 int maxIndex = _track.getNumPoints() - 1;
406 if (_currentPoint > maxIndex)
408 _currentPoint = maxIndex;
410 if (_endIndex > maxIndex)
412 _endIndex = maxIndex;
414 if (_startIndex > maxIndex)
416 _startIndex = maxIndex;
421 // track is empty, clear selections
422 _currentPoint = _startIndex = _endIndex = -1;
425 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);