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 int _altitudeFormat = Altitude.FORMAT_NONE;
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 * Reset selection to be recalculated
44 * Select the point at the given index
45 * @param inIndex index number of selected point
47 public void selectPoint(int inIndex)
51 _currentPoint = inIndex;
57 * Select the specified point and range in one go
58 * @param inPointIndex point selection
59 * @param inStart range start
60 * @param inEnd range end
62 public void select(int inPointIndex, int inStart, int inEnd)
64 _currentPoint = inPointIndex;
65 _startIndex = inStart;
73 * Select the previous point
75 public void selectPreviousPoint()
77 if (_currentPoint > 0)
78 selectPoint(_currentPoint - 1);
82 * Select the next point
84 public void selectNextPoint()
86 selectPoint(_currentPoint + 1);
90 * @return the current point index
92 public int getCurrentPointIndex()
99 * @return true if range is selected
101 public boolean hasRangeSelected()
103 return _startIndex >= 0 && _endIndex > _startIndex;
108 * Recalculate all selection details
110 private void recalculate()
112 _altitudeFormat = Altitude.FORMAT_NONE;
113 if (_track.getNumPoints() > 0 && hasRangeSelected())
115 _altitudeRange = new IntegerRange();
118 Altitude altitude = null;
119 Timestamp time = null, startTime = null, endTime = null;
120 Timestamp previousTime = null;
121 DataPoint lastPoint = null, currPoint = null;
122 _angDistance = 0.0; _angMovingDistance = 0.0;
123 _totalSeconds = 0L; _movingSeconds = 0L;
125 int lastAltValue = 0;
126 boolean foundAlt = false;
127 for (int i=_startIndex; i<=_endIndex; i++)
129 currPoint = _track.getPoint(i);
130 altitude = currPoint.getAltitude();
131 // Ignore waypoints in altitude calculations
132 if (!currPoint.isWaypoint() && altitude.isValid())
134 altValue = altitude.getValue(_altitudeFormat);
135 if (_altitudeFormat == Altitude.FORMAT_NONE)
136 _altitudeFormat = altitude.getFormat();
137 _altitudeRange.addValue(altValue);
140 if (altValue > lastAltValue)
141 _climb += (altValue - lastAltValue);
143 _descent += (lastAltValue - altValue);
145 lastAltValue = altValue;
148 // Store the first and last timestamp in the range
149 time = currPoint.getTimestamp();
152 if (startTime == null || startTime.isAfter(time)) startTime = time;
153 if (endTime == null || time.isAfter(endTime)) endTime = time;
155 if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
156 _movingSeconds += time.getSecondsSince(previousTime);
160 // Calculate distances, again ignoring waypoints
161 if (!currPoint.isWaypoint())
163 if (lastPoint != null)
165 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
166 _angDistance += radians;
167 if (!currPoint.getSegmentStart()) {
168 _angMovingDistance += radians;
171 lastPoint = currPoint;
174 if (endTime != null) {
175 _totalSeconds = endTime.getSecondsSince(startTime);
183 * @return start index
185 public int getStart()
187 if (!_valid) recalculate();
197 if (!_valid) recalculate();
203 * @return the altitude format, ie feet or metres
205 public int getAltitudeFormat()
207 return _altitudeFormat;
211 * @return altitude range
213 public IntegerRange getAltitudeRange()
215 if (!_valid) recalculate();
216 return _altitudeRange;
223 public int getClimb()
225 if (!_valid) recalculate();
232 public int getDescent()
234 if (!_valid) recalculate();
240 * @return number of seconds spanned by selection
242 public long getNumSeconds()
244 if (!_valid) recalculate();
245 return _totalSeconds;
249 * @return number of seconds spanned by segments within selection
251 public long getMovingSeconds()
253 if (!_valid) recalculate();
254 return _movingSeconds;
258 * @param inUnits distance units to use, from class Distance
259 * @return distance of Selection in specified units
261 public double getDistance(int inUnits)
263 return Distance.convertRadiansToDistance(_angDistance, inUnits);
267 * @param inUnits distance units to use, from class Distance
268 * @return moving distance of Selection in specified units
270 public double getMovingDistance(int inUnits)
272 return Distance.convertRadiansToDistance(_angMovingDistance, inUnits);
276 * Clear selected point and range
278 public void clearAll()
289 public void deselectRange()
291 _startIndex = _endIndex = -1;
298 * Select the range from the current point
300 public void selectRangeStart()
302 selectRangeStart(_currentPoint);
307 * Set the index for the start of the range selection
308 * @param inStartIndex start index
310 public void selectRangeStart(int inStartIndex)
312 if (inStartIndex < 0)
314 _startIndex = _endIndex = -1;
318 _startIndex = inStartIndex;
319 // Move end of selection to max if necessary
320 if (_endIndex <= _startIndex)
322 _endIndex = _track.getNumPoints() - 1;
326 UpdateMessageBroker.informSubscribers();
331 * Select the range up to the current point
333 public void selectRangeEnd()
335 selectRangeEnd(_currentPoint);
340 * Set the index for the end of the range selection
341 * @param inEndIndex end index
343 public void selectRangeEnd(int inEndIndex)
347 _startIndex = _endIndex = -1;
351 _endIndex = inEndIndex;
352 // Move start of selection to min if necessary
353 if (_startIndex > _endIndex || _startIndex < 0)
359 UpdateMessageBroker.informSubscribers();
364 * Modify the selection given that the selected range has been deleted
366 public void modifyRangeDeleted()
368 // Modify current point, if any
369 if (_currentPoint > _endIndex)
371 _currentPoint -= (_endIndex - _startIndex);
373 else if (_currentPoint > _startIndex)
375 _currentPoint = _startIndex;
377 // Clear selected range
378 _startIndex = _endIndex = -1;
379 // Check for consistency and fire update
385 * Modify the selection when a point is deleted
387 public void modifyPointDeleted()
389 // current point index doesn't change, just gets checked
390 // range needs to get altered if deleted point is inside or before
391 if (hasRangeSelected() && _currentPoint <= _endIndex)
394 if (_currentPoint < _startIndex)
405 public void deselectPhoto()
407 _currentPhotoIndex = -1;
413 * Select the specified photo and point
414 * @param inPhotoIndex index of selected photo in PhotoList
415 * @param inPointIndex index of selected point
417 public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
419 _currentPhotoIndex = inPhotoIndex;
420 if (inPointIndex > -1)
422 // select associated point, if any
423 selectPoint(inPointIndex);
427 // Check if not already done
434 * @return currently selected photo index
436 public int getCurrentPhotoIndex()
438 return _currentPhotoIndex;
442 * Check that the selection still makes sense
443 * and fire update message to listeners
449 if (_track.getNumPoints() > 0)
451 int maxIndex = _track.getNumPoints() - 1;
452 if (_currentPoint > maxIndex)
454 _currentPoint = maxIndex;
456 if (_endIndex > maxIndex)
458 _endIndex = maxIndex;
460 if (_startIndex > maxIndex)
462 _startIndex = maxIndex;
467 // track is empty, clear selections
468 _currentPoint = _startIndex = _endIndex = -1;
471 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);