JAVA凸包算法
呵呵,有点儿像当年看着没信号的电视。。。下一步要把它用在ArcGIS Server上。
代码
源码一:JarvisMarch.java
package mtn.uis.xaltin.convex;
import static java.lang.Math.abs;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class JarvisMarch {
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
private static int MAX_ANGLE = 4;
private double currentMinAngle = 0;
private List<Point> hullPointList;
private List<Integer> indexList;
private PointFactory pf;
private Point[] ps;
public Point[] getPs() {
return ps;
}
private int firstIndex;
public int getFirstIndex() {
return firstIndex;
}
public JarvisMarch() {
this(10);
}
public JarvisMarch(int count) {
pf = PointFactory.getInstance(count);
initialize();
}
public JarvisMarch(int[] x, int[] y) {
pf = PointFactory.getInstance(x, y);
initialize();
}
private void initialize() {
hullPointList = new LinkedList<Point>();
indexList = new LinkedList<Integer>();
firstIndex = pf.getFirstIndex();
ps = pf.getPoints();
addToHull(firstIndex);
}
private void addToHull(int index) {
indexList.add(index);
hullPointList.add(ps[index]);
}
public int calculateHull() {
for (int i = getNextIndex(firstIndex); i != firstIndex; i = getNextIndex(i)) {
addToHull(i);
}
showHullPoints();
return 0;
}
private void showHullPoints() {
Iterator<Point> itPoint = hullPointList.iterator();
Iterator<Integer> itIndex = indexList.iterator();
Point p;
int i;
int index = 0;
System.out.println("The hull points is: -> ");
while (itPoint.hasNext()) {
i = itIndex.next();
p = itPoint.next();
System.out.print(i + ":(" + p.getX() + "," + p.getY() + ") ");
index++;
if (index % 10 == 0)
System.out.println();
}
System.out.println();
System.out.println("****************************************************************");
System.out.println("The count of all hull points is " + index);
}
public int getNextIndex(int currentIndex) {
double minAngle = MAX_ANGLE;
double pseudoAngle;
int minIndex = 0;
for (int i = 0; i < ps.length; i++) {
if (i != currentIndex) {
pseudoAngle = getPseudoAngle(ps[i].getX() - ps[currentIndex].getX(),
ps[i].getY() - ps[currentIndex].getY());
if (pseudoAngle >= currentMinAngle && pseudoAngle < minAngle) {
minAngle = pseudoAngle;
minIndex = i;
} else if (pseudoAngle == minAngle){
if((abs(ps[i].getX() - ps[currentIndex].getX()) >
abs(ps[minIndex].getX() - ps[currentIndex].getX()))
|| (abs(ps[i].getY() - ps[currentIndex].getY()) >
abs(ps[minIndex].getY() - ps[currentIndex].getY()))){
minIndex = i;
}
}
}
}
currentMinAngle = minAngle;
return minIndex;
}
public double getPseudoAngle(double dx, double dy) {
if (dx > 0 && dy >= 0)
return dy / (dx + dy);
if (dx <= 0 && dy > 0)
return 1 + (abs(dx) / (abs(dx) + dy));
if (dx < 0 && dy <= 0)
return 2 + (dy / (dx + dy));
if (dx >= 0 && dy < 0)
return 3 + (dx / (dx + abs(dy)));
throw new Error("Impossible");
}
}
源码二:Point.java
package mtn.uis.xaltin.convex;
public class Point {
// 定义点的x,y坐标,之所以是int类型,是为了日后可以在计算机屏幕上进行可视化。
private int x;
private int y;
// x,y的get方法
public int getX() {
return x;
}
public int getY() {
return y;
}
// 定义点到屏幕边缘的距离
private static double PADDING = 20;
// 点在屏幕中的范围
private static double POINT_RANGE = (800 - PADDING * 2);
// 默认构造方法,产生随机点
public Point() {
this.x = (int) ((Math.random() * POINT_RANGE) + PADDING);
this.y = (int) ((Math.random() * POINT_RANGE) + PADDING);
}
// 带参构造方法,可以实现手动输入固定点
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// 覆写hashCode()和equals()方法,实现比较和Hash
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
Point other = (Point) obj;
if ((x == other.x) && (y == other.y))
return true;
return false;
}
}
源码三:PointFactory.java
package mtn.uis.xaltin.convex;
public class PointFactory {
/**
* 单例模式,大批量产生Point,也可以手动产生Point
*/
private Point[] points = null;
private int newIndex;
private int firstIndex = 0;
public Point[] getPoints() {
return points;
}
public int getFirstIndex() {
return firstIndex;
}
public static PointFactory getInstance() {
return new PointFactory();
}
public static PointFactory getInstance(int count) {
return new PointFactory(count);
}
public static PointFactory getInstance(int[] x, int[] y) {
return new PointFactory(x, y);
}
private PointFactory() {
this(10);
}
private PointFactory(int count) {
points = new Point[count];
for (int i = 0; i < count; i++) {
points[i] = new Point();
newIndex = i;
validatePoints();
}
firstIndex = getFirstPoint();
}
public PointFactory(int[] x, int[] y) {
points = new Point[y.length];
for (int i = 0; i < y.length; i++) {
points[i] = new Point(x[i], y[i]);
}
firstIndex = getFirstPoint();
}
private void validatePoints() {
for(int i = 0; i < newIndex; i++) {
if(points[i].equals(points[newIndex])) {
points[newIndex] = new Point();
validatePoints();
}
}
}
public int getFirstPoint() {
int minIndex = 0;
for (int i = 1; i < points.length; i++) {
if (points[i].getY() < points[minIndex].getY()) {
minIndex = i;
} else if ((points[i].getY() == points[minIndex].getY())
&& (points[i].getX() < points[minIndex].getX())) {
minIndex = i;
}
}
return minIndex;
}
}
源码四:Test.java(主函数)
package mtn.uis.xaltin.convex;
public class Test {
public static void main(String[] args) {
long start = System.currentTimeMillis();
JarvisMarch j = new JarvisMarch(100000);
Point[] points = j.getPs();
int firstIndex = j.getFirstIndex();
// for (int i = 0; i < points.length; i++) {
// System.out.print(i + ":(" + points[i].getX() + "," + points[i].getY() + ") ");
// if((i+1) % 10 == 0) {
// System.out.println();
// }
// }
// System.out.println();
// System.out.println("*****************************************************************");
System.out.println("the first point is: " + firstIndex + ":(" +
points[firstIndex].getX() + "," + points[firstIndex].getY() + ")");
System.out.println("*****************************************************************");
j.calculateHull();
System.out.println("The total running time is " + (System.currentTimeMillis() - start) + " millis.");
}
}