//Created by plusminus on 11:34:13 - 25.05.2008 package org.androad.nav; import java.util.ArrayList; import java.util.List; import org.osmdroid.util.GeoPoint; public class WaypointOptimizer { // =========================================================== // Final Fields // =========================================================== // =========================================================== // Fields // =========================================================== // =========================================================== // Constructors // =========================================================== // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== /** * */ public static boolean optimize(final GeoPoint start, final List<GeoPoint> waypoints, final GeoPoint end){ if(waypoints.size() < 2) { return false; } int[] best = null; long bestLen = Long.MAX_VALUE; long curLen = 0; final int[] dummy = new int[waypoints.size()]; // Initiate dummy with simple, ascending indizes for(int i = 0; i < dummy.length; i++) { dummy[i] = i; } final int[][] permutations = permutate(dummy); for(final int[] p : permutations){ if((curLen = calcLen(start, waypoints, end, p)) < bestLen){ bestLen = curLen; best = p; } } if(isOriginal(best)) { return false; } final ArrayList<GeoPoint> tmp = new ArrayList<GeoPoint>(waypoints); // Bring waypoints into the optimized order. for(int i = 0; i < best.length; i++) { waypoints.set(i, tmp.get(best[i])); } return true; } protected static boolean isOriginal(final int[] arr) { for(int i = 0; i < arr.length; i++) { if(i != arr[i]) { return false; } } return true; } public static long calcLen(final GeoPoint start, final ArrayList<GeoPoint> waypoints, final GeoPoint end) { final int[] p = new int[waypoints.size()]; // Initiate dummy with simple, ascending indizes for(int i = 0; i < p.length; i++) { p[i] = i; } return calcLen(start, waypoints, end, p); } public static long calcLen(final GeoPoint start, final List<GeoPoint> waypoints, final GeoPoint end, final int[] p) { if(waypoints.size() != p.length) { throw new IllegalArgumentException(); } /* As only ordering is important, no SQRT needs to be taken. */ long out = start.distanceTo(waypoints.get(p[0])); out += end.distanceTo(waypoints.get(p[waypoints.size() - 1])); for(int i = 0; i < p.length - 1; i++) { out += waypoints.get(p[i]).distanceTo(waypoints.get(p[i+1])); } return out; } protected static final int[][] permutate(final int[] bucket){ if(bucket.length == 1) { return new int[][]{{bucket[0]}}; } // The number of permutations is: // <code>faculty(amount)</code> final int facLessOne = faculty(bucket.length - 1); final int fac = facLessOne * bucket.length; final int[][] out = new int[fac][]; for(int i = 0; i < bucket.length; i++){ // All except the last one // We will leave out one element final int except = bucket[i]; // so we create a sub-array with one size less final int[] sub = new int[bucket.length - 1]; // Copy all values except the one above System.arraycopy(bucket, 0, sub, 0, i); System.arraycopy(bucket, i + 1, sub, i, bucket.length - i - 1); // And permutate the sub-bucket final int[][] ret = permutate(sub); // Each permutated sub-bucket then needs to be merged with the element we excluded before for(int j = 0; j < ret.length; j++){ final int[] cur = ret[j]; final int[] merged = new int[bucket.length]; // Copy all values from the current sub-bucket for(int k = 0; k < cur.length; k++) { merged[k] = cur[k]; } merged[merged.length - 1] = except; // Copy back the merged bucket out[i * facLessOne + j] = merged; } } return out; } public static final int faculty(final int i){ if(i > 1) { return i * faculty(i - 1); } else { return i; } } // =========================================================== // Inner and Anonymous Classes // =========================================================== }