import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.util.*;
import javax.swing.*;
public class ConvexHull {
static class Point {
public Point(double x, double y) {
this.x = x;
this.y = y;
}
double x, y;
//formula from geometry course
static int ccw(Point a, Point b, Point c) {
double area = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
if(area < 0) return -1;
if(area > 0) return 1; //counter clockwise
else return 0;
}
public final Comparator<Point> POLAR_ORDER = new PolarOrder();
private class PolarOrder implements Comparator<Point> {
public int compare(Point q1, Point q2) {
double dx1 = q1.x - x;
double dy1 = q1.y - y;
double dx2 = q2.x - x;
double dy2 = q2.y - y;
if (dy1 >= 0 && dy2 < 0) return -1; // q1 above; q2 below
else if (dy2 >= 0 && dy1 < 0) return +1; // q1 below; q2 above
else if (dy1 == 0 && dy2 == 0) { // 3-collinear and horizontal
if (dx1 >= 0 && dx2 < 0) return -1;
else if (dx2 >= 0 && dx1 < 0) return +1;
else return 0;
}
else return -ccw(Point.this, q1, q2); // both above or below
}
}
@Override
public String toString() {
return "(" + x + "," + y + ")";
}
}
private static List<Point> points = new ArrayList<>();
private static final int N = 300;
private static final double Max = 300;
public static void main(String...args) {
Random r = new Random();
for(int i = 0; i < N; i++) {
points.add(new Point(r.nextDouble() * Max, r.nextDouble() * Max));
}
Collections.sort(points, (p1, p2) -> (int)(p1.y - p2.y));
Collections.sort(points, points.get(0).POLAR_ORDER);
Deque<Point> hull = new ArrayDeque<>();
hull.push(points.get(0));
hull.push(points.get(1));
for(int i = 2; i < points.size(); i++) {
Point top = hull.pop();
Point c = points.get(i);
while(Point.ccw(hull.peek(), top, c) <= 0) {
top = hull.pop();
}
hull.push(top);
hull.push(c);
}
myDraw(new PolarDraw(points.get(0), points, hull));
}
static void myDraw(JPanel jpanel) {
JFrame frame = new JFrame("Points");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(jpanel);
frame.setSize((int)(Max * 2), (int)(Max * 1.5));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static class PolarDraw extends JPanel {
private Point origin;
private List<Point> points;
private Deque<Point> hull;
public PolarDraw(Point origin, List<Point> points, Deque<Point> hull) {
this.origin = origin;
this.points = points;
this.hull = hull;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.red);
int i = 0;
for (Point p: points) {
g2d.draw(new Line2D.Double(origin.x, origin.y, p.x, p.y));
g2d.drawString("" + (i++), (int)p.x, (int)p.y);
}
g2d.setColor(Color.blue);
Point p0 = hull.poll();
Point p;
while((p = hull.poll()) != null) {
g2d.draw(new Line2D.Double(p0.x, p0.y, p.x, p.y));
p0 = p;
}
}
}
}