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 UpdateMessageBroker _broker = null;
14 private int _currentPoint = -1;
15 private boolean _valid = false;
16 private int _startIndex = -1, _endIndex = -1;
17 private int _currentPhotoIndex = -1;
18 private IntegerRange _altitudeRange = null;
19 private int _climb = -1, _descent = -1;
20 private int _altitudeFormat = Altitude.FORMAT_NONE;
21 private long _seconds = 0L;
22 private double _angDistance = -1.0; //, _averageSpeed = -1.0;
27 * @param inTrack track object
28 * @param inBroker broker object
30 public Selection(Track inTrack, UpdateMessageBroker inBroker)
38 * Reset selection to be recalculated
47 * Select the point at the given index
48 * @param inIndex index number of selected point
50 public void selectPoint(int inIndex)
54 _currentPoint = inIndex;
60 * Select the specified point and range in one go
61 * @param inPointIndex point selection
62 * @param inStart range start
63 * @param inEnd range end
65 public void select(int inPointIndex, int inStart, int inEnd)
67 _currentPoint = inPointIndex;
68 _startIndex = inStart;
76 * Select the previous point
78 public void selectPreviousPoint()
80 if (_currentPoint > 0)
81 selectPoint(_currentPoint - 1);
85 * Select the next point
87 public void selectNextPoint()
89 selectPoint(_currentPoint + 1);
93 * @return the current point index
95 public int getCurrentPointIndex()
102 * @return true if range is selected
104 public boolean hasRangeSelected()
106 return _startIndex >= 0 && _endIndex > _startIndex;
111 * Recalculate all selection details
113 private void recalculate()
115 _altitudeFormat = Altitude.FORMAT_NONE;
116 if (_track.getNumPoints() > 0 && hasRangeSelected())
118 _altitudeRange = new IntegerRange();
121 Altitude altitude = null;
122 Timestamp time = null, startTime = null, endTime = null;
123 DataPoint lastPoint = null, currPoint = null;
126 int lastAltValue = 0;
127 boolean foundAlt = false;
128 for (int i=_startIndex; i<=_endIndex; i++)
130 currPoint = _track.getPoint(i);
131 altitude = currPoint.getAltitude();
132 // Ignore waypoints in altitude calculations
133 if (!currPoint.isWaypoint() && altitude.isValid())
135 altValue = altitude.getValue(_altitudeFormat);
136 if (_altitudeFormat == Altitude.FORMAT_NONE)
137 _altitudeFormat = altitude.getFormat();
138 _altitudeRange.addValue(altValue);
141 if (altValue > lastAltValue)
142 _climb += (altValue - lastAltValue);
144 _descent += (lastAltValue - altValue);
146 lastAltValue = altValue;
149 // Store the first and last timestamp in the range
150 time = currPoint.getTimestamp();
153 if (startTime == null) startTime = time;
156 // Calculate distances, again ignoring waypoints
157 if (!currPoint.isWaypoint())
159 if (lastPoint != null)
161 _angDistance += DataPoint.calculateRadiansBetween(lastPoint, currPoint);
163 lastPoint = currPoint;
168 _seconds = endTime.getSecondsSince(startTime);
180 * @return start index
182 public int getStart()
184 if (!_valid) recalculate();
194 if (!_valid) recalculate();
200 * @return the altitude format, ie feet or metres
202 public int getAltitudeFormat()
204 return _altitudeFormat;
208 * @return altitude range
210 public IntegerRange getAltitudeRange()
212 if (!_valid) recalculate();
213 return _altitudeRange;
220 public int getClimb()
222 if (!_valid) recalculate();
229 public int getDescent()
231 if (!_valid) recalculate();
237 * @return number of seconds spanned by selection
239 public long getNumSeconds()
241 if (!_valid) recalculate();
247 * @param inUnits distance units to use, from class Distance
248 * @return distance of Selection in specified units
250 public double getDistance(int inUnits)
252 return Distance.convertRadiansToDistance(_angDistance, inUnits);
257 * Clear selected point and range
259 public void clearAll()
270 public void deselectRange()
272 _startIndex = _endIndex = -1;
279 * Select the range from the current point
281 public void selectRangeStart()
283 selectRangeStart(_currentPoint);
288 * Set the index for the start of the range selection
289 * @param inStartIndex start index
291 public void selectRangeStart(int inStartIndex)
293 if (inStartIndex < 0)
295 _startIndex = _endIndex = -1;
299 _startIndex = inStartIndex;
300 // Move end of selection to max if necessary
301 if (_endIndex <= _startIndex)
303 _endIndex = _track.getNumPoints() - 1;
307 _broker.informSubscribers();
312 * Select the range up to the current point
314 public void selectRangeEnd()
316 selectRangeEnd(_currentPoint);
321 * Set the index for the end of the range selection
322 * @param inEndIndex end index
324 public void selectRangeEnd(int inEndIndex)
328 _startIndex = _endIndex = -1;
332 _endIndex = inEndIndex;
333 // Move start of selection to min if necessary
334 if (_startIndex > _endIndex || _startIndex < 0)
340 _broker.informSubscribers();
345 * Modify the selection given that the selected range has been deleted
347 public void modifyRangeDeleted()
349 // Modify current point, if any
350 if (_currentPoint > _endIndex)
352 _currentPoint -= (_endIndex - _startIndex);
354 else if (_currentPoint > _startIndex)
356 _currentPoint = _startIndex;
358 // Clear selected range
359 _startIndex = _endIndex = -1;
360 // Check for consistency and fire update
366 * Modify the selection when a point is deleted
368 public void modifyPointDeleted()
370 // current point index doesn't change, just gets checked
371 // range needs to get altered if deleted point is inside or before
372 if (hasRangeSelected() && _currentPoint <= _endIndex)
375 if (_currentPoint < _startIndex)
386 public void deselectPhoto()
388 _currentPhotoIndex = -1;
394 * Select the specified photo and point
395 * @param inPhotoIndex index of selected photo in PhotoList
396 * @param inPointIndex index of selected point
398 public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
400 _currentPhotoIndex = inPhotoIndex;
401 if (inPointIndex > -1)
403 // select associated point, if any
404 selectPoint(inPointIndex);
408 // Check if not already done
415 * @return currently selected photo index
417 public int getCurrentPhotoIndex()
419 return _currentPhotoIndex;
424 * Check that the selection still makes sense
425 * and fire update message to listeners
431 if (_track.getNumPoints() > 0)
433 int maxIndex = _track.getNumPoints() - 1;
434 if (_currentPoint > maxIndex)
436 _currentPoint = maxIndex;
438 if (_endIndex > maxIndex)
440 _endIndex = maxIndex;
442 if (_startIndex > maxIndex)
444 _startIndex = maxIndex;
449 // track is empty, clear selections
450 _currentPoint = _startIndex = _endIndex = -1;
453 _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);