You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.3 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.jwetherell.algorithms.mathematics;
import java.util.ArrayList;
import java.util.List;
/**
* The RamerDouglasPeucker 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 <phishman3579@gmail.com>
*/
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<Double[]> list, int s, int e, double epsilon, List<Double[]> 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<end; i++) {
// Point
final double px = list.get(i)[0];
final double py = list.get(i)[1];
// Start
final double vx = list.get(start)[0];
final double vy = list.get(start)[1];
// End
final double wx = list.get(end)[0];
final double wy = list.get(end)[1];
final double d = perpendicularDistance(px, py, vx, vy, wx, wy);
if (d > 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<Double[]> douglasPeucker(List<Double[]> list, double epsilon) {
final List<Double[]> resultList = new ArrayList<Double[]>();
douglasPeucker(list, 0, list.size(), epsilon, resultList);
return resultList;
}
}