programming-examples/java/Numerical_Problems/RamerDouglasPeucker.java
2019-11-15 12:59:38 +01:00

93 lines
3.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}