Java-正确的直线相交检查
我需要确定两条直线段是否相交,但使用line2D.linesIntersect方法存在问题。即使这些行只共享一个端点,该方法也会返回一个真正的结果,如下所示:Java-正确的直线相交检查,java,line,point,Java,Line,Point,我需要确定两条直线段是否相交,但使用line2D.linesIntersect方法存在问题。即使这些行只共享一个端点,该方法也会返回一个真正的结果,如下所示: 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.linesInterse
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.");
}
在这种情况下,我将始终收到“lines share a endpoint”消息。当然,在某些直线共享端点的情况下,它们可能会无限多次相交((0,0)到(0,1)被(0,0)到(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)函数,它确定一个点是否位于直线上(由另外两个点组成)
试试看,让我知道结果 如果不局限于Point2D和Line2D对象,则可以使用(Java拓扑套件)
- 将线创建为线字符串对象
- 使用该方法
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);
我在网络上找到了一个解决方案,并对其进行了调整和手动测试。 它是自包含的,只需导入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;
}
/**
*测试第一个点是否位于由其他两个点表示的边界框中
*要点。
*/
公共静态布尔值介于之间(点2D测试、点2D p1、点2D p2){
返回isBetween(pToTest.getX(),pToTest.getY(),p1.getX(),p1.getY(),p2.getX(),p2.getY());
}
/**
*通过这些点调用{@link#isBetween(Point2D,Point2D,Point2D)}
*坐标。
*/
公共静态布尔值isBetween(双pxToTest、双pyToTest、双px1、双py1、双px2、双py2){
双w,h;
//从矩形的课程中获得灵感
w=px1-px2;
if(w<0)
w=-w;
h=py1-py2;
if(h<0)
h=-h;
//使用p1作为矩形的左上角
//(左上角视为原点(0;0))
如果(px1>px2)
px1=px2//
如果(py1>py2)
py1=py2//
if(pxToTestpxToTest)和&(hpyToTest));
}
公共静态双斜率(双xa、双ya、双xb、双yb){
如果(xb==xa)
返回双正无穷大;
收益率(yb==ya)?0.0:((yb-ya)/(xb-xa));
}
/**
*由{@link#areLinesIntersecting(Point2D,Point2D,Point2D,Point2D)调用
*通过提供每个点的坐标。
*/
公共静态点2D是线性插入检测(双pxStart1、双pyStart1、双pxEnd1、双pyEnd1、,
双pxStart2,双pyStart2,双pxEnd2,双pyEnd2){
双斜率ab,斜率cd,分子,分母,q_ab,q_cd,x,y;
点2dp;
斜率=斜率(pxStart1,pyStart1,pxEnd1,pyEnd1);
斜率=斜率(pxStart2,pyStart2,pxEnd2,pyEnd2);
q_ab=(pyStart1-斜率_ab*pxStart1);
q_cd=(pyStart2-斜率_cd*pxStart2);
如果((斜率=slope\u ab==slope\u cd)//平行?
&& (
//重叠?
(斜率| ab==Double.POSITIVE |斜率| ab==Double.NaN)和&pxStart1==pxStart2)//
|| //
//重叠?
(斜率=0.0&&pyStart1==pyStart2)//
|| //
//如果线的不同共有部分,则平行但不重叠
(q_ab==q_cd)//
)) {
if(isBetween(pxStart2、pyStart2、pxStart1、pyStart1、pxEnd1、pyEnd1))
返回新的点2d.Double(pxStart2,pyStart2);
if(isBetween(pxEnd2,pyEnd2,pxStart1,pyStart1,pxEnd1,pyEnd1))
返回新的点2d.Double(pxEnd2,pyEnd2);
if(isBetween(pxStart1、pyStart1、pxStart2、pyStart2、pxEnd2、pyEnd2))
返回新的点2d.Double(pxStart1,pyStart1);
if(isBetween(pxEnd1,pyEnd1,pxStart2,pyStart2,pxEnd2,pyEnd2))
返回新的点2d.Double(pxEnd1,pyEnd1);
}
if(斜率=双正无穷大){
//ab垂直线:所有a&b的x-E相等
x=pxStart1;
y=(q_cd+(斜率_cd*x));
//这是一个十字架
if((pyStart1 pyEnd1)
//这一点是相反的
:(y>pyStart1 | | y 如果((pxStart2/**
* 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;
}