]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - src/tim/prune/function/InterpolateFunction.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / src / tim / prune / function / InterpolateFunction.java
diff --git a/src/tim/prune/function/InterpolateFunction.java b/src/tim/prune/function/InterpolateFunction.java
new file mode 100644 (file)
index 0000000..221fdaf
--- /dev/null
@@ -0,0 +1,149 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+import tim.prune.undo.UndoInterpolate;
+
+/**
+ * Function to interpolate between the points in a range
+ */
+public class InterpolateFunction extends SingleNumericParameterFunction
+{
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public InterpolateFunction(App inApp) {
+               super(inApp, 1, 1000);
+       }
+
+       /** @return name key */
+       public String getNameKey() {
+               return "function.interpolate";
+       }
+
+       /** @return description key for input parameter */
+       public String getDescriptionKey() {
+               return "dialog.interpolate.parameter.text";
+       }
+
+       /** @return current (or default) parameter value */
+       public int getCurrentParamValue() {
+               return 0;
+       }
+
+       /**
+        * Perform the operation
+        */
+       public void begin()
+       {
+               // not needed, we just use the completeFunction method instead
+       }
+
+       /**
+        * Complete the function after the input parameter has been chosen
+        */
+       public void completeFunction(int inParam)
+       {
+               // Firstly, work out whether the selected range only contains waypoints or not
+               final int startIndex = _app.getTrackInfo().getSelection().getStart();
+               final int endIndex   = _app.getTrackInfo().getSelection().getEnd();
+               boolean betweenWaypoints = false;
+               // if there are only waypoints, then ask whether to interpolate them
+               if (!selectedRangeHasTrackpoints(_app.getTrackInfo().getTrack(), startIndex, endIndex))
+               {
+                       int answer = JOptionPane.showConfirmDialog(_parentFrame,
+                               I18nManager.getText("dialog.interpolate.betweenwaypoints"),
+                               I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION);
+                       if (answer == JOptionPane.NO_OPTION) {
+                               // user said no, so nothing to do
+                               return;
+                       }
+                       betweenWaypoints = true;
+               }
+
+               if (startIndex < 0 || endIndex < 0 || endIndex <= startIndex) {
+                       return;
+               }
+
+               // construct new point array with the interpolated points
+               final int numToAdd = inParam;
+               final Track track = _app.getTrackInfo().getTrack();
+               final int maxToAdd = (endIndex-startIndex) * numToAdd;
+               final int extendedSize = track.getNumPoints() + maxToAdd;
+               DataPoint[] oldPoints = track.cloneContents();
+               DataPoint[] newPoints = new DataPoint[extendedSize];
+               // Copy points before
+               System.arraycopy(oldPoints, 0, newPoints, 0, startIndex);
+               // Loop, copying points and interpolating
+               int destIndex = startIndex;
+               DataPoint prevPoint = null;
+               for (int i=startIndex; i<= endIndex; i++)
+               {
+                       DataPoint p = _app.getTrackInfo().getTrack().getPoint(i);
+                       if (prevPoint != null && ((p.isWaypoint() && betweenWaypoints) || (!p.isWaypoint() && !p.getSegmentStart())))
+                       {
+                               // interpolate between the previous point and this one
+                               DataPoint[] addition = prevPoint.interpolate(p, numToAdd);
+                               System.arraycopy(addition, 0, newPoints, destIndex, numToAdd);
+                               destIndex += numToAdd;
+                       }
+                       // copy point
+                       newPoints[destIndex] = p;
+                       destIndex++;
+                       if (!p.isWaypoint() || betweenWaypoints)
+                       {
+                               prevPoint = p;
+                       }
+                       else if (!p.isWaypoint()) {
+                               prevPoint = null;
+                       }
+                       // If it's a waypoint, then keep the old prevPoint
+               }
+               final int totalInserted = destIndex - endIndex - 1;
+               // Copy the points after the selected range
+               System.arraycopy(oldPoints, endIndex, newPoints, destIndex-1, track.getNumPoints()-endIndex);
+
+               // If necessary, make a new array of the correct size and do another arraycopy into it
+               final int newTotalPoints = track.getNumPoints() + totalInserted;
+               if (newTotalPoints != newPoints.length)
+               {
+                       DataPoint[] croppedPoints = new DataPoint[newTotalPoints];
+                       System.arraycopy(newPoints, 0, croppedPoints, 0, newTotalPoints);
+                       newPoints = croppedPoints;
+               }
+
+               // Make undo object
+               UndoInterpolate undo = new UndoInterpolate(_app.getTrackInfo(), totalInserted);
+               // Replace track with new points array
+               if (track.replaceContents(newPoints))
+               {
+                       _app.completeFunction(undo, I18nManager.getText("confirm.interpolate"));
+                       // Alter selection
+                       _app.getTrackInfo().getSelection().selectRange(startIndex, endIndex + totalInserted);
+               }
+       }
+
+       /**
+        * Check if the given Track has trackpoints in the specified range
+        * @param inTrack track object
+        * @param inStart start index
+        * @param inEnd end index
+        * @return true if there are any non-waypoints in the range
+        */
+       private static boolean selectedRangeHasTrackpoints(Track inTrack, int inStart, int inEnd)
+       {
+               for (int i=inStart; i<= inEnd; i++)
+               {
+                       DataPoint p = inTrack.getPoint(i);
+                       if (p != null && !p.isWaypoint()) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+}