X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Ffunction%2FInterpolateFunction.java;fp=tim%2Fprune%2Ffunction%2FInterpolateFunction.java;h=84826144d94e787bdea53e457e2818e57ce34270;hb=4d5796d02a15808311c09448d79e6e7d1de9d636;hp=0000000000000000000000000000000000000000;hpb=f1b92378a792131ac8fb33a869405851d5b2d1f7;p=GpsPrune.git diff --git a/tim/prune/function/InterpolateFunction.java b/tim/prune/function/InterpolateFunction.java new file mode 100644 index 0000000..8482614 --- /dev/null +++ b/tim/prune/function/InterpolateFunction.java @@ -0,0 +1,164 @@ +package tim.prune.function; + +import javax.swing.JOptionPane; + +import tim.prune.App; +import tim.prune.GenericFunction; +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 GenericFunction +{ + /** + * Constructor + * @param inApp app object + */ + public InterpolateFunction(App inApp) { + super(inApp); + } + + /** @return name key */ + public String getNameKey() { + return "function.interpolate"; + } + + /** + * Perform the operation + */ + public void begin() + { + // 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; + } + + // Get number of points to add + Object numPointsStr = JOptionPane.showInputDialog(_parentFrame, + I18nManager.getText("dialog.interpolate.parameter.text"), + I18nManager.getText(getNameKey()), + JOptionPane.QUESTION_MESSAGE, null, null, ""); + if (numPointsStr == null) {return;} + int numToAdd = parseNumber(numPointsStr); + if (numToAdd <= 0 || numToAdd > 1000) + { + _app.showErrorMessage(getNameKey(), "error.interpolate.invalidparameter"); + return; + } + + if (startIndex < 0 || endIndex < 0 || endIndex <= startIndex) { + return; + } + + // construct new point array with the interpolated points + 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; + } + + /** + * Helper method to parse an Object into an integer + * @param inObject object, eg from dialog + * @return int value given + */ + private static int parseNumber(Object inObject) + { + int num = 0; + if (inObject != null) + { + try + { + num = Integer.parseInt(inObject.toString()); + } + catch (NumberFormatException nfe) + {} + } + return num; + } +}