Compute the intersection between two line segments, or two lines of infinite length. - Java java.lang

Java examples for java.lang:Math Geometry Line

Description

Compute the intersection between two line segments, or two lines of infinite length.

Demo Code



public class Main{
    /**/* w w  w.j a  v a 2 s  . co m*/
     * 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 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);
    }
    /**
     * 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;
    }
    /**
     * 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;
    }
}

Related Tutorials