凸包的JarvisMarch演算法——Java語言
阿新 • • 發佈:2019-02-19
public class JarvisMarch<T extends Planarizable>{ private List<T> points; private List<T> hull; private static int MAX_ANGLE = 4; private double currentMinAngle = 0; public JarvisMarch(List<T> points) { this.points = points; this.hull = new ArrayList<T>(); this.calculate(); } private void calculate() { int firstIndex = getFirstPointIndex(this.points); this.hull.clear(); this.hull.add(this.points.get(firstIndex));//向list(hull)中新增第一個點 currentMinAngle = 0; for (int i = nextIndex(firstIndex, this.points); i != firstIndex; i = nextIndex( i, this.points)) { this.hull.add(this.points.get(i)); }//向list(hull)中新增其他的點,這些點將構成一個convex hull } public void remove(T item) { if (!hull.contains(item)) { points.remove(item); return; } points.remove(item); // TODO calculate(); } public void remove(List<T> items){ points.removeAll(items); calculate(); } public void add(T item) { points.add(item); List<T> tmplist = new ArrayList<T>(); tmplist.addAll(hull); tmplist.add(item); List<T> tmphull = new ArrayList<T>(); int firstIndex = getFirstPointIndex(tmplist); tmphull.add(tmplist.get(firstIndex)); currentMinAngle = 0; for (int i = nextIndex(firstIndex, tmplist); i != firstIndex; i = nextIndex( i, tmplist)) { tmphull.add(tmplist.get(i)); } this.hull = tmphull; } public void add(List<T> items) { points.addAll(items); List<T> tmplist = new ArrayList<T>(); tmplist.addAll(hull); tmplist.addAll(items); List<T> tmphull = new ArrayList<T>(); int firstIndex = getFirstPointIndex(tmplist); tmphull.add(tmplist.get(firstIndex)); currentMinAngle = 0; for (int i = nextIndex(firstIndex, tmplist); i != firstIndex; i = nextIndex( i, tmplist)) { tmphull.add(tmplist.get(i)); } this.hull = tmphull; } public List<T> getHull() { return this.hull; } private int nextIndex(int currentIndex, List<T> points) { double minAngle = MAX_ANGLE; double pseudoAngle; int minIndex = 0; for (int i = 0; i < points.size(); i++) { if (i != currentIndex) { pseudoAngle = getPseudoAngle( points.get(i).x() - points.get(currentIndex).x(), points.get(i).y() - points.get(currentIndex).y()); if (pseudoAngle >= currentMinAngle && pseudoAngle < minAngle) { minAngle = pseudoAngle; minIndex = i; } else if (pseudoAngle == minAngle) { if ((Math.abs(points.get(i).x() - points.get(currentIndex).x()) > Math.abs(points .get(minIndex).x() - points.get(currentIndex).x())) || (Math.abs(points.get(i).y() - points.get(currentIndex).y()) > Math .abs(points.get(minIndex).y() - points.get(currentIndex).y()))) { minIndex = i; } } } } currentMinAngle = minAngle; return minIndex; } //獲得起始點 private int getFirstPointIndex(List<T> points) { int minIndex = 0; for (int i = 1; i < points.size(); i++) { if (points.get(i).y() < points.get(minIndex).y()) { minIndex = i; } else if ((points.get(i).y() == points.get(minIndex).y()) && (points.get(i).x() < points.get(minIndex).x())) { minIndex = i; } } return minIndex; } private double getPseudoAngle(double dx, double dy) { if (dx > 0 && dy >= 0) return dy / (dx + dy); if (dx <= 0 && dy > 0) return 1 + (Math.abs(dx) / (Math.abs(dx) + dy)); if (dx < 0 && dy <= 0) return 2 + (dy / (dx + dy)); if (dx >= 0 && dy < 0) return 3 + (dx / (dx + Math.abs(dy))); throw new Error("Impossible"); } }