1 package tim.prune.function;
3 import javax.swing.JOptionPane;
6 import tim.prune.GenericFunction;
7 import tim.prune.I18nManager;
8 import tim.prune.data.DataPoint;
9 import tim.prune.data.Track;
10 import tim.prune.undo.UndoInterpolate;
13 * Function to interpolate between the points in a range
15 public class InterpolateFunction extends GenericFunction
19 * @param inApp app object
21 public InterpolateFunction(App inApp) {
25 /** @return name key */
26 public String getNameKey() {
27 return "function.interpolate";
31 * Perform the operation
35 // Firstly, work out whether the selected range only contains waypoints or not
36 final int startIndex = _app.getTrackInfo().getSelection().getStart();
37 final int endIndex = _app.getTrackInfo().getSelection().getEnd();
38 boolean betweenWaypoints = false;
39 // if there are only waypoints, then ask whether to interpolate them
40 if (!selectedRangeHasTrackpoints(_app.getTrackInfo().getTrack(), startIndex, endIndex))
42 int answer = JOptionPane.showConfirmDialog(_parentFrame,
43 I18nManager.getText("dialog.interpolate.betweenwaypoints"),
44 I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION);
45 if (answer == JOptionPane.NO_OPTION) {
46 // user said no, so nothing to do
49 betweenWaypoints = true;
52 // Get number of points to add
53 Object numPointsStr = JOptionPane.showInputDialog(_parentFrame,
54 I18nManager.getText("dialog.interpolate.parameter.text"),
55 I18nManager.getText(getNameKey()),
56 JOptionPane.QUESTION_MESSAGE, null, null, "");
57 if (numPointsStr == null) {return;}
58 int numToAdd = parseNumber(numPointsStr);
59 if (numToAdd <= 0 || numToAdd > 1000)
61 _app.showErrorMessage(getNameKey(), "error.interpolate.invalidparameter");
65 if (startIndex < 0 || endIndex < 0 || endIndex <= startIndex) {
69 // construct new point array with the interpolated points
70 final Track track = _app.getTrackInfo().getTrack();
71 final int maxToAdd = (endIndex-startIndex) * numToAdd;
72 final int extendedSize = track.getNumPoints() + maxToAdd;
73 DataPoint[] oldPoints = track.cloneContents();
74 DataPoint[] newPoints = new DataPoint[extendedSize];
76 System.arraycopy(oldPoints, 0, newPoints, 0, startIndex);
77 // Loop, copying points and interpolating
78 int destIndex = startIndex;
79 DataPoint prevPoint = null;
80 for (int i=startIndex; i<= endIndex; i++)
82 DataPoint p = _app.getTrackInfo().getTrack().getPoint(i);
83 if (prevPoint != null && ((p.isWaypoint() && betweenWaypoints) || (!p.isWaypoint() && !p.getSegmentStart())))
85 // interpolate between the previous point and this one
86 DataPoint[] addition = prevPoint.interpolate(p, numToAdd);
87 System.arraycopy(addition, 0, newPoints, destIndex, numToAdd);
88 destIndex += numToAdd;
91 newPoints[destIndex] = p;
93 if (!p.isWaypoint() || betweenWaypoints)
97 else if (!p.isWaypoint()) {
100 // If it's a waypoint, then keep the old prevPoint
102 final int totalInserted = destIndex - endIndex - 1;
103 // Copy the points after the selected range
104 System.arraycopy(oldPoints, endIndex, newPoints, destIndex-1, track.getNumPoints()-endIndex);
106 // If necessary, make a new array of the correct size and do another arraycopy into it
107 final int newTotalPoints = track.getNumPoints() + totalInserted;
108 if (newTotalPoints != newPoints.length)
110 DataPoint[] croppedPoints = new DataPoint[newTotalPoints];
111 System.arraycopy(newPoints, 0, croppedPoints, 0, newTotalPoints);
112 newPoints = croppedPoints;
116 UndoInterpolate undo = new UndoInterpolate(_app.getTrackInfo(), totalInserted);
117 // Replace track with new points array
118 if (track.replaceContents(newPoints))
120 _app.completeFunction(undo, I18nManager.getText("confirm.interpolate"));
122 _app.getTrackInfo().getSelection().selectRange(startIndex, endIndex + totalInserted);
127 * Check if the given Track has trackpoints in the specified range
128 * @param inTrack track object
129 * @param inStart start index
130 * @param inEnd end index
131 * @return true if there are any non-waypoints in the range
133 private static boolean selectedRangeHasTrackpoints(Track inTrack, int inStart, int inEnd)
135 for (int i=inStart; i<= inEnd; i++)
137 DataPoint p = inTrack.getPoint(i);
138 if (p != null && !p.isWaypoint()) {
146 * Helper method to parse an Object into an integer
147 * @param inObject object, eg from dialog
148 * @return int value given
150 private static int parseNumber(Object inObject)
153 if (inObject != null)
157 num = Integer.parseInt(inObject.toString());
159 catch (NumberFormatException nfe)