import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.util.Arrays; import java.util.Random; public class AngleAreaOrientationSortRotationPerpendicular { // pay attention to case ax==0 && ay==0 or bx==0 && by == 0 public static double angleBetween(long ax, long ay, long bx, long by) { double a = Math.atan2(ax * by - ay * bx, ax * bx + ay * by); return a < 0 ? a + 2 * Math.PI : a; } // pay attention to case ax==0 && ay==0 or bx==0 && by == 0 public static double angleBetween2(long ax, long ay, long bx, long by) { double a = Math.atan2(by, bx) - Math.atan2(ay, ax); return a < 0 ? a + 2 * Math.PI : a; } public static long doubleSignedArea(int[] x, int[] y) { int n = x.length; long area = 0; for (int i = 0, j = n - 1; i < n; j = i++) { area += (long) (x[i] - x[j]) * (y[i] + y[j]); // area += (long) x[i] * y[j] - (long) x[j] * y[i]; } return area; } // Returns -1 for clockwise, 0 for straight line, 1 for counterclockwise orientation public static int orientation(long ax, long ay, long bx, long by, long cx, long cy) { bx -= ax; by -= ay; cx -= ax; cy -= ay; return Long.signum(bx * cy - by * cx); } public static boolean isMiddle(long a, long m, long b) { return Math.min(a, b) <= m && m <= Math.max(a, b); } public static boolean isMiddle(long ax, long ay, long mx, long my, long bx, long by) { return orientation(ax, ay, mx, my, bx, by) == 0 && isMiddle(ax, mx, bx) && isMiddle(ay, my, by); } public static class Point implements Comparable { int x; int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public int compareTo(Point o) { boolean up1 = y > 0 || (y == 0 && x >= 0); boolean up2 = o.y > 0 || (o.y == 0 && o.x >= 0); if (up1 != up2) return up1 ? -1 : 1; int cmp = Long.signum((long) o.x * y - (long) o.y * x); if (cmp != 0) return cmp; return Long.compare((long) x * x + (long) y * y, (long) o.x * o.x + (long) o.y * o.y); //return Double.compare(Math.atan2(y, x), Math.atan2(o.y, o.x)); } @Override public String toString() { return "(" + x + ',' + y + ')'; } } public Point2D.Double rotateCCW(Point2D.Double p, double angle) { return new Point2D.Double(p.x * Math.cos(angle) - p.y * Math.sin(angle), p.x * Math.sin(angle) + p.y * Math.cos(angle)); } public Line perpendicular(Line line, long x, long y) { return new Line(-line.b, line.a, line.b * x - line.a * y); } public static class Line { long a, b, c; public Line(long a, long b, long c) { this.a = a; this.b = b; this.c = c; } } // random test public static void main(String[] args) { Random rnd = new Random(1); int range = 100; for (int step = 0; step < 100_000; step++) { long ax = rnd.nextInt(range) - range / 2; long ay = rnd.nextInt(range) - range / 2; long bx = rnd.nextInt(range) - range / 2; long by = rnd.nextInt(range) - range / 2; long cx = rnd.nextInt(range) - range / 2; long cy = rnd.nextInt(range) - range / 2; int orientation1 = orientation(ax, ay, bx, by, cx, cy); int orientation2 = -Line2D.relativeCCW(ax, ay, bx, by, cx, cy); if (orientation1 == 0) continue; if (orientation1 != orientation2) throw new RuntimeException(); if (ax == 0 && ay == 0 || bx == 0 && by == 0) continue; double res1 = angleBetween(ax, ay, bx, by); double res2 = angleBetween2(ax, ay, bx, by); if (!(Math.abs(res1 - res2) < 1e-9)) throw new RuntimeException(); } Point[] points = new Point[]{new Point(1, 1), new Point(1, -1), new Point(0, 0)}; Arrays.sort(points); System.out.println(Arrays.toString(points)); } }