]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/function/InterpolateFunction.java
Version 14, October 2012
[GpsPrune.git] / tim / prune / function / InterpolateFunction.java
1 package tim.prune.function;
2
3 import javax.swing.JOptionPane;
4
5 import tim.prune.App;
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;
11
12 /**
13  * Function to interpolate between the points in a range
14  */
15 public class InterpolateFunction extends GenericFunction
16 {
17         /**
18          * Constructor
19          * @param inApp app object
20          */
21         public InterpolateFunction(App inApp) {
22                 super(inApp);
23         }
24
25         /** @return name key */
26         public String getNameKey() {
27                 return "function.interpolate";
28         }
29
30         /**
31          * Perform the operation
32          */
33         public void begin()
34         {
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))
41                 {
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
47                                 return;
48                         }
49                         betweenWaypoints = true;
50                 }
51
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)
60                 {
61                         _app.showErrorMessage(getNameKey(), "error.interpolate.invalidparameter");
62                         return;
63                 }
64
65                 if (startIndex < 0 || endIndex < 0 || endIndex <= startIndex) {
66                         return;
67                 }
68
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];
75                 // Copy points before
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++)
81                 {
82                         DataPoint p = _app.getTrackInfo().getTrack().getPoint(i);
83                         if (prevPoint != null && ((p.isWaypoint() && betweenWaypoints) || (!p.isWaypoint() && !p.getSegmentStart())))
84                         {
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;
89                         }
90                         // copy point
91                         newPoints[destIndex] = p;
92                         destIndex++;
93                         if (!p.isWaypoint() || betweenWaypoints)
94                         {
95                                 prevPoint = p;
96                         }
97                         else if (!p.isWaypoint()) {
98                                 prevPoint = null;
99                         }
100                         // If it's a waypoint, then keep the old prevPoint
101                 }
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);
105
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)
109                 {
110                         DataPoint[] croppedPoints = new DataPoint[newTotalPoints];
111                         System.arraycopy(newPoints, 0, croppedPoints, 0, newTotalPoints);
112                         newPoints = croppedPoints;
113                 }
114
115                 // Make undo object
116                 UndoInterpolate undo = new UndoInterpolate(_app.getTrackInfo(), totalInserted);
117                 // Replace track with new points array
118                 if (track.replaceContents(newPoints))
119                 {
120                         _app.completeFunction(undo, I18nManager.getText("confirm.interpolate"));
121                         // Alter selection
122                         _app.getTrackInfo().getSelection().selectRange(startIndex, endIndex + totalInserted);
123                 }
124         }
125
126         /**
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
132          */
133         private static boolean selectedRangeHasTrackpoints(Track inTrack, int inStart, int inEnd)
134         {
135                 for (int i=inStart; i<= inEnd; i++)
136                 {
137                         DataPoint p = inTrack.getPoint(i);
138                         if (p != null && !p.isWaypoint()) {
139                                 return true;
140                         }
141                 }
142                 return false;
143         }
144
145         /**
146          * Helper method to parse an Object into an integer
147          * @param inObject object, eg from dialog
148          * @return int value given
149          */
150         private static int parseNumber(Object inObject)
151         {
152                 int num = 0;
153                 if (inObject != null)
154                 {
155                         try
156                         {
157                                 num = Integer.parseInt(inObject.toString());
158                         }
159                         catch (NumberFormatException nfe)
160                         {}
161                 }
162                 return num;
163         }
164 }