1
2
3
4
5
6
7
8
9 package math.geom2d.polygon.convhull;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.Comparator;
15 import java.util.List;
16
17 import math.geom2d.Angle2D;
18 import math.geom2d.Point2D;
19 import math.geom2d.polygon.Polygon2D;
20 import math.geom2d.polygon.SimplePolygon2D;
21
22
23
24
25
26
27 public class GrahamScan2D implements ConvexHull2D {
28
29
30
31
32 public GrahamScan2D() {
33 }
34
35
36
37
38 public Polygon2D convexHull(Collection<? extends Point2D> points) {
39 int nbPoints = points.size();
40
41
42
43 Point2D lowestPoint = null;
44 double lowestY = Double.MAX_VALUE;
45 for(Point2D point : points){
46 double y = point.getY();
47 if(y<lowestY){
48 lowestPoint = point;
49 lowestY = y;
50 }
51 }
52
53
54 Comparator<Point2D> comparator =
55 new CompareByPseudoAngle(lowestPoint);
56
57
58 ArrayList<Point2D> sorted = new ArrayList<Point2D>(nbPoints);
59 sorted.addAll(points);
60 Collections.sort(sorted, comparator);
61
62
63
64
65 int m = 2;
66 for(int i=3; i<nbPoints; i++){
67 while(Point2D.ccw(sorted.get(m), sorted.get(m-1),
68 sorted.get(i))>=0)
69 m--;
70 m++;
71 Collections.swap(sorted, m, i);
72 }
73
74
75 List<Point2D> hull = sorted.subList(0, Math.min(m+1, nbPoints));
76 return new SimplePolygon2D(hull);
77 }
78
79 private class CompareByPseudoAngle implements Comparator<Point2D>{
80 Point2D basePoint;
81 public CompareByPseudoAngle(Point2D base) {
82 this.basePoint = base;
83 }
84
85
86
87
88 public int compare(Point2D point1, Point2D point2) {
89 double angle1 = Angle2D.getPseudoAngle(basePoint, point1);
90 double angle2 = Angle2D.getPseudoAngle(basePoint, point2);
91
92 if(angle1<angle2) return -1;
93 if(angle1>angle2) return +1;
94
95 return 0;
96 }
97 }
98 }