code: static List<Point2D> grahamScan(final List<Point2D> points) {
  
          if (points.size() <= 3) return new ArrayList<Point2D>(points);
  
          Collections.sort(points, new CompareYThenX());
          Collections.sort(points, new PolarComparator(points.get(0)));
  
          Deque<Point2D> hull = new ArrayDeque<Point2D>();
  
          hull.push(points.get(0));
          hull.push(points.get(1));
          hull.push(points.get(2));
  
          for (int i = 3; i < points.size(); i++) {
              Point2D top = hull.pop();
              while (!hull.isEmpty() && !isLeftTurn(hull.peek(), top, points.get(i))) {
                  top = hull.pop();
              }
              hull.push(top);
              hull.push(points.get(i));
          }
  
          return new ArrayList<Point2D>(hull);
      }
docs: The Graham Scan algorithm determines the points belonging to the convex hull in O(n lg n).
  
  @param points set of points
  @return points in the convex hull
  @see <a href="http://en.wikipedia.org/wiki/Graham_scan">Graham scan, Wikipedia</a>