package tim.prune.function.compress; import java.awt.Component; import java.awt.event.ActionListener; import tim.prune.data.DataPoint; import tim.prune.data.Track; /** * Douglas-Peucker algorithm for compresssion */ public class DouglasPeuckerAlgorithm extends SingleParameterAlgorithm { /** * Constructor * @param inTrack track object * @param inDetails track details object * @param inListener listener to attach to activation control */ public DouglasPeuckerAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener) { super(inTrack, inDetails, inListener); } /** * Perform the compression and work out which points should be deleted * @param inFlags deletion flags from previous algorithms * @return number of points deleted */ protected int compress(boolean[] inFlags) { // Parse parameter double param = getParameter(); // Use 1/x if x greater than 1 if (param > 1.0) param = 1.0 / param; if (param <= 0.0 || param >= 1.0) { // Parameter isn't valid, don't delete any return 0; } double threshold = _trackDetails.getTrackSpan() * param; int numPoints = _track.getNumPoints(); int origNumDeleted = countFlags(inFlags); // Convert inFlags into keepFlags int[] keepFlags = new int[numPoints]; int segStart = -1, segEnd = -1; // Loop over all points in track for (int i=0; i -1 && segEnd > segStart) { keepFlags[segEnd] = 1; // keep compressSegment(keepFlags, segStart, segEnd, threshold); segStart = segEnd = -1; } } if (inFlags[i]) keepFlags[i] = -1; // already deleted else if (currPoint.isWaypoint() || currPoint.hasMedia() || currPoint.getSegmentStart()) { keepFlags[i] = 1; // keep } // Don't consider points which are already marked as deleted, ignore waypoints if (!inFlags[i] && !currPoint.isWaypoint()) { // remember starts and ends if (segStart < 0) {segStart = i;} else {segEnd = i;} } } // Last segment, if any if (segStart >= 0 && segEnd > segStart) { keepFlags[segEnd] = 1; // keep compressSegment(keepFlags, segStart, segEnd, threshold); } // Convert keepFlags back into inFlags for (int i=1; i 1.0) { dist = endxy.vectorTo(currPoint).len(); // outside on the B side } else { // P lies between A and B so use dot product dist = Math.abs(perpendicular.dot(ac)); } if (dist > maxDist) { maxDist = dist; furthestIndex = i; } } } // Check furthest point and see if it's further than the threshold if (maxDist > inThreshold) { inFlags[furthestIndex] = 1; // Make recursive calls for bit before and bit after kept point compressSegment(inFlags, inSegStart, furthestIndex, inThreshold); compressSegment(inFlags, furthestIndex, inSegEnd, inThreshold); } } /** * @return specific gui components for dialog */ protected Component getSpecificGuiComponents() { return getSpecificGuiComponents("dialog.compress.douglaspeucker.paramdesc", "2000"); } /** * @return title key for box */ protected String getTitleTextKey() { return "dialog.compress.douglaspeucker.title"; } }