什么是凸包?
给定大量离散点的集合Q求一个最小的凸多边形,使得Q中的点在该多边形内或边上。
本方案为分治法求解凸包问题。
首先给定一个点的类:
public class Point {
private final double x;
private final double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double x() {
return x;
}
public double y() {
return y;
}
}
找出点集中在左下角的点,作为初始点。
public static Point getminPoint(List<Point> points) {
Point minPoint = points.get(0);
for(int i = 1;i<points.size();i++) {
if(points.get(i).x()<minPoint.x()) {
minPoint = points.get(i);
}else if(points.get(i).x() == minPoint.x()) {
if(points.get(i).y()<minPoint.y()) {
minPoint = points.get(i);
}
}
}
return minPoint;
}
计算两个点的极角。
public static double calculatebearings(Point point1,Point point2) {
double angle = Math.atan2(point2.y() - point1.y(), point2.x() - point1.x()) * 180 / Math.PI;
if (angle < 0) {
angle += 360;
}
return angle;
}
主函数。
public static Set<Point> Hull(Set<Point> points){
ArrayList<Integer> PointIndex = new ArrayList<>();
Set<Point> HullSet = new HashSet<Point>();
List<Point> PointsList = new ArrayList<>(points);
/*点集小于3个时,点集即为凸包*/
if(PointsList.size() <= 3) {
for(int i = 0;i<PointsList.size();i++) {
HullSet.add(PointsList.get(i));
}
return HullSet;
}
Point MinPoint = getminPoint(PointsList);
double MinAngle = 360,Angle = 0;
int MinIndex = 0,Index = 0;
/*确定左下角的点在list中的位置*/
for(int i = 0;i<PointsList.size();i++) {
if((MinPoint.x() == PointsList.get(i).x())&&(MinPoint.y() == PointsList.get(i).y()))
MinIndex = i;
}
PointIndex.add(MinIndex);
HullSet.add(PointsList.get(MinIndex));
while(true) {
MinAngle = 360;
for(int i = 0;i<PointsList.size();i++) {
if(i == MinIndex) {
continue;
}
Angle = calculatebearings(PointsList.get(MinIndex), PointsList.get(i));
if(Angle < MinAngle) {
MinAngle = Angle;
Index = i;
}else if(Angle == MinAngle) {
double my = PointsList.get(MinIndex).y();
double ty = PointsList.get(Index).y();
double iy = PointsList.get(i).y();
if (((my - ty < 0) && (ty - iy < 0))||((my - ty > 0) && (ty - iy > 0))||(ty == iy)) {
MinAngle = Angle;
Index = i;
}
}
}
for(int j = 0;j<PointIndex.size();j++) {
if(PointIndex.get(j) == Index) {
return HullSet;
}
}
MinIndex = Index;
PointIndex.add(MinIndex);
HullSet.add(PointsList.get(MinIndex));
}
}