Determines the intersection of two line segments, if one exists. - Java 2D Graphics

Java examples for 2D Graphics:Line

Description

Determines the intersection of two line segments, if one exists.

Demo Code



public class Main{
    /**//from  ww  w  .ja v a 2  s . c o  m
     * Determines the intersection of two line segments, if one exists.
     * 
     * @param x11 The first x coord of line 1
     * @param y11 The first y coord of line 1
     * @param x12 The second x coord of line 1
     * @param y12 The second y coord of line 1
     * @param x21 The first x coord of line 2
     * @param y21 The first y coord of line 2
     * @param x22 The second x coord of line 2
     * @param y22 The second y coord of line 2
     * @return The intersection of two lines, if it exists
     */
    public static double[] findLineSegmentIntersection(double s1x1,
            double s1y1, double s1x2, double s1y2, double s2x1,
            double s2y1, double s2x2, double s2y2) {
        double[] point = findIntersectionOfTwoLines(s1x1, s1y1, s1x2, s1y2,
                s2x1, s2y1, s2x2, s2y2);
        point = nullIfOutOfBounds(point, s2x1, s2y1, s2x2, s2y2);
        return nullIfOutOfBounds(point, s1x1, s1y1, s1x2, s1y2);
    }
    public static double[] findIntersectionOfTwoLines(double l1x1,
            double l1y1, double l1x2, double l1y2, double l2x1,
            double l2y1, double l2x2, double l2y2) {
        // Cheating check to make sure the lines do not connect up end to end
        // This is required because such delicate intersections can be fucked by cumulative floating point error
        if (l1x1 == l2x1 && l1y1 == l2y1) {
            return new double[] { l1x1, l1y1 };
        }
        if (l1x1 == l2x2 && l1y1 == l2y2) {
            return new double[] { l1x1, l1y1 };
        }
        if (l1x2 == l2x1 && l1y2 == l2y1) {
            return new double[] { l1x2, l1y2 };
        }
        if (l1x2 == l2x2 && l1y2 == l2y2) {
            return new double[] { l1x2, l1y2 };
        }
        if (l1x1 == l1x2 && l1y1 > l1y2) {// The first line is pointing up
            if (l2x1 == l2x2) { // The second line is vertical
                return new double[] { l1x1, Math.max(l2y1, l2y2) };
            } else {
                double intersectY = solveForY(l2x1, l2y1, l2x2, l2y2, l1x1);
                return new double[] { l1x1, intersectY };
            }
        }
        if (l1x1 == l1x2 && l1y1 < l1y2) { // The first line is pointing straight down
            if (l2x1 == l2x2) { // The second line is vertical
                return new double[] { l1x1, Math.min(l2y1, l2y2) };
            } else {
                double intersectY = solveForY(l2x1, l2y1, l2x2, l2y2, l1x1);
                return new double[] { l1x1, intersectY };
            }
        }
        if (l2x1 == l2x2) { // The second line is vertical
            double yIntersect = solveForY(l1x1, l1y1, l1x2, l1y2, l2x1);
            return new double[] { l2x1, yIntersect };
        }
        // Here we solve the simultaneous equation to get the intersection
        double[] firstLine = TrigUtil.getLineEquation(l1x1, l1y1, l1x2,
                l1y2);
        double[] secondLine = TrigUtil.getLineEquation(l2x1, l2y1, l2x2,
                l2y2);
        double coefficient1 = firstLine[0];
        double shift1 = firstLine[1];
        double coefficient2 = secondLine[0];
        double shift2 = secondLine[1];
        double xIntersect = (shift1 - shift2)
                / (coefficient2 - coefficient1);
        double yIntersect = solveForY(l2x1, l2y1, l2x2, l2y2, xIntersect);

        return new double[] { xIntersect, yIntersect };
    }
    /**
     * Tests whether point lies within the x and y boundaries given.
     * 
     * @param point The point for bounds testing
     * @param bX1 The first x coord
     * @param bY1 The first y coord
     * @param bX2 The second x coord
     * @param bY2 The second y coord
     * @return point if point lies within the boundaries, null otherwise
     */
    private static double[] nullIfOutOfBounds(double[] point, double bX1,
            double bY1, double bX2, double bY2) {
        if (point != null && isBetween(point[0], bX1, bX2)
                && isBetween(point[1], bY1, bY2)) {
            return point;
        } else {
            return null;
        }
    }
    /**
     * Solves the equation of the line described by the point (x1,y1) and rotation for Y given
     * the value of x provided.
     * 
     * If the ray is not solvable for x, the Double.NaN is returned.  Since we are solving
     * for a ray and not a line there are some values of x which do not yield an y value.
     * 
     * @param rotation the rotation, in radians, clockwise from the pointing up position
     * @param x1 First x coordinate
     * @param y1 First y coordinate
     * @param x The value of x
     * @return The value of y for this line, given x or Double.Nan if there is no solution
     */
    public static double solveForY(double rotation, double x1, double y1,
            double x) {
        if (isBetween(rotation, 0, Math.PI) && x < x1) { // Facing right
            return Double.NaN;
        } else if (isBetween(rotation, Math.PI, Math.PI * 2) && x > x1) { // Facing left
            return Double.NaN;
        }
        double[] line = getLineEquation(rotation, x1, y1);
        double coefficient = line[0];
        double shift = line[1];
        return (coefficient * x) + shift;
    }
    /**
     * Solves the equation of the line described by the pair of points {(x1,y1),(x2,y2)} for Y given
     * the value of x provided.
     * 
     * @param x1 First x coordinate
     * @param y1 First y coordinate
     * @param x2 Second x coordinate
     * @param y2 Second y coordinate
     * @param x The value of x
     * @return The value of y for this line, given x
     */
    public static double solveForY(double x1, double y1, double x2,
            double y2, double x) {
        double[] line = getLineEquation(x1, y1, x2, y2);
        double coefficient = line[0];
        double shift = line[1];
        return (coefficient * x) + shift;
    }
    /**
     * Given two points {(x1,y1),(x2,y2)} returns {m,b} from the equation y = mx + b for a line
     * which passes through both points.
     * 
     * @param x1 First x coordinate
     * @param y1 First y coordinate
     * @param x2 Second x coordinate
     * @param y2 Second y coordinate
     * @return The slope and y intercept of the line passing through the points provided
     */
    public static double[] getLineEquation(double x1, double y1, double x2,
            double y2) {
        double coefficient = (y2 - y1) / (x2 - x1);
        double shift = -(coefficient * x1) + y1;
        return new double[] { coefficient, shift };
    }
    /**
     * Given a rotation (in radians) and a single point (x,y) returns {m,b} from the equation y = mx + b
     * for a line which passes through (x,y) and is oriented by rotation many radians clockwise from the
     * pointing straight up position.
     * 
     * @param rotation The rotated orientation of the line from the straight up position
     * @param x The x coordinate
     * @param y The y coordinate
     * @return The slope and y intercept of the line passing through the point provided with the provided rotation
     */
    public static double[] getLineEquation(double rotation, double x,
            double y) {
        double coefficient = -(Math.cos(rotation) / Math.sin(rotation));
        double shift = -(coefficient * x) + y;
        return new double[] { coefficient, shift };
    }
    /**
     * Indicates if the value x is between x1 and x2.
     * 
     * If x is NaN then I am currently assuming that it will never lie between any
     * two double values.  Surprisingly couldn't easily find a reference to how
     * weird double comparisons behave in Java :)
     * 
     * @param x The value for testing
     * @param x1 First boundary value
     * @param x2 Second boundary value
     * @return true if the x is between x1 and x2, false otherwise
     */
    public static boolean isBetween(double x, double x1, double x2) {
        if (x <= x1 && x >= x2) {
            return true;
        }
        if (x <= x2 && x >= x1) {
            return true;
        }
        return false;
    }
}

Related Tutorials