View Javadoc

1   /**
2    * File: 	GrahamScan2D.java
3    * Project: javaGeom
4    * 
5    * Distributed under the LGPL License.
6    *
7    * Created: 18 janv. 09
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   * @author dlegland
25   *
26   */
27  public class GrahamScan2D implements ConvexHull2D {
28  
29      /**
30       * Creates a new Convex hull calculator.
31       */
32      public GrahamScan2D() {
33      }
34  
35      /* (non-Javadoc)
36       * @see math.geom2d.polygon.convhull.ConvexHull2D#convexHull(java.util.Collection)
37       */
38      public Polygon2D convexHull(Collection<? extends Point2D> points) {
39          int nbPoints = points.size();
40          //TODO: manage small values of n
41          
42          // Find point with lowest y-coord
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          // build the comparator, using the lowest point
54          Comparator<Point2D> comparator = 
55              new CompareByPseudoAngle(lowestPoint);
56          
57          // create a sorted set
58          ArrayList<Point2D> sorted = new ArrayList<Point2D>(nbPoints);
59          sorted.addAll(points);
60          Collections.sort(sorted, comparator);
61          
62          // main loop
63          // i-> current vertex of point cloud
64          // m-> current hull vertex
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          // Format result to return a polygon
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          /* (non-Javadoc)
86           * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
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              //TODO: and what about colinear points ?
95              return 0;
96          }
97      }
98  }