Java - 正确的行交叉检查

时间:2014-04-21 07:05:05

标签: java line point

我需要确定两个线段是否相交,但是使用line2D.linesIntersect方法存在问题。即使行仅共享端点,该方法也会返回true结果,如下所示:

Point2D.Double temp1 = new Point2D.Double(0, 0);
Point2D.Double temp2 = new Point2D.Double(0, 1);
Point2D.Double temp3 = new Point2D.Double(1, 0);

if(Line2D.linesIntersect(temp1.x, temp1.y, temp2.x, temp2.y, temp1.x, temp1.y, temp3.x, temp3.y){
    System.out.println("Lines share an endpoint.");
}
else{
    System.out.println("Lines don't intersect.");
}

在这种情况下,我总是让"线共享一个端点"信息。当然,在线路共享端点的某些情况下,它们可能无限次交叉多次((0,0)到(0,1)与(0,0)到(0,2)相交) ,这显然应该返回一个真实的结果。但是,在仅共享端点且没有其他交叉点发生的其他情况下,程序无法正常工作。有什么方法可以防止这个问题吗?

3 个答案:

答案 0 :(得分:2)

这是我可以用我的基础数学知识得出的答案。希望它能帮到你。给定4个点,它会告诉您两条线(来自这四个点)是否相交,共享一个终点或两者都没有。

        //starting point of line 1
        Point2D.Double temp1 = new Point2D.Double(0 , 1);
        //ending point of line 1
        Point2D.Double temp2 = new Point2D.Double(0, -1);
        //starting point of line 2
        Point2D.Double temp3 = new Point2D.Double(-1, 0);
        //ending point of line 2
        Point2D.Double temp4 = new Point2D.Double(1, 0);

        //determine if the lines intersect
        boolean intersects = Line2D.linesIntersect(temp1.x, temp1.y, temp2.x, temp2.y, temp3.x, temp3.y, temp4.x, temp4.y);

        //determines if the lines share an endpoint
        boolean shareAnyPoint = shareAnyPoint(temp1, temp2, temp3, temp4);

        if (intersects && shareAnyPoint) {
            System.out.println("Lines share an endpoint.");
        } else if (intersects && !shareAnyPoint) {
            System.out.println("Lines intersect.");
        } else {
            System.out.println("Lines neither intersect nor share a share an endpoint.");
        }

这是shareAnyPoint( StartPointA EndPointA StartPointB EndPointB )功能,用于检查是否启动/任何一条线的终点位于另一条线上。

public static boolean shareAnyPoint(Point2D.Double A, Point2D.Double B, Point2D.Double C, Point2D.Double D) {
    if (isPointOnTheLine(A, B, C)) return true;
    else if (isPointOnTheLine(A, B, D)) return true;
    else if (isPointOnTheLine(C, D, A)) return true;
    else if (isPointOnTheLine(C, D, B)) return true;
    else return false;
}

以下是isPointOnTheLine( StartPoint EndPoint MyPoint )函数,用于确定某个点是否在线(由其他2个制作)分)

public static boolean isPointOnTheLine(Point2D.Double A, Point2D.Double B, Point2D.Double P) {  
    double m = (B.y - A.y) / (B.x - A.x);

    //handle special case where the line is vertical
    if (Double.isInfinite(m)) {
        if(A.x == P.x) return true;
        else return false;
    }

    if ((P.y - A.y) == m * (P.x - A.x)) return true;
    else return false;
}

尝试一下,让我知道结果。

答案 1 :(得分:0)

如果您不受限于 Point2D Line2D 对象,则可以使用JTS(Java拓扑套件)。

  • 将您的行创建为LineString对象
  • 使用intersects方法

简单的代码示例:

LineString lineA = new GeometryFactory().createLineString(new Coordinate[]{new Coordinate(0, 0), new Coordinate(0, 10)});
LineString lineB = new GeometryFactory().createLineString(new Coordinate[]{new Coordinate(-5,5), new Coordinate(5,5)});
boolean intersect = lineA.intersects(lineB);

答案 2 :(得分:0)

我在网上找到了一个解决方案,并对其进行了修改,并进行了手动测试。 它是独立的,只需导入java.awt.geom.Point2D

/**
 * Test if the first point lies in the bounding box denote by the other two
 * points.
 */
public static boolean isBetween(Point2D pToTest, Point2D p1, Point2D p2) {
    return isBetween(pToTest.getX(), pToTest.getY(), p1.getX(), p1.getY(), p2.getX(), p2.getY());
}

/**
 * Called {@link #isBetween(Point2D, Point2D, Point2D)} passing those points
 * coordinates.
 */
public static boolean isBetween(double pxToTest, double pyToTest, double px1, double py1, double px2, double py2) {
    double w, h;
    // taking inspiration from Rectangle's class
    w = px1 - px2;
    if (w < 0)
        w = -w;
    h = py1 - py2;
    if (h < 0)
        h = -h;
    // use p1 as the left-top corner of the rectangle
    // (the left-top corner is considered as the origin (0;0))
    if (px1 > px2)
        px1 = px2;//
    if (py1 > py2)
        py1 = py2;//
    if (pxToTest < px1 || pyToTest < py1) {
        return false;
    }
    w += px1;
    h += py1;
    // overflow || intersect
    return ((w < px1 || w > pxToTest) && (h < py1 || h > pyToTest));
}

public static double slope(double xa, double ya, double xb, double yb) {
    if (xb == xa)
        return Double.POSITIVE_INFINITY;
    return (yb == ya) ? 0.0 : ((yb - ya) / (xb - xa));
}

/**
 * Called by {@link #areLinesIntersecting(Point2D, Point2D, Point2D, Point2D)}
 * by providing each of those point's coordinates.
 */
public static Point2D areLinesIntersecting(double pxStart1, double pyStart1, double pxEnd1, double pyEnd1,
        double pxStart2, double pyStart2, double pxEnd2, double pyEnd2) {
    double slope_ab, slope_cd, numerator, denominator, q_ab, q_cd, x, y;
    Point2D p;
    slope_ab = slope(pxStart1, pyStart1, pxEnd1, pyEnd1);
    slope_cd = slope(pxStart2, pyStart2, pxEnd2, pyEnd2);
    q_ab = (pyStart1 - slope_ab * pxStart1);
    q_cd = (pyStart2 - slope_cd * pxStart2);
    if ((slope_ab == slope_cd) // parallel?
            && (
            // overlapping?
            ((slope_ab == Double.POSITIVE_INFINITY || slope_ab == Double.NaN) && pxStart1 == pxStart2) //
                    || //
                        // overlapping?
                    (slope_ab == 0.0 && pyStart1 == pyStart2) //
                    || //
                        // if different costant parts of lines, then parallel BUT not overlapping
                    (q_ab == q_cd)//
            )) {
        if (isBetween(pxStart2, pyStart2, pxStart1, pyStart1, pxEnd1, pyEnd1))
            return new Point2D.Double(pxStart2, pyStart2);
        if (isBetween(pxEnd2, pyEnd2, pxStart1, pyStart1, pxEnd1, pyEnd1))
            return new Point2D.Double(pxEnd2, pyEnd2);
        if (isBetween(pxStart1, pyStart1, pxStart2, pyStart2, pxEnd2, pyEnd2))
            return new Point2D.Double(pxStart1, pyStart1);
        if (isBetween(pxEnd1, pyEnd1, pxStart2, pyStart2, pxEnd2, pyEnd2))
            return new Point2D.Double(pxEnd1, pyEnd1);
    }
    if (slope_ab == Double.POSITIVE_INFINITY) {
        // ab vertical line: all a&b's x-es are equals
        x = pxStart1;
        y = (q_cd + (slope_cd * x));
        // it's a cross
        if ((pyStart1 <= pyEnd1) ? (y < pyStart1 || y > pyEnd1)
                // point are reversed
                : (y > pyStart1 || y < pyEnd1))
            return null;
        if ((pxStart2 < pxEnd2) ? (pxStart2 <= x && x <= pxEnd2)//
                : (pxEnd2 <= x && x <= pxStart2))
            return new Point2D.Double(x, y);
        else
            return null;
    }
    if (slope_cd == Double.POSITIVE_INFINITY) {
        // cd vertical line: all c&d's x-es are equals
        x = pxStart2;
        y = (q_ab + (slope_ab * x));
        // it's a cross
        if ((pyStart2 <= pyEnd2) ? (y < pyStart2 || y > pyEnd2)
                // point are reversed
                : (y > pyStart2 || y < pyEnd2))
            return null;
        // if the y lies inside the line a-b, then intersection
        if ((pxStart1 < pxEnd1) ? (pxStart1 <= x && x <= pxEnd1)//
                : (pxEnd1 <= x && x <= pxStart1))
            return new Point2D.Double(x, y);
        else
            return null;

    }
    // slopes cannot be infinity
    if (slope_ab == 0.0) {
        y = pyStart1;
        // slope_cd cannot be Infinity (second group of checks) and zero (first ones)
        x = (y - q_cd) / slope_cd;

        if ((pxStart1 <= pxEnd1) ? (x < pxStart1 || x > pxEnd1)
                // point are reversed
                : (x > pxStart1 || x < pxEnd1))
            return null;
        if ((pxStart2 <= pxEnd2) ? (x < pxStart2 || x > pxEnd2)
                // point are reversed
                : (x > pxStart2 || x < pxEnd2))
            return null;
        if ((pyStart2 < pyEnd2) ? (pyStart2 <= y && y <= pyEnd2)//
                : (pyEnd2 <= y && y <= pyStart2))
            return new Point2D.Double(x, y);
        else
            return null;
    }
    if (slope_cd == 0.0) {
        y = pyStart2;
        // slope_ab cannot be Infinity (second group of checks) and zero (first ones)
        x = (y - q_ab) / slope_ab;

        if ((pxStart2 <= pxEnd2) ? (x < pxStart2 || x > pxEnd2)
                // point are reversed
                : (x > pxStart2 || x < pxEnd2))
            return null;

        if ((pxStart1 <= pxEnd1) ? (x < pxStart1 || x > pxEnd1)
                // point are reversed
                : (x > pxStart1 || x < pxEnd1))
            return null;
        if ((pyStart1 < pyEnd1) ? (pyStart1 <= y && y <= pyEnd1)//
                : (pyEnd1 <= y && y <= pyStart1))
            return new Point2D.Double(x, y);
        else
            return null;
    }
    denominator = slope_cd - slope_ab;
    numerator = q_ab - q_cd;
    x = (numerator / denominator);
    y = (q_ab + (slope_ab * x));
    p = new Point2D.Double(x, y);
    if (isBetween(p.getX(), p.getY(), pxStart1, pyStart1, pxEnd1, pyEnd1)
            && isBetween(p.getX(), p.getY(), pxStart2, pyStart2, pxEnd2, pyEnd2))
        return p;
    y = (q_cd + (slope_cd * x));
    p = new Point2D.Double(x, y);
    if ((isBetween(p.getX(), p.getY(), pxStart1, pyStart1, pxEnd1, pyEnd1)
            && isBetween(p.getX(), p.getY(), pxStart2, pyStart2, pxEnd2, pyEnd2)))
        return p;

    return null;
}