programming-examples/java/Numerical_Problems/RamerDouglasPeucker.java

93 lines
3.3 KiB
Java
Raw Normal View History

2019-11-15 12:59:38 +01:00
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;
}
}