package org.geogebra.common.util.clipper; import java.util.Comparator; public abstract class Point<T extends Number & Comparable<T>> { public static class DoublePoint extends Point<Double> { public static double getDeltaX(DoublePoint pt1, DoublePoint pt2) { if (pt1.getY() == pt2.getY()) { return Edge.HORIZONTAL; } return (pt2.getX() - pt1.getX()) / (pt2.getY() - pt1.getY()); } public DoublePoint() { this(0, 0); } public DoublePoint(double x, double y) { this(x, y, 0); } public DoublePoint(double x, double y, double z) { super(x, y, z); } public DoublePoint(DoublePoint other) { super(other); } public double getX() { return x; } public double getY() { return y; } public double getZ() { return z; } } private static class NumberComparator<T extends Number & Comparable<T>> implements Comparator<T> { @Override public int compare(T a, T b) throws ClassCastException { return a.compareTo(b); } } static boolean arePointsClose(Point<? extends Number> pt1, Point<? extends Number> pt2, double distSqrd) { final double dx = pt1.x.doubleValue() - pt2.x.doubleValue(); final double dy = pt1.y.doubleValue() - pt2.y.doubleValue(); return dx * dx + dy * dy <= distSqrd; } static double distanceFromLineSqrd(Point<? extends Number> pt, Point<? extends Number> ln1, Point<? extends Number> ln2) { // The equation of a line in general form (a x + b y + c = 0) // given 2 points (x1,y1) & (x2,y2) is ... // (y1 - y2)x + (x2 - x1)y + (y2 - y1)x1 - (x2 - x1)y1 = 0 // A = (y1 - y2); B = (x2 - x1); c = (y2 - y1)x1 - (x2 - x1)y1 // perpendicular distance of point (x0,y0) is // (a x0 + b y0 + c) / sqrt(a^2 + b^2) // see https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line final double A = ln1.y.doubleValue() - ln2.y.doubleValue(); final double B = ln2.x.doubleValue() - ln1.x.doubleValue(); double C = A * ln1.x.doubleValue() + B * ln1.y.doubleValue(); C = A * pt.x.doubleValue() + B * pt.y.doubleValue() - C; return C * C / (A * A + B * B); } /** * modified to be compatible with double */ static DoublePoint getUnitNormal(DoublePoint pt1, DoublePoint pt2) { double dx = pt2.x - pt1.x; double dy = pt2.y - pt1.y; if (dx == 0 && dy == 0) { return new DoublePoint(); } final double f = 1 * 1.0 / Math.sqrt(dx * dx + dy * dy); dx *= f; dy *= f; return new DoublePoint(dy, -dx); } /** * modified to be compatible with double */ protected static boolean isPt2BetweenPt1AndPt3(DoublePoint pt1, DoublePoint pt2, DoublePoint pt3) { if (pt1.equals(pt3) || pt1.equals(pt2) || pt3.equals(pt2)) { return false; } else if (pt1.x != pt3.x) { return pt2.x > pt1.x == pt2.x < pt3.x; } else { return pt2.y > pt1.y == pt2.y < pt3.y; } } /** * modified to be compatible with double */ protected static boolean slopesEqual(DoublePoint pt1, DoublePoint pt2, DoublePoint pt3) { return (pt1.y - pt2.y) * (pt2.x - pt3.x) - (pt1.x - pt2.x) * (pt2.y - pt3.y) == 0; } /** * modified to be compatible with double */ protected static boolean slopesEqual(DoublePoint pt1, DoublePoint pt2, DoublePoint pt3, DoublePoint pt4) { return (pt1.y - pt2.y) * (pt3.x - pt4.x) - (pt1.x - pt2.x) * (pt3.y - pt4.y) == 0; } /** * modified to be compatible with double */ static boolean slopesNearCollinear(DoublePoint pt1, DoublePoint pt2, DoublePoint pt3, double distSqrd) { // this function is more accurate when the point that's GEOMETRICALLY // between the other 2 points is the one that's tested for distance. // nb: with 'spikes', either pt1 or pt3 is geometrically between the // other pts if (Math.abs(pt1.x - pt2.x) > Math.abs(pt1.y - pt2.y)) { if (pt1.x > pt2.x == pt1.x < pt3.x) { return distanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; } else if (pt2.x > pt1.x == pt2.x < pt3.x) { return distanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; } else { return distanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; } } if (pt1.y > pt2.y == pt1.y < pt3.y) { return distanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; } else if (pt2.y > pt1.y == pt2.y < pt3.y) { return distanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; } else { return distanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; } } private final static NumberComparator NUMBER_COMPARATOR = new NumberComparator(); protected T x; protected T y; protected T z; protected Point(Point<T> pt) { this(pt.x, pt.y, pt.z); } protected Point(T x, T y, T z) { this.x = x; this.y = y; this.z = z; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj instanceof Point<?>) { final Point<?> a = (Point<?>) obj; return NUMBER_COMPARATOR.compare(x, a.x) == 0 && NUMBER_COMPARATOR.compare(y, a.y) == 0; } return false; } @Override public int hashCode() { return x.hashCode() + y.hashCode() * 37 + z.hashCode() * 41; } public void set(Point<T> other) { x = other.x; y = other.y; z = other.z; } public void setX(T x) { this.x = x; } public void setY(T y) { this.y = y; } public void setZ(T z) { this.z = z; } @Override public String toString() { return "Point [x=" + x + ", y=" + y + ", z=" + z + "]"; } }// end struct IntPoint