]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/function/compress/MarkLiftsFunction.java
Version 18, July 2015
[GpsPrune.git] / tim / prune / function / compress / MarkLiftsFunction.java
diff --git a/tim/prune/function/compress/MarkLiftsFunction.java b/tim/prune/function/compress/MarkLiftsFunction.java
new file mode 100644 (file)
index 0000000..5e39866
--- /dev/null
@@ -0,0 +1,143 @@
+package tim.prune.function.compress;
+
+import tim.prune.App;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.RangeStats;
+import tim.prune.data.Track;
+import tim.prune.data.UnitSetLibrary;
+
+/**
+ * Function to mark all the points going uphill on ski lifts
+ */
+public class MarkLiftsFunction extends MarkAndDeleteFunction
+{
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public MarkLiftsFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** @return name key */
+       public String getNameKey() {
+               return "function.marklifts";
+       }
+
+       /** this function _does_ require split at deleted points */
+       protected boolean getShouldSplitSegments() {
+               return true;
+       }
+
+       /**
+        * Begin the function using the set parameters
+        */
+       public void begin()
+       {
+               // TODO: Might need to do this in a separate thread, it might take a while if the track is big
+               // Loop over all points in track
+               int numMarked = 0;
+               final Track track = _app.getTrackInfo().getTrack();
+               final int numPoints = track.getNumPoints();
+               boolean[] markFlags = new boolean[numPoints];
+               int previousStartIndex = -1;
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint currPoint = track.getPoint(i);
+                       if (currPoint != null && !currPoint.isWaypoint() && currPoint.hasAltitude() && currPoint.hasTimestamp())
+                       {
+                               int n = i+1;
+                               DataPoint endPoint = track.getPoint(n);
+                               while (endPoint != null && endPoint.hasAltitude() && endPoint.hasTimestamp() &&
+                                       !endPoint.isWaypoint() && endPoint.getTimestamp().getSecondsSince(currPoint.getTimestamp()) < 120)
+                               {
+                                       n++;
+                                       endPoint = track.getPoint(n);
+                               }
+                               if (endPoint != null && endPoint.hasAltitude() && endPoint.hasTimestamp() && !endPoint.isWaypoint()
+                                       && n > (i+10))
+                               {
+                                       // Found a 2 minute range to test with at least 12 points
+                                       if (looksLikeLiftRange(track, i, n))
+                                       {
+                                               // Passes tests, so we want to mark all points between i and n
+                                               int startIndex = i;
+                                               // First check if we can merge with the previous marked range
+                                               if (previousStartIndex >= 0
+                                                       && (looksLikeLiftRange(track, previousStartIndex, i)
+                                                        || looksLikeLiftRange(track, previousStartIndex, n)))
+                                               {
+                                                       startIndex = previousStartIndex; // merge
+                                               }
+                                               for (int j=startIndex; j<=n; j++)
+                                               {
+                                                       markFlags[j] = true;
+                                               }
+                                               // Remember start point for next one
+                                               previousStartIndex = startIndex;
+                                               // skip forward half the range, don't need to test the same points again
+                                               i = (i+n)/2;
+                                       }
+                               }
+                       }
+               }
+
+               // Copy mark flags to points
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint point = track.getPoint(i);
+                       if (!point.isWaypoint()) point.setMarkedForDeletion(markFlags[i]);
+                       if (markFlags[i]) numMarked++;
+               }
+               // Inform subscribers to update display
+               UpdateMessageBroker.informSubscribers();
+               // Confirm message showing how many marked
+               if (numMarked > 0)
+               {
+                       optionallyDeleteMarkedPoints(numMarked);
+               }
+               else
+               {
+                       // TODO: Show message that no lifts were found
+               }
+       }
+
+
+       /**
+        * Check whether the specified range looks like an uphill lift section or not
+        * Must go at most a little bit downhill, much more uphill than down, and straight
+        * (speed isn't checked yet, but maybe could be?)
+        * @param inTrack track
+        * @param inStartIndex start index of range
+        * @param inEndIndex end index of range
+        * @return true if it looks like a lift
+        */
+       private boolean looksLikeLiftRange(Track inTrack, int inStartIndex, int inEndIndex)
+       {
+               RangeStats stats = new RangeStats(inTrack, inStartIndex, inEndIndex);
+               int descent = stats.getTotalAltitudeRange().getDescent(UnitSetLibrary.UNITS_METRES);
+               if (descent < 20)
+               {
+                       int ascent = stats.getTotalAltitudeRange().getClimb(UnitSetLibrary.UNITS_METRES);
+                       if (ascent > (descent * 10))
+                       {
+                               // Now check distance and compare to distance between start and end
+                               final DataPoint startPoint = inTrack.getPoint(inStartIndex);
+                               final DataPoint endPoint   = inTrack.getPoint(inEndIndex);
+
+                               final double trackDist = stats.getTotalDistance();
+                               final double endToEndDist = Distance.convertRadiansToDistance(
+                                       DataPoint.calculateRadiansBetween(startPoint, endPoint));
+                               if ((trackDist / endToEndDist) < 1.02)  // Straight(ish) line
+                               {
+                                       return true;
+                               }
+                               //else System.out.println("Not straight enough: " + (trackDist / endToEndDist));
+                       }
+               }
+               return false;
+       }
+}