mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-12-19 07:00:35 +08:00
118 lines
3.9 KiB
Java
118 lines
3.9 KiB
Java
package com.thealgorithms.geometry;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
/**
|
|
* A class providing algorithms to compute the convex hull of a set of points
|
|
* using brute-force and recursive methods.
|
|
*
|
|
* Convex hull: The smallest convex polygon that contains all the given points.
|
|
*
|
|
* Algorithms provided:
|
|
* 1. Brute-Force Method
|
|
* 2. Recursive (Divide-and-Conquer) Method
|
|
*
|
|
* @author Hardvan
|
|
*/
|
|
public final class ConvexHull {
|
|
private ConvexHull() {
|
|
}
|
|
|
|
private static boolean checkPointOrientation(Point i, Point j, Point k) {
|
|
int detK = Point.orientation(i, j, k);
|
|
if (detK > 0) {
|
|
return true; // pointsLeftOfIJ
|
|
} else if (detK < 0) {
|
|
return false; // pointsRightOfIJ
|
|
} else {
|
|
return k.compareTo(i) >= 0 && k.compareTo(j) <= 0;
|
|
}
|
|
}
|
|
|
|
public static List<Point> convexHullBruteForce(List<Point> points) {
|
|
Set<Point> convexSet = new TreeSet<>(Comparator.naturalOrder());
|
|
|
|
for (int i = 0; i < points.size() - 1; i++) {
|
|
for (int j = i + 1; j < points.size(); j++) {
|
|
boolean allPointsOnOneSide = true;
|
|
boolean leftSide = checkPointOrientation(points.get(i), points.get(j), points.get((i + 1) % points.size()));
|
|
|
|
for (int k = 0; k < points.size(); k++) {
|
|
if (k != i && k != j && checkPointOrientation(points.get(i), points.get(j), points.get(k)) != leftSide) {
|
|
allPointsOnOneSide = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (allPointsOnOneSide) {
|
|
convexSet.add(points.get(i));
|
|
convexSet.add(points.get(j));
|
|
}
|
|
}
|
|
}
|
|
|
|
return new ArrayList<>(convexSet);
|
|
}
|
|
|
|
public static List<Point> convexHullRecursive(List<Point> points) {
|
|
Collections.sort(points);
|
|
Set<Point> convexSet = new HashSet<>();
|
|
Point leftMostPoint = points.get(0);
|
|
Point rightMostPoint = points.get(points.size() - 1);
|
|
|
|
convexSet.add(leftMostPoint);
|
|
convexSet.add(rightMostPoint);
|
|
|
|
List<Point> upperHull = new ArrayList<>();
|
|
List<Point> lowerHull = new ArrayList<>();
|
|
|
|
for (int i = 1; i < points.size() - 1; i++) {
|
|
int det = Point.orientation(leftMostPoint, rightMostPoint, points.get(i));
|
|
if (det > 0) {
|
|
upperHull.add(points.get(i));
|
|
} else if (det < 0) {
|
|
lowerHull.add(points.get(i));
|
|
}
|
|
}
|
|
|
|
constructHull(upperHull, leftMostPoint, rightMostPoint, convexSet);
|
|
constructHull(lowerHull, rightMostPoint, leftMostPoint, convexSet);
|
|
|
|
List<Point> result = new ArrayList<>(convexSet);
|
|
Collections.sort(result);
|
|
return result;
|
|
}
|
|
|
|
private static void constructHull(Collection<Point> points, Point left, Point right, Set<Point> convexSet) {
|
|
if (!points.isEmpty()) {
|
|
Point extremePoint = null;
|
|
int extremePointDistance = Integer.MIN_VALUE;
|
|
List<Point> candidatePoints = new ArrayList<>();
|
|
|
|
for (Point p : points) {
|
|
int det = Point.orientation(left, right, p);
|
|
if (det > 0) {
|
|
candidatePoints.add(p);
|
|
if (det > extremePointDistance) {
|
|
extremePointDistance = det;
|
|
extremePoint = p;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (extremePoint != null) {
|
|
constructHull(candidatePoints, left, extremePoint, convexSet);
|
|
convexSet.add(extremePoint);
|
|
constructHull(candidatePoints, extremePoint, right, convexSet);
|
|
}
|
|
}
|
|
}
|
|
}
|