X-Git-Url: https://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=tim%2Fprune%2Ffunction%2FRearrangeWaypointsFunction.java;h=17e937027c2d021593979e7c54fefcdf4851f940;hp=e04aea0430877889f651f07ba0563054b26fef51;hb=a6197ddcaac11c0b943183da7d46169742d024af;hpb=88f2c3647ed9e055090484f01a959d4581f85e7d diff --git a/tim/prune/function/RearrangeWaypointsFunction.java b/tim/prune/function/RearrangeWaypointsFunction.java index e04aea0..17e9370 100644 --- a/tim/prune/function/RearrangeWaypointsFunction.java +++ b/tim/prune/function/RearrangeWaypointsFunction.java @@ -1,61 +1,69 @@ package tim.prune.function; +import java.util.Arrays; + import javax.swing.JOptionPane; import tim.prune.App; -import tim.prune.GenericFunction; import tim.prune.I18nManager; +import tim.prune.data.Checker; +import tim.prune.data.DataPoint; import tim.prune.data.Track; +import tim.prune.data.sort.SortMode; +import tim.prune.data.sort.WaypointComparer; import tim.prune.undo.UndoRearrangeWaypoints; /** * Class to provide the function for rearranging waypoints */ -public class RearrangeWaypointsFunction extends GenericFunction +public class RearrangeWaypointsFunction extends RearrangeFunction { - /** Enumeration for rearrange commands */ - public enum Rearrange - { - /** Rearrange all waypoints to start */ - TO_START, - /** Rearrange all waypoints to end */ - TO_END, - /** Rearrange each waypoint to nearest track point */ - TO_NEAREST - } - /** * Constructor * @param inApp app object */ public RearrangeWaypointsFunction(App inApp) { - super(inApp); + super(inApp, true); + } + + /** Get the name key */ + public String getNameKey() { + return "function.rearrangewaypoints"; } - /** Begin the rearrange (not needed) */ - public void begin() { + /** Get whether sorting by time is allowed or not */ + protected boolean isSortByTimeAllowed() { + return Checker.haveWaypointsGotTimestamps(_app.getTrackInfo().getTrack()); } - /** Get the name key (not needed) */ - public String getNameKey() { - return null; + /** Get the description key */ + public String getDescriptionKey() { + return "dialog.rearrangewaypoints.desc"; + } + + /** Sort by name key */ + protected String getSortNameKey() { + return "sortbyname"; } /** - * Rearrange the waypoints into track order - * @param inFunction nearest point, all to end or all to start + * Perform the rearrange and sort according to the radio buttons */ - public void rearrangeWaypoints(Rearrange inFunction) + protected void finish() { Track track = _app.getTrackInfo().getTrack(); + // Figure out what is required from the radio buttons + Rearrange rearrangeOption = getRearrangeOption(); + SortMode sortOption = getSortMode(); + UndoRearrangeWaypoints undo = new UndoRearrangeWaypoints(track); boolean success = false; - if (inFunction == Rearrange.TO_START || inFunction == Rearrange.TO_END) + if (rearrangeOption == Rearrange.TO_START || rearrangeOption == Rearrange.TO_END) { // Collect the waypoints to the start or end of the track - success = track.collectWaypoints(inFunction == Rearrange.TO_START); + success = collectWaypoints(rearrangeOption, sortOption); } else { @@ -74,4 +82,108 @@ public class RearrangeWaypointsFunction extends GenericFunction } } + + /** + * Do the collection and sorting of the waypoints + * @param inRearrangeOption beginning or end + * @param inSortOption optional sort criterion + * @return true on success + */ + private boolean collectWaypoints(Rearrange inRearrangeOption, SortMode inSortOption) + { + // Check for mixed data, numbers of waypoints & nons + int numWaypoints = 0, numNonWaypoints = 0; + boolean wayAfterNon = false, nonAfterWay = false; + Track track = _app.getTrackInfo().getTrack(); + final int numPoints = track.getNumPoints(); + DataPoint[] waypoints = new DataPoint[numPoints]; + DataPoint[] nonWaypoints = new DataPoint[numPoints]; + DataPoint point = null; + for (int i=0; i 0); + } + else + { + nonWaypoints[numNonWaypoints] = point; + numNonWaypoints++; + nonAfterWay |= (numWaypoints > 0); + } + } + + // Exit if the data is already in the specified order + final boolean wpsToStart = (inRearrangeOption == Rearrange.TO_START); + final boolean doSort = (inSortOption != SortMode.DONT_SORT); + if (numWaypoints == 0 || numNonWaypoints == 0 + || (wpsToStart && !wayAfterNon && nonAfterWay && !doSort) + || (!wpsToStart && wayAfterNon && !nonAfterWay && !doSort) + || inRearrangeOption == Rearrange.TO_NEAREST) + { + return false; + } + // Note: it could still be that the rearrange and sort has no effect, but we don't know yet + // Make a copy of the waypoints array first so we can compare it with after the sort + DataPoint[] origWaypoints = new DataPoint[numPoints]; + System.arraycopy(waypoints, 0, origWaypoints, 0, numPoints); + + if (doSort && numWaypoints > 1) + { + // Sort the waypoints array + WaypointComparer comparer = new WaypointComparer(inSortOption); + Arrays.sort(waypoints, comparer); + final boolean sortDidNothing = areArraysSame(origWaypoints, waypoints); + if (sortDidNothing && (numNonWaypoints == 0 + || (wpsToStart && !wayAfterNon && nonAfterWay) + || (!wpsToStart && wayAfterNon && !nonAfterWay))) + { + return false; + } + } + + // Copy the arrays into an array in the specified order + DataPoint[] neworder = new DataPoint[numPoints]; + if (wpsToStart) + { + System.arraycopy(waypoints, 0, neworder, 0, numWaypoints); + System.arraycopy(nonWaypoints, 0, neworder, numWaypoints, numNonWaypoints); + } + else + { + System.arraycopy(nonWaypoints, 0, neworder, 0, numNonWaypoints); + System.arraycopy(waypoints, 0, neworder, numNonWaypoints, numWaypoints); + } + // Give track the new point order + return track.replaceContents(neworder); + } + + /** + * Compare two arrays of DataPoints and see if they're identical or not + * @param inOriginal original array of points + * @param inSorted array of points after sorting + * @return true if the two arrays have the same points in the same order + */ + private static boolean areArraysSame(DataPoint[] inOriginal, DataPoint[] inSorted) + { + if (inOriginal == null && inSorted == null) return true; // both null + if (inOriginal == null || inSorted == null) return false; // only one of them null + if (inOriginal.length != inSorted.length) return false; + // Loop over all points + for (int i=0; i