Java examples for java.lang:Math Geometry Line
Find the intersections between a polygon and a straight line.
public class Main{ /**// w ww . j ava 2s . c om * Find the intersections between a polygon and a straight line. * * NOTE: This method is only guaranteed to work if the polygon is first * preprocessed so that "unneccesary" vertices are removed (i.e vertices on * the straight line between its neighbours). * * @param x X coordinates of polygon. * @param y Y coordinates of polygon. * @param x0 X first end point of line. * @param x0 Y first end point of line. * @param x0 X second end point of line. * @param x0 Y second end point of line. * @return Intersections [x,y,x,y...]. */ public static double[] findLinePolygonIntersections(double[] x, double[] y, double x0, double y0, double x1, double y1) { double x2, y2, x3, y3; double xi, yi; int nPoints = x.length; int nIntersections = 0; double[] intersections = new double[24]; // Result vector x,y,x,y,... double[] intersection = new double[2]; // Any given intersection x,y for (int i = 0; i < nPoints; i++) { int next = i == nPoints - 1 ? 0 : i + 1; // The line segment of the polyline to check x2 = x[i]; y2 = y[i]; x3 = x[next]; y3 = y[next]; boolean isIntersecting = false; // Ignore segments of zero length if (GeometryUtils.equals(x2, x3) && GeometryUtils.equals(y2, y3)) { continue; } int type = GeometryUtils.findLineSegmentIntersection(x0, y0, x1, y1, x2, y2, x3, y3, intersection); if (type == -2) { // Overlapping int p1 = i == 0 ? nPoints - 1 : i - 1; int p2 = next == nPoints - 1 ? 0 : next + 1; int side = GeometryUtils.sameSide(x0, y0, x1, y1, x[p1], y[p1], x[p2], y[p2]); if (side < 0) { isIntersecting = true; } } else if (type == 1) { isIntersecting = true; } // Add the intersection point if (isIntersecting) { // Reallocate if necessary if (nIntersections << 1 == intersections.length) { double[] newArray = new double[nIntersections << 2]; System.arraycopy(intersections, 0, newArray, 0, intersections.length); intersections = newArray; } // Then add intersections[nIntersections << 1 + 0] = intersection[0]; intersections[nIntersections << 1 + 1] = intersection[1]; nIntersections++; } } if (nIntersections == 0) { return null; } // Reallocate result so array match number of intersections double[] finalArray = new double[nIntersections << 2]; System.arraycopy(intersections, 0, finalArray, 0, finalArray.length); return finalArray; } /** * Check if two double precision numbers are "equal", i.e. close enough to a * given limit. * * @param a First number to check * @param b Second number to check * @param limit The definition of "equal". * @return True if the twho numbers are "equal", false otherwise */ private static boolean equals(double a, double b, double limit) { return Math.abs(a - b) < limit; } /** * Check if two double precision numbers are "equal", i.e. close enough to a * prespecified limit. * * @param a First number to check * @param b Second number to check * @return True if the twho numbers are "equal", false otherwise */ private static boolean equals(double a, double b) { return equals(a, b, 1.0e-5); } /** * Compute the intersection between two line segments, or two lines of * infinite length. * * @param x0 X coordinate first end point first line segment. * @param y0 Y coordinate first end point first line segment. * @param x1 X coordinate second end point first line segment. * @param y1 Y coordinate second end point first line segment. * @param x2 X coordinate first end point second line segment. * @param y2 Y coordinate first end point second line segment. * @param x3 X coordinate second end point second line segment. * @param y3 Y coordinate second end point second line segment. * @param intersection[2] Preallocated by caller to double[2] * @return -1 if lines are parallel (x,y unset), -2 if lines are parallel * and overlapping (x, y center) 0 if intesrection outside segments (x,y * set) +1 if segments intersect (x,y set) */ public static int findLineSegmentIntersection(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double[] intersection) { // TODO: Make limit depend on input domain final double LIMIT = 1e-5; final double INFINITY = 1e10; double x, y; // // Convert the lines to the form y = ax + b // // Slope of the two lines double a0 = GeometryUtils.equals(x0, x1, LIMIT) ? INFINITY : (y0 - y1) / (x0 - x1); double a1 = GeometryUtils.equals(x2, x3, LIMIT) ? INFINITY : (y2 - y3) / (x2 - x3); double b0 = y0 - a0 * x0; double b1 = y2 - a1 * x2; // Check if lines are parallel if (GeometryUtils.equals(a0, a1)) { if (!GeometryUtils.equals(b0, b1)) { return -1; // Parallell non-overlapping } else { if (GeometryUtils.equals(x0, x1)) { if (Math.min(y0, y1) < Math.max(y2, y3) || Math.max(y0, y1) > Math.min(y2, y3)) { double twoMiddle = y0 + y1 + y2 + y3 - GeometryUtils.min(y0, y1, y2, y3) - GeometryUtils.max(y0, y1, y2, y3); y = (twoMiddle) / 2.0; x = (y - b0) / a0; } else { return -1; // Parallell non-overlapping } } else { if (Math.min(x0, x1) < Math.max(x2, x3) || Math.max(x0, x1) > Math.min(x2, x3)) { double twoMiddle = x0 + x1 + x2 + x3 - GeometryUtils.min(x0, x1, x2, x3) - GeometryUtils.max(x0, x1, x2, x3); x = (twoMiddle) / 2.0; y = a0 * x + b0; } else { return -1; } } intersection[0] = x; intersection[1] = y; return -2; } } // Find correct intersection point if (GeometryUtils.equals(a0, INFINITY)) { x = x0; y = a1 * x + b1; } else if (GeometryUtils.equals(a1, INFINITY)) { x = x2; y = a0 * x + b0; } else { x = -(b0 - b1) / (a0 - a1); y = a0 * x + b0; } intersection[0] = x; intersection[1] = y; // Then check if intersection is within line segments double distanceFrom1; if (GeometryUtils.equals(x0, x1)) { if (y0 < y1) { distanceFrom1 = y < y0 ? GeometryUtils.length(x, y, x0, y0) : y > y1 ? GeometryUtils.length(x, y, x1, y1) : 0.0; } else { distanceFrom1 = y < y1 ? GeometryUtils.length(x, y, x1, y1) : y > y0 ? GeometryUtils.length(x, y, x0, y0) : 0.0; } } else { if (x0 < x1) { distanceFrom1 = x < x0 ? GeometryUtils.length(x, y, x0, y0) : x > x1 ? GeometryUtils.length(x, y, x1, y1) : 0.0; } else { distanceFrom1 = x < x1 ? GeometryUtils.length(x, y, x1, y1) : x > x0 ? GeometryUtils.length(x, y, x0, y0) : 0.0; } } double distanceFrom2; if (GeometryUtils.equals(x2, x3)) { if (y2 < y3) { distanceFrom2 = y < y2 ? GeometryUtils.length(x, y, x2, y2) : y > y3 ? GeometryUtils.length(x, y, x3, y3) : 0.0; } else { distanceFrom2 = y < y3 ? GeometryUtils.length(x, y, x3, y3) : y > y2 ? GeometryUtils.length(x, y, x2, y2) : 0.0; } } else { if (x2 < x3) { distanceFrom2 = x < x2 ? GeometryUtils.length(x, y, x2, y2) : x > x3 ? GeometryUtils.length(x, y, x3, y3) : 0.0; } else { distanceFrom2 = x < x3 ? GeometryUtils.length(x, y, x3, y3) : x > x2 ? GeometryUtils.length(x, y, x2, y2) : 0.0; } } return GeometryUtils.equals(distanceFrom1, 0.0) && GeometryUtils.equals(distanceFrom2, 0.0) ? 1 : 0; } /** * Check if two points are on the same side of a given line. Algorithm from * Sedgewick page 350. * * @param x0, y0, x1, y1 The line. * @param px0, py0 First point. * @param px1, py1 Second point. * @return <0 if points on opposite sides. =0 if one of the points is * exactly on the line >0 if points on same side. */ private static int sameSide(double x0, double y0, double x1, double y1, double px0, double py0, double px1, double py1) { int sameSide = 0; double dx = x1 - x0; double dy = y1 - y0; double dx1 = px0 - x0; double dy1 = py0 - y0; double dx2 = px1 - x1; double dy2 = py1 - y1; // Cross product of the vector from the endpoint of the line to the point double c1 = dx * dy1 - dy * dx1; double c2 = dx * dy2 - dy * dx2; if (c1 != 0 && c2 != 0) { sameSide = c1 < 0 != c2 < 0 ? -1 : 1; } else if (dx == 0 && dx1 == 0 && dx2 == 0) { sameSide = !isBetween(y0, y1, py0) && !isBetween(y0, y1, py1) ? 1 : 0; } else if (dy == 0 && dy1 == 0 && dy2 == 0) { sameSide = !isBetween(x0, x1, px0) && !isBetween(x0, x1, px1) ? 1 : 0; } return sameSide; } /** * Check if two points are on the same side of a given line. Integer domain. * * @param x0, y0, x1, y1 The line. * @param px0, py0 First point. * @param px1, py1 Second point. * @return <0 if points on opposite sides. =0 if one of the points is * exactly on the line >0 if points on same side. */ private static int sameSide(int x0, int y0, int x1, int y1, int px0, int py0, int px1, int py1) { return sameSide((double) x0, (double) y0, (double) x1, (double) y1, (double) px0, (double) py0, (double) px1, (double) py1); } /** * Return smallest of four numbers. * * @param a First number to find smallest among. * @param b Second number to find smallest among. * @param c Third number to find smallest among. * @param d Fourth number to find smallest among. * @return Smallest of a, b, c and d. */ private static double min(double a, double b, double c, double d) { return Math.min(Math.min(a, b), Math.min(c, d)); } /** * Return largest of four numbers. * * @param a First number to find largest among. * @param b Second number to find largest among. * @param c Third number to find largest among. * @param d Fourth number to find largest among. * @return Largest of a, b, c and d. */ private static double max(double a, double b, double c, double d) { return Math.max(Math.max(a, b), Math.max(c, d)); } /** * Return the length of a vector. * * @param v Vector to compute length of [x,y,z]. * @return Length of vector. */ public static double length(double[] v) { return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } /** * Compute distance between two points. * * @param p0, p1 Points to compute distance between [x,y,z]. * @return Distance between points. */ public static double length(double[] p0, double[] p1) { double[] v = GeometryUtils.createVector(p0, p1); return length(v); } /** * Compute the length of the line from (x0,y0) to (x1,y1) * * @param x0, y0 First line end point. * @param x1, y1 Second line end point. * @return Length of line from (x0,y0) to (x1,y1). */ public static double length(int x0, int y0, int x1, int y1) { return GeometryUtils.length((double) x0, (double) y0, (double) x1, (double) y1); } /** * Compute the length of the line from (x0,y0) to (x1,y1) * * @param x0, y0 First line end point. * @param x1, y1 Second line end point. * @return Length of line from (x0,y0) to (x1,y1). */ public static double length(double x0, double y0, double x1, double y1) { double dx = x1 - x0; double dy = y1 - y0; return Math.sqrt(dx * dx + dy * dy); } /** * Compute the length of a polyline. * * @param x, y Arrays of x,y coordinates * @param nPoints Number of elements in the above. * @param isClosed True if this is a closed polygon, false otherwise * @return Length of polyline defined by x, y and nPoints. */ public static double length(int[] x, int[] y, boolean isClosed) { double length = 0.0; int nPoints = x.length; for (int i = 0; i < nPoints - 1; i++) { length += GeometryUtils.length(x[i], y[i], x[i + 1], y[i + 1]); } // Add last leg if this is a polygon if (isClosed && nPoints > 1) { length += GeometryUtils.length(x[nPoints - 1], y[nPoints - 1], x[0], y[0]); } return length; } /** * Return true if c is between a and b. */ private static boolean isBetween(int a, int b, int c) { return b > a ? c >= a && c <= b : c >= b && c <= a; } /** * Return true if c is between a and b. */ private static boolean isBetween(double a, double b, double c) { return b > a ? c >= a && c <= b : c >= b && c <= a; } /** * Construct the vector specified by two points. * * @param p0, p1 Points the construct vector between [x,y,z]. * @return v Vector from p0 to p1 [x,y,z]. */ public static double[] createVector(double[] p0, double[] p1) { double v[] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] }; return v; } }