public static List<VoronoiPoint> getConvexHull(List<VoronoiPoint> points) throws IllegalArgumentException {

        List<VoronoiPoint> sorted = new ArrayList<>(getSortedPointSet(points));

        if(sorted.size() < 3) {
            throw new IllegalArgumentException("can only create a convex hull of 3 or more unique points");
        }

        if(areAllCollinear(sorted)) {
            throw new IllegalArgumentException("cannot create a convex hull from collinear points");
        }

        Stack<VoronoiPoint> stack = new Stack<>();
        stack.push(sorted.get(0));
        stack.push(sorted.get(1));

        for (int i = 2; i < sorted.size(); i++) {

            VoronoiPoint head = sorted.get(i);
            VoronoiPoint middle = stack.pop();
            VoronoiPoint tail = stack.peek();

            Turn turn = getTurn(tail, middle, head);

            switch(turn) {
                case COUNTER_CLOCKWISE:
                    stack.push(middle);
                    stack.push(head);
                    break;
                case CLOCKWISE:
                    i--;
                    break;
                case COLLINEAR:
                    stack.push(head);
                    break;
            }
        }

        // close the hull
        stack.push(sorted.get(0));

        return new ArrayList<>(stack);
    }
Returns the convex hull of the points created from the list
<code>points</code>. Note that the first and last point in the
returned VoronoiPoint are the same
point.

@param points the list of points.
@return       the convex hull of the points created from the list
              <code>points</code>.
@throws IllegalArgumentException if all points are collinear or if there
                                 are less than 3 unique points present.
vorolay/src/main/java/quatja/com/vorolay/GrahamScan.java