programming-examples/java/Data_Structures/AngleAreaOrientationSortRotationPerpendicular.java
2019-11-15 12:59:38 +01:00

120 lines
3.6 KiB
Java

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<Point> {
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));
}
}