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 boolean _multipleSegments = false;
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;
68 _multipleSegments = false;
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()) {
124 _multipleSegments = true;
127 _angMovingDistance += radians;
130 lastPoint = currPoint;
133 if (endTime != null) {
134 _totalSeconds = endTime.getSecondsSince(startTime);
142 * @return start index
144 public int getStart()
146 if (!_valid) recalculate();
156 if (!_valid) recalculate();
162 * @return the altitude format, ie feet or metres
164 public Altitude.Format getAltitudeFormat()
166 return _altitudeFormat;
170 * @return altitude range
172 public IntegerRange getAltitudeRange()
174 if (!_valid) recalculate();
175 return _altitudeRange;
182 public int getClimb()
184 if (!_valid) recalculate();
191 public int getDescent()
193 if (!_valid) recalculate();
199 * @return number of seconds spanned by selection
201 public long getNumSeconds()
203 if (!_valid) recalculate();
204 return _totalSeconds;
208 * @return number of seconds spanned by segments within selection
210 public long getMovingSeconds()
212 if (!_valid) recalculate();
213 return _movingSeconds;
217 * @param inUnits distance units to use, from class Distance
218 * @return distance of Selection in specified units
220 public double getDistance(Distance.Units inUnits)
222 return Distance.convertRadiansToDistance(_angDistance, inUnits);
226 * @param inUnits distance units to use, from class Distance
227 * @return moving distance of Selection in specified units
229 public double getMovingDistance(Distance.Units inUnits)
231 return Distance.convertRadiansToDistance(_angMovingDistance, inUnits);
235 * @return true if track has multiple segments
237 public boolean getHasMultipleSegments()
239 return _multipleSegments;
243 * Clear selected point, range and photo
245 public void clearAll()
249 _currentPhotoIndex = -1;
256 * @param inStartIndex index of start of range
257 * @param inEndIndex index of end of range
259 public void selectRange(int inStartIndex, int inEndIndex)
261 _startIndex = inStartIndex;
262 _endIndex = inEndIndex;
269 * Select the range from the current point
271 public void selectRangeStart()
273 selectRangeStart(_currentPoint);
278 * Set the index for the start of the range selection
279 * @param inStartIndex start index
281 private void selectRangeStart(int inStartIndex)
283 if (inStartIndex < 0)
285 _startIndex = _endIndex = -1;
289 _startIndex = inStartIndex;
290 // Move end of selection to max if necessary
291 if (_endIndex <= _startIndex)
293 _endIndex = _track.getNumPoints() - 1;
297 UpdateMessageBroker.informSubscribers();
302 * Select the range up to the current point
304 public void selectRangeEnd()
306 selectRangeEnd(_currentPoint);
311 * Set the index for the end of the range selection
312 * @param inEndIndex end index
314 public void selectRangeEnd(int inEndIndex)
318 _startIndex = _endIndex = -1;
322 _endIndex = inEndIndex;
323 // Move start of selection to min if necessary
324 if (_startIndex > _endIndex || _startIndex < 0) {
329 UpdateMessageBroker.informSubscribers();
334 * Modify the selection given that the selected range has been deleted
336 public void modifyRangeDeleted()
338 // Modify current point, if any
339 if (_currentPoint > _endIndex)
341 _currentPoint -= (_endIndex - _startIndex);
343 else if (_currentPoint > _startIndex)
345 _currentPoint = _startIndex;
347 // Clear selected range
348 _startIndex = _endIndex = -1;
349 // Check for consistency and fire update
355 * Modify the selection when a point is deleted
357 public void modifyPointDeleted()
359 // current point index doesn't change, just gets checked
360 // range needs to get altered if deleted point is inside or before
361 if (hasRangeSelected() && _currentPoint <= _endIndex)
364 if (_currentPoint < _startIndex)
373 * Select the specified photo and point
374 * @param inPhotoIndex index of selected photo in PhotoList
375 * @param inPointIndex index of selected point
377 public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
379 _currentPhotoIndex = inPhotoIndex;
380 _currentPoint = inPointIndex;
386 * @return currently selected photo index
388 public int getCurrentPhotoIndex()
390 return _currentPhotoIndex;
394 * Check that the selection still makes sense
395 * and fire update message to listeners
401 if (_track.getNumPoints() > 0)
403 int maxIndex = _track.getNumPoints() - 1;
404 if (_currentPoint > maxIndex)
406 _currentPoint = maxIndex;
408 if (_endIndex > maxIndex)
410 _endIndex = maxIndex;
412 if (_startIndex > maxIndex)
414 _startIndex = maxIndex;
419 // track is empty, clear selections
420 _currentPoint = _startIndex = _endIndex = -1;
423 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);