package tim.prune.data;
+import tim.prune.DataSubscriber;
import tim.prune.UpdateMessageBroker;
/**
public class Selection
{
private Track _track = null;
- private UpdateMessageBroker _broker = null;
private int _currentPoint = -1;
private boolean _valid = false;
+ private int _prevNumPoints = 0;
private int _startIndex = -1, _endIndex = -1;
- private IntegerRange _altitudeRange = null;
- private int _climb = -1, _descent = -1;
- private int _altitudeFormat = Altitude.FORMAT_NONE;
- private long _seconds = 0L;
- private double _angDistance = -1.0; //, _averageSpeed = -1.0;
+ private int _currentPhotoIndex = -1;
+ private int _currentAudioIndex = -1;
+ private AltitudeRange _altitudeRange = null;
+ private long _totalSeconds = 0L, _movingSeconds = 0L;
+ private double _angDistance = -1.0, _angMovingDistance = -1.0;
+ private int _numSegments = 0;
/**
* Constructor
* @param inTrack track object
- * @param inBroker broker object
*/
- public Selection(Track inTrack, UpdateMessageBroker inBroker)
+ public Selection(Track inTrack)
{
_track = inTrack;
- _broker = inBroker;
}
/**
- * Reset selection to be recalculated
+ * Mark selection invalid so it will be recalculated
*/
- private void reset()
+ public void markInvalid()
{
_valid = false;
}
- /**
- * Select the point at the given index
- * @param inIndex index number of selected point
- */
- public void selectPoint(int inIndex)
- {
- if (inIndex >= -1)
- {
- _currentPoint = inIndex;
- check();
- }
- }
-
- /**
- * Select the specified point and range in one go
- * @param inPointIndex point selection
- * @param inStart range start
- * @param inEnd range end
- */
- public void select(int inPointIndex, int inStart, int inEnd)
- {
- _currentPoint = inPointIndex;
- _startIndex = inStart;
- _endIndex = inEnd;
- reset();
- check();
- }
-
-
- /**
- * Select the previous point
- */
- public void selectPreviousPoint()
- {
- if (_currentPoint > 0)
- selectPoint(_currentPoint - 1);
- }
-
- /**
- * Select the next point
- */
- public void selectNextPoint()
- {
- selectPoint(_currentPoint + 1);
- }
-
/**
* @return the current point index
*/
*/
private void recalculate()
{
- _altitudeFormat = Altitude.FORMAT_NONE;
- if (_track.getNumPoints() > 0 && hasRangeSelected())
+ _numSegments = 0;
+ final int numPoints = _track.getNumPoints();
+ // Recheck if the number of points has changed
+ if (numPoints != _prevNumPoints) {
+ _prevNumPoints = numPoints;
+ check();
+ }
+ if (numPoints > 0 && hasRangeSelected())
{
- _altitudeRange = new IntegerRange();
- _climb = 0;
- _descent = 0;
+ _altitudeRange = new AltitudeRange();
Altitude altitude = null;
Timestamp time = null, startTime = null, endTime = null;
+ Timestamp previousTime = null;
DataPoint lastPoint = null, currPoint = null;
- _angDistance = 0.0;
- int altValue = 0;
- int lastAltValue = 0;
- boolean foundAlt = false;
+ _angDistance = 0.0; _angMovingDistance = 0.0;
+ _totalSeconds = 0L; _movingSeconds = 0L;
+ // Loop over points in selection
for (int i=_startIndex; i<=_endIndex; i++)
{
currPoint = _track.getPoint(i);
// Ignore waypoints in altitude calculations
if (!currPoint.isWaypoint() && altitude.isValid())
{
- altValue = altitude.getValue(_altitudeFormat);
- if (_altitudeFormat == Altitude.FORMAT_NONE)
- _altitudeFormat = altitude.getFormat();
- _altitudeRange.addValue(altValue);
- if (foundAlt)
- {
- if (altValue > lastAltValue)
- _climb += (altValue - lastAltValue);
- else
- _descent += (lastAltValue - altValue);
- }
- lastAltValue = altValue;
- foundAlt = true;
+ _altitudeRange.addValue(altitude);
}
// Store the first and last timestamp in the range
time = currPoint.getTimestamp();
if (time.isValid())
{
- if (startTime == null) startTime = time;
- endTime = time;
+ if (startTime == null || startTime.isAfter(time)) startTime = time;
+ if (endTime == null || time.isAfter(endTime)) endTime = time;
+ // add moving time
+ if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
+ _movingSeconds += time.getSecondsSince(previousTime);
+ }
+ previousTime = time;
}
// Calculate distances, again ignoring waypoints
if (!currPoint.isWaypoint())
{
if (lastPoint != null)
{
- _angDistance += DataPoint.calculateRadiansBetween(lastPoint, currPoint);
+ double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
+ _angDistance += radians;
+ if (currPoint.getSegmentStart()) {
+ _numSegments++;
+ }
+ else {
+ _angMovingDistance += radians;
+ }
}
lastPoint = currPoint;
+ // If it's a track point then there must be at least one segment
+ if (_numSegments == 0) {_numSegments = 1;}
}
}
- if (endTime != null)
- {
- _seconds = endTime.getSecondsSince(startTime);
- }
- else
- {
- _seconds = 0L;
+ if (endTime != null) {
+ _totalSeconds = endTime.getSecondsSince(startTime);
}
}
_valid = true;
return _endIndex;
}
-
- /**
- * @return the altitude format, ie feet or metres
- */
- public int getAltitudeFormat()
- {
- return _altitudeFormat;
- }
-
/**
* @return altitude range
*/
- public IntegerRange getAltitudeRange()
+ public AltitudeRange getAltitudeRange()
{
if (!_valid) recalculate();
return _altitudeRange;
/**
- * @return climb
+ * @return number of seconds spanned by selection
*/
- public int getClimb()
+ public long getNumSeconds()
{
if (!_valid) recalculate();
- return _climb;
+ return _totalSeconds;
}
/**
- * @return descent
+ * @return number of seconds spanned by segments within selection
*/
- public int getDescent()
+ public long getMovingSeconds()
{
if (!_valid) recalculate();
- return _descent;
+ return _movingSeconds;
}
-
/**
- * @return number of seconds spanned by selection
+ * @return distance of Selection in specified units
*/
- public long getNumSeconds()
+ public double getDistance()
{
- if (!_valid) recalculate();
- return _seconds;
+ return Distance.convertRadiansToDistance(_angDistance);
}
-
/**
- * @param inFormat distance units to use, from class Distance
- * @return distance of Selection in specified units
+ * @return moving distance of Selection in current units
*/
- public double getDistance(int inUnits)
+ public double getMovingDistance()
{
- return Distance.convertRadians(_angDistance, inUnits);
+ return Distance.convertRadiansToDistance(_angMovingDistance);
}
+ /**
+ * @return number of segments in selection
+ */
+ public int getNumSegments()
+ {
+ return _numSegments;
+ }
/**
- * Clear selected point and range
+ * Clear selected point, range, photo and audio
*/
public void clearAll()
{
_currentPoint = -1;
- deselectRange();
+ selectRange(-1, -1);
+ _currentPhotoIndex = -1;
+ _currentAudioIndex = -1;
+ check();
}
/**
- * Deselect range
+ * Select range from start to end
+ * @param inStartIndex index of start of range
+ * @param inEndIndex index of end of range
*/
- public void deselectRange()
+ public void selectRange(int inStartIndex, int inEndIndex)
{
- _startIndex = _endIndex = -1;
- reset();
+ _startIndex = inStartIndex;
+ _endIndex = inEndIndex;
+ markInvalid();
check();
}
* Set the index for the start of the range selection
* @param inStartIndex start index
*/
- public void selectRangeStart(int inStartIndex)
+ private void selectRangeStart(int inStartIndex)
{
if (inStartIndex < 0)
{
_endIndex = _track.getNumPoints() - 1;
}
}
- reset();
- _broker.informSubscribers();
+ markInvalid();
+ UpdateMessageBroker.informSubscribers();
}
{
_endIndex = inEndIndex;
// Move start of selection to min if necessary
- if (_startIndex > _endIndex || _startIndex < 0)
- {
+ if (_startIndex > _endIndex || _startIndex < 0) {
_startIndex = 0;
}
}
- reset();
- _broker.informSubscribers();
+ markInvalid();
+ UpdateMessageBroker.informSubscribers();
}
_endIndex--;
if (_currentPoint < _startIndex)
_startIndex--;
- reset();
+ markInvalid();
}
check();
}
+ /**
+ * Select the specified photo and point
+ * @param inPointIndex index of selected point
+ * @param inPhotoIndex index of selected photo in PhotoList
+ * @param inAudioIndex index of selected audio item
+ */
+ public void selectPointPhotoAudio(int inPointIndex, int inPhotoIndex, int inAudioIndex)
+ {
+ _currentPoint = inPointIndex;
+ _currentPhotoIndex = inPhotoIndex;
+ _currentAudioIndex = inAudioIndex;
+ check();
+ }
+
+
+ /**
+ * @return currently selected photo index
+ */
+ public int getCurrentPhotoIndex()
+ {
+ return _currentPhotoIndex;
+ }
+
+ /**
+ * @return currently selected audio index
+ */
+ public int getCurrentAudioIndex()
+ {
+ return _currentAudioIndex;
+ }
+
/**
* Check that the selection still makes sense
* and fire update message to listeners
*/
private void check()
{
- if (_track != null)
+ if (_track != null && _track.getNumPoints() > 0)
{
- if (_track.getNumPoints() > 0)
+ int maxIndex = _track.getNumPoints() - 1;
+ if (_currentPoint > maxIndex)
{
- int maxIndex = _track.getNumPoints() - 1;
- if (_currentPoint > maxIndex)
- {
- _currentPoint = maxIndex;
- }
- if (_endIndex > maxIndex)
- {
- _endIndex = maxIndex;
- }
- if (_startIndex > maxIndex)
- {
- _startIndex = maxIndex;
- }
+ _currentPoint = maxIndex;
}
- else
+ if (_endIndex > maxIndex)
{
- // track is empty, clear selections
- _currentPoint = _startIndex = _endIndex = -1;
+ _endIndex = maxIndex;
}
+ if (_startIndex > maxIndex)
+ {
+ _startIndex = maxIndex;
+ }
+ }
+ else
+ {
+ // track is empty, clear selections
+ _currentPoint = _startIndex = _endIndex = -1;
}
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
}
}