package com.baselet.control.basics.geom; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class GeometricFunctions { public static double distanceBetweenTwoPoints(PointDouble p1, PointDouble p2) { return GeometricFunctions.distanceBetweenTwoPoints(p1.x, p1.y, p2.x, p2.y); } public static double getDistanceBetweenLineAndPoint(PointDouble start, PointDouble end, PointDouble pointToCheck) { return getDistanceBetweenLineAndPoint(start.x, start.y, end.x, end.y, pointToCheck.x, pointToCheck.y); } private static double distanceBetweenTwoPoints(double x1, double y1, double x2, double y2) { double xDist = x1 - x2; double yDist = y1 - y2; return Math.sqrt(xDist * xDist + yDist * yDist); } /** * implementation is based on http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment/2233538#2233538 */ private static double getDistanceBetweenLineAndPoint(double x1, double y1, double x2, double y2, double checkX, double checkY) { double px = x2 - x1; double py = y2 - y1; double mult = px * px + py * py; double u = ((checkX - x1) * px + (checkY - y1) * py) / mult; if (u > 1) { u = 1; } else if (u < 0) { u = 0; } double x = x1 + u * px; double y = y1 + u * py; return GeometricFunctions.distanceBetweenTwoPoints(x, y, checkX, checkY); } /** * for math information see http://www.mathisfunforum.com/viewtopic.php?id=9657 */ public static PointDouble getPointOnLineWithDistanceFromStart(PointDouble start, PointDouble end, double distance) { double xDiff = end.getX() - start.getX(); double yDiff = end.getY() - start.getY(); double length = distanceBetweenTwoPoints(start, end); double distanceToGo = distance / length; return new PointDouble(start.getX() + xDiff * distanceToGo, start.getY() + yDiff * distanceToGo); } /** * from https://stackoverflow.com/questions/15594424/line-crosses-rectangle-how-to-find-the-cross-points/15594751#15594751 */ public static PointDouble getIntersectionPoint(Line lineA, Line lineB) { double x1 = lineA.getStart().getX(); double y1 = lineA.getStart().getY(); double x2 = lineA.getEnd().getX(); double y2 = lineA.getEnd().getY(); double x3 = lineB.getStart().getX(); double y3 = lineB.getStart().getY(); double x4 = lineB.getEnd().getX(); double y4 = lineB.getEnd().getY(); PointDouble p = null; double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); if (d != 0) { double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d; double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d; p = new PointDouble(xi, yi); // remove intersections which are not on the line (use 1 instead of 0 distance for tolerance) if (lineA.getDistanceToPoint(p) > 1 || lineB.getDistanceToPoint(p) > 1) { p = null; } } return p; } public static List<PointDouble> getIntersectionPoints(Line line, Rectangle rectangle) { List<PointDouble> list = Arrays.asList( // TOP getIntersectionPoint(line, new Line(new PointDouble(rectangle.getX(), rectangle.getY()), new PointDouble(rectangle.getX() + rectangle.getWidth(), rectangle.getY()))), // BOTTOM getIntersectionPoint(line, new Line(new PointDouble(rectangle.getX(), rectangle.getY() + rectangle.getHeight()), new PointDouble(rectangle.getX() + rectangle.getWidth(), rectangle.getY() + rectangle.getHeight()))), // LEFT getIntersectionPoint(line, new Line(new PointDouble(rectangle.getX(), rectangle.getY()), new PointDouble(rectangle.getX(), rectangle.getY() + rectangle.getHeight()))), // RIGHT getIntersectionPoint(line, new Line(new PointDouble(rectangle.getX() + rectangle.getWidth(), rectangle.getY()), new PointDouble(rectangle.getX() + rectangle.getWidth(), rectangle.getY() + rectangle.getHeight())))); // remove nulls List<PointDouble> returnList = new ArrayList<PointDouble>(); for (PointDouble p : list) { if (p != null) { returnList.add(p); } } return returnList; } }