package com.jwetherell.algorithms.mathematics; import java.util.ArrayList; import java.util.List; /** * The Ramer–Douglas–Peucker algorithm (RDP) is an algorithm for reducing the number of points in a * curve that is approximated by a series of points. * * http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm * * @author Justin Wetherell */ public class RamerDouglasPeucker { private RamerDouglasPeucker() { } private static final double sqr(double x) { return Math.pow(x, 2); } private static final double distanceBetweenPoints(double vx, double vy, double wx, double wy) { return sqr(vx - wx) + sqr(vy - wy); } private static final double distanceToSegmentSquared(double px, double py, double vx, double vy, double wx, double wy) { final double l2 = distanceBetweenPoints(vx, vy, wx, wy); if (l2 == 0) return distanceBetweenPoints(px, py, vx, vy); final double t = ((px - vx) * (wx - vx) + (py - vy) * (wy - vy)) / l2; if (t < 0) return distanceBetweenPoints(px, py, vx, vy); if (t > 1) return distanceBetweenPoints(px, py, wx, wy); return distanceBetweenPoints(px, py, (vx + t * (wx - vx)), (vy + t * (wy - vy))); } private static final double perpendicularDistance(double px, double py, double vx, double vy, double wx, double wy) { return Math.sqrt(distanceToSegmentSquared(px, py, vx, vy, wx, wy)); } private static final void douglasPeucker(List list, int s, int e, double epsilon, List resultList) { // Find the point with the maximum distance double dmax = 0; int index = 0; final int start = s; final int end = e-1; for (int i=start+1; i dmax) { index = i; dmax = d; } } // If max distance is greater than epsilon, recursively simplify if (dmax > epsilon) { // Recursive call douglasPeucker(list, s, index, epsilon, resultList); douglasPeucker(list, index, e, epsilon, resultList); } else { if ((end-start)>0) { resultList.add(list.get(start)); resultList.add(list.get(end)); } else { resultList.add(list.get(start)); } } } /** * Given a curve composed of line segments find a similar curve with fewer points. * * @param list List of Double[] points (x,y) * @param epsilon Distance dimension * @return Similar curve with fewer points */ public static final List douglasPeucker(List list, double epsilon) { final List resultList = new ArrayList(); douglasPeucker(list, 0, list.size(), epsilon, resultList); return resultList; } }