]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/InterpolateFunction.java
Version 20.4, May 2021
[GpsPrune.git] / src / 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.I18nManager;
7 import tim.prune.data.DataPoint;
8 import tim.prune.data.Track;
9 import tim.prune.undo.UndoInterpolate;
10
11 /**
12  * Function to interpolate between the points in a range
13  */
14 public class InterpolateFunction extends SingleNumericParameterFunction
15 {
16         /**
17          * Constructor
18          * @param inApp app object
19          */
20         public InterpolateFunction(App inApp) {
21                 super(inApp, 1, 1000);
22         }
23
24         /** @return name key */
25         public String getNameKey() {
26                 return "function.interpolate";
27         }
28
29         /** @return description key for input parameter */
30         public String getDescriptionKey() {
31                 return "dialog.interpolate.parameter.text";
32         }
33
34         /** @return current (or default) parameter value */
35         public int getCurrentParamValue() {
36                 return 0;
37         }
38
39         /**
40          * Perform the operation
41          */
42         public void begin()
43         {
44                 // not needed, we just use the completeFunction method instead
45         }
46
47         /**
48          * Complete the function after the input parameter has been chosen
49          */
50         public void completeFunction(int inParam)
51         {
52                 // Firstly, work out whether the selected range only contains waypoints or not
53                 final int startIndex = _app.getTrackInfo().getSelection().getStart();
54                 final int endIndex   = _app.getTrackInfo().getSelection().getEnd();
55                 boolean betweenWaypoints = false;
56                 // if there are only waypoints, then ask whether to interpolate them
57                 if (!selectedRangeHasTrackpoints(_app.getTrackInfo().getTrack(), startIndex, endIndex))
58                 {
59                         int answer = JOptionPane.showConfirmDialog(_parentFrame,
60                                 I18nManager.getText("dialog.interpolate.betweenwaypoints"),
61                                 I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION);
62                         if (answer == JOptionPane.NO_OPTION) {
63                                 // user said no, so nothing to do
64                                 return;
65                         }
66                         betweenWaypoints = true;
67                 }
68
69                 if (startIndex < 0 || endIndex < 0 || endIndex <= startIndex) {
70                         return;
71                 }
72
73                 // construct new point array with the interpolated points
74                 final int numToAdd = inParam;
75                 final Track track = _app.getTrackInfo().getTrack();
76                 final int maxToAdd = (endIndex-startIndex) * numToAdd;
77                 final int extendedSize = track.getNumPoints() + maxToAdd;
78                 DataPoint[] oldPoints = track.cloneContents();
79                 DataPoint[] newPoints = new DataPoint[extendedSize];
80                 // Copy points before
81                 System.arraycopy(oldPoints, 0, newPoints, 0, startIndex);
82                 // Loop, copying points and interpolating
83                 int destIndex = startIndex;
84                 DataPoint prevPoint = null;
85                 for (int i=startIndex; i<= endIndex; i++)
86                 {
87                         DataPoint p = _app.getTrackInfo().getTrack().getPoint(i);
88                         if (prevPoint != null && ((p.isWaypoint() && betweenWaypoints) || (!p.isWaypoint() && !p.getSegmentStart())))
89                         {
90                                 // interpolate between the previous point and this one
91                                 DataPoint[] addition = prevPoint.interpolate(p, numToAdd);
92                                 System.arraycopy(addition, 0, newPoints, destIndex, numToAdd);
93                                 destIndex += numToAdd;
94                         }
95                         // copy point
96                         newPoints[destIndex] = p;
97                         destIndex++;
98                         if (!p.isWaypoint() || betweenWaypoints)
99                         {
100                                 prevPoint = p;
101                         }
102                         else if (!p.isWaypoint()) {
103                                 prevPoint = null;
104                         }
105                         // If it's a waypoint, then keep the old prevPoint
106                 }
107                 final int totalInserted = destIndex - endIndex - 1;
108                 // Copy the points after the selected range
109                 System.arraycopy(oldPoints, endIndex, newPoints, destIndex-1, track.getNumPoints()-endIndex);
110
111                 // If necessary, make a new array of the correct size and do another arraycopy into it
112                 final int newTotalPoints = track.getNumPoints() + totalInserted;
113                 if (newTotalPoints != newPoints.length)
114                 {
115                         DataPoint[] croppedPoints = new DataPoint[newTotalPoints];
116                         System.arraycopy(newPoints, 0, croppedPoints, 0, newTotalPoints);
117                         newPoints = croppedPoints;
118                 }
119
120                 // Make undo object
121                 UndoInterpolate undo = new UndoInterpolate(_app.getTrackInfo(), totalInserted);
122                 // Replace track with new points array
123                 if (track.replaceContents(newPoints))
124                 {
125                         final String confirmMessage = I18nManager.getTextWithNumber("confirm.pointsadded", totalInserted);
126                         _app.completeFunction(undo, confirmMessage);
127                         // Alter selection
128                         _app.getTrackInfo().getSelection().selectRange(startIndex, endIndex + totalInserted);
129                 }
130         }
131
132         /**
133          * Check if the given Track has trackpoints in the specified range
134          * @param inTrack track object
135          * @param inStart start index
136          * @param inEnd end index
137          * @return true if there are any non-waypoints in the range
138          */
139         private static boolean selectedRangeHasTrackpoints(Track inTrack, int inStart, int inEnd)
140         {
141                 for (int i=inStart; i<= inEnd; i++)
142                 {
143                         DataPoint p = inTrack.getPoint(i);
144                         if (p != null && !p.isWaypoint()) {
145                                 return true;
146                         }
147                 }
148                 return false;
149         }
150 }