11package algolib .geometry .dim2 ;
22
33import java .util .ArrayList ;
4- import java .util .Collections ;
4+ import java .util .Comparator ;
55import java .util .List ;
6+ import java .util .stream .Collectors ;
67
7- /** Algorithm for convex hull in 2D (monotone chain ). */
8+ /** Algorithm for convex hull in 2D (Graham's scan ). */
89public final class ConvexHull
910{
1011 /**
@@ -17,38 +18,29 @@ public static List<Point2D> findConvexHull(List<Point2D> points)
1718 if (points .size () < 3 )
1819 return List .of ();
1920
20- List <Point2D > sorted = new ArrayList <>(points );
21+ Point2D minPoint = points .stream ()
22+ .min (Comparator .comparingDouble ((Point2D pt ) -> pt .y )
23+ .thenComparingDouble (pt -> pt .x ))
24+ .orElseThrow ();
25+ Vector2D moving = Vector2D .between (Point2D .of (0 , 0 ), minPoint );
26+ List <Point2D > anglePoints = points .stream ()
27+ .map (pt -> Geometry2D .translate (pt , moving .negate ()))
28+ .collect (Collectors .toCollection (ArrayList ::new ));
2129
22- Geometry2D .sortByX ( sorted );
30+ Geometry2D .sortByAngle ( anglePoints );
2331
24- List <Point2D > lowerHull = createHalfHull (sorted );
25-
26- Collections .reverse (sorted );
27-
28- List <Point2D > upperHull = createHalfHull (sorted );
29-
30- lowerHull .remove (lowerHull .size () - 1 );
31- upperHull .remove (upperHull .size () - 1 );
32- lowerHull .addAll (upperHull );
33- return lowerHull ;
34- }
35-
36- // Computes half of convex hull for given points.
37- private static List <Point2D > createHalfHull (List <Point2D > points )
38- {
3932 List <Point2D > hull = new ArrayList <>();
4033
41- for (Point2D pt : points )
34+ for (Point2D pt : anglePoints )
4235 {
4336 while (hull .size () > 1
44- && crossProduct (hull .get (hull .size () - 2 ), hull .get (hull .size () - 1 ), pt )
45- >= 0 )
37+ && crossProduct (hull .get (hull .size () - 2 ), hull .get (hull .size () - 1 ), pt ) >= 0 )
4638 hull .remove (hull .size () - 1 );
4739
4840 hull .add (pt );
4941 }
5042
51- return hull ;
43+ return hull . stream (). map ( pt -> Geometry2D . translate ( pt , moving )). toList () ;
5244 }
5345
5446 private static double crossProduct (Point2D pt1 , Point2D pt2 , Point2D pt3 )
0 commit comments