X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=src%2Ftim%2Fprune%2Ffunction%2Fcompress%2FDouglasPeuckerAlgorithm.java;fp=src%2Ftim%2Fprune%2Ffunction%2Fcompress%2FDouglasPeuckerAlgorithm.java;h=046e72ecd49c357940aae94f28b1806fe98830ac;hp=0000000000000000000000000000000000000000;hb=ce6f2161b8596f7018d6a76bff79bc9e571f35fd;hpb=2d8cb72e84d5cc1089ce77baf1e34ea3ea2f8465 diff --git a/src/tim/prune/function/compress/DouglasPeuckerAlgorithm.java b/src/tim/prune/function/compress/DouglasPeuckerAlgorithm.java new file mode 100644 index 0000000..046e72e --- /dev/null +++ b/src/tim/prune/function/compress/DouglasPeuckerAlgorithm.java @@ -0,0 +1,217 @@ +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 inSegStart) + { + compressSegment(inFlags, inSegStart, furthestIndex, inThreshold); + compressSegment(inFlags, furthestIndex, inSegEnd, inThreshold); + } + return; + } + + double maxDist = -1.0, dist = -1.0; + int furthestIndex = -1; + for (int i=inSegStart+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"; + } + + /** + * Find the index of the point furthest away from the start and end points + * @param inStartIndex start index of segment to check + * @param inEndIndex end index of segment to check + * @return index of furthest point, or -1 if none found + */ + private int getFurthestPointIndex(int inStartIndex, int inEndIndex) + { + int furthestIndex = -1; + if (inStartIndex >= 0 && inEndIndex > inStartIndex) + { + final DataPoint startPoint = _track.getPoint(inStartIndex); + double maxDist = 0.0; + // Loop over points between start and end + for (int i=inStartIndex+1; i maxDist) + { + furthestIndex = i; + maxDist = distFromStart; + } + } + } + } + return furthestIndex; + } +}