136 lines
4.7 KiB
Java
136 lines
4.7 KiB
Java
import java.util.Objects;
|
|
|
|
public class FindTriangle {
|
|
private static final double EPS = 0.001;
|
|
private static final double EPS_SQUARE = EPS * EPS;
|
|
|
|
public static class Point {
|
|
private final double x, y;
|
|
|
|
public Point(double x, double y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
|
|
public double getX() {
|
|
return x;
|
|
}
|
|
|
|
public double getY() {
|
|
return y;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return String.format("(%f, %f)", x, y);
|
|
}
|
|
}
|
|
|
|
public static class Triangle {
|
|
private final Point p1, p2, p3;
|
|
|
|
public Triangle(Point p1, Point p2, Point p3) {
|
|
this.p1 = Objects.requireNonNull(p1);
|
|
this.p2 = Objects.requireNonNull(p2);
|
|
this.p3 = Objects.requireNonNull(p3);
|
|
}
|
|
|
|
public Point getP1() {
|
|
return p1;
|
|
}
|
|
|
|
public Point getP2() {
|
|
return p2;
|
|
}
|
|
|
|
public Point getP3() {
|
|
return p3;
|
|
}
|
|
|
|
private boolean pointInTriangleBoundingBox(Point p) {
|
|
var xMin = Math.min(p1.getX(), Math.min(p2.getX(), p3.getX())) - EPS;
|
|
var xMax = Math.max(p1.getX(), Math.max(p2.getX(), p3.getX())) + EPS;
|
|
var yMin = Math.min(p1.getY(), Math.min(p2.getY(), p3.getY())) - EPS;
|
|
var yMax = Math.max(p1.getY(), Math.max(p2.getY(), p3.getY())) + EPS;
|
|
return !(p.getX() < xMin || xMax < p.getX() || p.getY() < yMin || yMax < p.getY());
|
|
}
|
|
|
|
private static double side(Point p1, Point p2, Point p) {
|
|
return (p2.getY() - p1.getY()) * (p.getX() - p1.getX()) + (-p2.getX() + p1.getX()) * (p.getY() - p1.getY());
|
|
}
|
|
|
|
private boolean nativePointInTriangle(Point p) {
|
|
boolean checkSide1 = side(p1, p2, p) >= 0;
|
|
boolean checkSide2 = side(p2, p3, p) >= 0;
|
|
boolean checkSide3 = side(p3, p1, p) >= 0;
|
|
return checkSide1 && checkSide2 && checkSide3;
|
|
}
|
|
|
|
private double distanceSquarePointToSegment(Point p1, Point p2, Point p) {
|
|
double p1_p2_squareLength = (p2.getX() - p1.getX()) * (p2.getX() - p1.getX()) + (p2.getY() - p1.getY()) * (p2.getY() - p1.getY());
|
|
double dotProduct = ((p.getX() - p1.getX()) * (p2.getX() - p1.getX()) + (p.getY() - p1.getY()) * (p2.getY() - p1.getY())) / p1_p2_squareLength;
|
|
if (dotProduct < 0) {
|
|
return (p.getX() - p1.getX()) * (p.getX() - p1.getX()) + (p.getY() - p1.getY()) * (p.getY() - p1.getY());
|
|
}
|
|
if (dotProduct <= 1) {
|
|
double p_p1_squareLength = (p1.getX() - p.getX()) * (p1.getX() - p.getX()) + (p1.getY() - p.getY()) * (p1.getY() - p.getY());
|
|
return p_p1_squareLength - dotProduct * dotProduct * p1_p2_squareLength;
|
|
}
|
|
return (p.getX() - p2.getX()) * (p.getX() - p2.getX()) + (p.getY() - p2.getY()) * (p.getY() - p2.getY());
|
|
}
|
|
|
|
private boolean accuratePointInTriangle(Point p) {
|
|
if (!pointInTriangleBoundingBox(p)) {
|
|
return false;
|
|
}
|
|
if (nativePointInTriangle(p)) {
|
|
return true;
|
|
}
|
|
if (distanceSquarePointToSegment(p1, p2, p) <= EPS_SQUARE) {
|
|
return true;
|
|
}
|
|
if (distanceSquarePointToSegment(p2, p3, p) <= EPS_SQUARE) {
|
|
return true;
|
|
}
|
|
return distanceSquarePointToSegment(p3, p1, p) <= EPS_SQUARE;
|
|
}
|
|
|
|
public boolean within(Point p) {
|
|
Objects.requireNonNull(p);
|
|
return accuratePointInTriangle(p);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return String.format("Triangle[%s, %s, %s]", p1, p2, p3);
|
|
}
|
|
}
|
|
|
|
private static void test(Triangle t, Point p) {
|
|
System.out.println(t);
|
|
System.out.printf("Point %s is within triangle? %s\n", p, t.within(p));
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
var p1 = new Point(1.5, 2.4);
|
|
var p2 = new Point(5.1, -3.1);
|
|
var p3 = new Point(-3.8, 1.2);
|
|
var tri = new Triangle(p1, p2, p3);
|
|
test(tri, new Point(0, 0));
|
|
test(tri, new Point(0, 1));
|
|
test(tri, new Point(3, 1));
|
|
System.out.println();
|
|
|
|
p1 = new Point(1.0 / 10, 1.0 / 9);
|
|
p2 = new Point(100.0 / 8, 100.0 / 3);
|
|
p3 = new Point(100.0 / 4, 100.0 / 9);
|
|
tri = new Triangle(p1, p2, p3);
|
|
var pt = new Point(p1.getX() + (3.0 / 7) * (p2.getX() - p1.getX()), p1.getY() + (3.0 / 7) * (p2.getY() - p1.getY()));
|
|
test(tri, pt);
|
|
System.out.println();
|
|
|
|
p3 = new Point(-100.0 / 8, 100.0 / 6);
|
|
tri = new Triangle(p1, p2, p3);
|
|
test(tri, pt);
|
|
}
|
|
}
|