]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - src/tim/prune/data/Selection.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / src / tim / prune / data / Selection.java
diff --git a/src/tim/prune/data/Selection.java b/src/tim/prune/data/Selection.java
new file mode 100644 (file)
index 0000000..7b63d70
--- /dev/null
@@ -0,0 +1,361 @@
+package tim.prune.data;
+
+import tim.prune.DataSubscriber;
+import tim.prune.UpdateMessageBroker;
+
+/**
+ * Class to represent a selected portion of a Track
+ * and its properties
+ */
+public class Selection
+{
+       private Track _track = null;
+       private int _currentPoint = -1;
+       private boolean _valid = false;
+       private int _prevNumPoints = 0;
+       private int _startIndex = -1, _endIndex = -1;
+       private int _currentPhotoIndex = -1;
+       private int _currentAudioIndex = -1;
+       private AltitudeRange _altitudeRange = null;
+       private long _movingMilliseconds = 0L;
+       private double _angMovingDistance = -1.0;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        */
+       public Selection(Track inTrack)
+       {
+               _track = inTrack;
+       }
+
+
+       /**
+        * Mark selection invalid so it will be recalculated
+        */
+       public void markInvalid()
+       {
+               _valid = false;
+       }
+
+
+       /**
+        * @return the current point index
+        */
+       public int getCurrentPointIndex()
+       {
+               return _currentPoint;
+       }
+
+
+       /**
+        * @return true if range is selected
+        */
+       public boolean hasRangeSelected()
+       {
+               return _startIndex >= 0 && _endIndex > _startIndex;
+       }
+
+
+       /**
+        * Recalculate all selection details
+        */
+       private void recalculate()
+       {
+               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 AltitudeRange();
+                       Altitude altitude = null;
+                       Timestamp time = null, previousTime = null;
+                       DataPoint lastPoint = null, currPoint = null;
+                       _angMovingDistance = 0.0;
+                       _movingMilliseconds = 0L;
+                       // Loop over points in selection
+                       for (int i=_startIndex; i<=_endIndex; i++)
+                       {
+                               currPoint = _track.getPoint(i);
+                               altitude = currPoint.getAltitude();
+                               // Ignore waypoints in altitude calculations
+                               if (!currPoint.isWaypoint() && altitude.isValid())
+                               {
+                                       if (currPoint.getSegmentStart()) {
+                                               _altitudeRange.ignoreValue(altitude);
+                                       }
+                                       else {
+                                               _altitudeRange.addValue(altitude);
+                                       }
+                               }
+                               // Compare timestamps within the segments
+                               time = currPoint.getTimestamp();
+                               if (time.isValid())
+                               {
+                                       // add moving time
+                                       if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
+                                               _movingMilliseconds += time.getMillisecondsSince(previousTime);
+                                       }
+                                       previousTime = time;
+                               }
+                               // Calculate distances, again ignoring waypoints
+                               if (!currPoint.isWaypoint())
+                               {
+                                       if (lastPoint != null)
+                                       {
+                                               double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
+                                               if (!currPoint.getSegmentStart()) {
+                                                       _angMovingDistance += radians;
+                                               }
+                                       }
+                                       lastPoint = currPoint;
+                               }
+                       }
+               }
+               _valid = true;
+       }
+
+
+       /**
+        * @return start index
+        */
+       public int getStart()
+       {
+               if (!_valid) recalculate();
+               return _startIndex;
+       }
+
+
+       /**
+        * @return end index
+        */
+       public int getEnd()
+       {
+               if (!_valid) recalculate();
+               return _endIndex;
+       }
+
+       /**
+        * @return altitude range
+        */
+       public AltitudeRange getAltitudeRange()
+       {
+               if (!_valid) recalculate();
+               return _altitudeRange;
+       }
+
+
+       /**
+        * @return number of seconds spanned by segments within selection
+        */
+       public long getMovingSeconds()
+       {
+               if (!_valid) recalculate();
+               return _movingMilliseconds / 1000L;
+       }
+
+       /**
+        * @return moving distance of Selection in current units
+        */
+       public double getMovingDistance()
+       {
+               return Distance.convertRadiansToDistance(_angMovingDistance);
+       }
+
+       /**
+        * Clear selected point, range, photo and audio
+        */
+       public void clearAll()
+       {
+               _currentPoint = -1;
+               selectRange(-1, -1);
+               _currentPhotoIndex = -1;
+               _currentAudioIndex = -1;
+               check();
+       }
+
+
+       /**
+        * Select range from start to end
+        * @param inStartIndex index of start of range
+        * @param inEndIndex index of end of range
+        */
+       public void selectRange(int inStartIndex, int inEndIndex)
+       {
+               _startIndex = inStartIndex;
+               _endIndex = inEndIndex;
+               markInvalid();
+               check();
+       }
+
+
+       /**
+        * Select the range from the current point
+        */
+       public void selectRangeStart()
+       {
+               selectRangeStart(_currentPoint);
+       }
+
+
+       /**
+        * Set the index for the start of the range selection
+        * @param inStartIndex start index
+        */
+       private void selectRangeStart(int inStartIndex)
+       {
+               if (inStartIndex < 0)
+               {
+                       _startIndex = _endIndex = -1;
+               }
+               else
+               {
+                       _startIndex = inStartIndex;
+                       // Move end of selection to max if necessary
+                       if (_endIndex <= _startIndex)
+                       {
+                               _endIndex = _track.getNumPoints() - 1;
+                       }
+               }
+               markInvalid();
+               UpdateMessageBroker.informSubscribers();
+       }
+
+
+       /**
+        * Select the range up to the current point
+        */
+       public void selectRangeEnd()
+       {
+               selectRangeEnd(_currentPoint);
+       }
+
+
+       /**
+        * Set the index for the end of the range selection
+        * @param inEndIndex end index
+        */
+       public void selectRangeEnd(int inEndIndex)
+       {
+               if (inEndIndex < 0)
+               {
+                       _startIndex = _endIndex = -1;
+               }
+               else
+               {
+                       _endIndex = inEndIndex;
+                       // Move start of selection to min if necessary
+                       if (_startIndex > _endIndex || _startIndex < 0) {
+                               _startIndex = 0;
+                       }
+               }
+               markInvalid();
+               UpdateMessageBroker.informSubscribers();
+       }
+
+
+       /**
+        * Modify the selection given that the selected range has been deleted
+        */
+       public void modifyRangeDeleted()
+       {
+               // Modify current point, if any
+               if (_currentPoint > _endIndex)
+               {
+                       _currentPoint -= (_endIndex - _startIndex);
+               }
+               else if (_currentPoint > _startIndex)
+               {
+                       _currentPoint = _startIndex;
+               }
+               // Clear selected range
+               _startIndex = _endIndex = -1;
+               // Check for consistency and fire update
+               check();
+       }
+
+
+       /**
+        * Modify the selection when a point is deleted
+        */
+       public void modifyPointDeleted()
+       {
+               // current point index doesn't change, just gets checked
+               // range needs to get altered if deleted point is inside or before
+               if (hasRangeSelected() && _currentPoint <= _endIndex)
+               {
+                       _endIndex--;
+                       if (_currentPoint < _startIndex)
+                               _startIndex--;
+                       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 && _track.getNumPoints() > 0)
+               {
+                       int maxIndex = _track.getNumPoints() - 1;
+                       if (_currentPoint > maxIndex)
+                       {
+                               _currentPoint = maxIndex;
+                       }
+                       if (_endIndex > maxIndex)
+                       {
+                               _endIndex = maxIndex;
+                       }
+                       if (_startIndex > maxIndex)
+                       {
+                               _startIndex = maxIndex;
+                       }
+               }
+               else
+               {
+                       // track is empty, clear selections
+                       _currentPoint = _startIndex = _endIndex = -1;
+               }
+               UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+       }
+}