快速排斥:不能处理端点为交点的情况;
快速排斥原理:用给出的两条线段作为各自的对角线建立矩形,如果矩形不相交,那么线段一定不相交。
具体实现:假设第一条线段的两个端点分别为(p1,p2)(p3,p4);
if(
min(p1.x,p2.x) <= max(p3.x,p4.x)&&
min(p3.x,p4.x) <= max(p1.x,p2.x)&&
min(p1.y,p2.y) <= max(p3.y,p4.y)&&
min(p3.y,p4.y) <= max(p1.y,p2.y)
) return true;
else return false;
缺点:无法处理下图的情况
-----------------------------------------------------------------------------------------------
跨立实验:为了弥补快速排斥的不能处理端点的问题,跨立实验出现。
原理:如果两条线段相互跨过,那么任意一条直线的连个端点一定会出现在另一条线段的两侧,利用叉乘分别判断两条线段就可以了
叉乘: k = x1 * y2 – x2 * y1 ,
if(k>0) {x 在 y 的顺时针方向}
if(k<0){x 在 y 的逆时针方向}
判断跨越:
四个Point类 p1,p2与q1,q2;
如果满足:((p1-q1)×(q2-q1))*((q2-q1)×(p2-q1)) > 0 && ((q1-p1)×(p2-p1))*((p2-p1)×(q2-p1)) > 0
那么这两条线段就是相交的;
上面的式子前面一个是判断p1,p2是不是分布在q1,q2的两侧,第二个则是判断q1,q2是不是分布在p1,p2的两侧;
模板
int segcross(Point a, Point b, Point c, Point d, Point &p) //判断线段相交
{
double s1, s2, s3,s4;
int d1, d2, d3, d4;
d1=dblcmp(s1=xmult(a,b,c));
d2=dblcmp(s2=xmult(a,b,d));
d3=dblcmp(s3=xmult(c,d,a));
d4=dblcmp(s4=xmult(c,d,b));
//若规范相交则求交点的代码
//d1^d2==-2相当于d1*d2<0;
//跨立实验
if ((d1^d2)==-2 && (d3^d4)==-2) //"(d1^d2)"这个小括号是必须的,否则会错
{
p.x=(c.x*s2-d.x*s1)/(s2-s1);
p.y=(c.y*s2-d.y*s1)/(s2-s1);
return 1;
}
//判断非规范相交
//d1==0, 则证明a,b,c三点共线;
//如果dblcmp(dmult(c,a,b))<0, 则说明点c在点a,b的中间;
//如果dblcmp(dmult(c,a,b))==0,则说明点c与线段ab的端点a,或者b重合。
//如果dblcmp(dmult(c,a,b))==0,则说明点c在线段ab的外面。
if (d1==0 && dblcmp(dmult(c,a,b))<=0 ||
d2==0 && dblcmp(dmult(d,a,b))<=0 ||
d3==0 && dblcmp(dmult(a,c,d))<=0 ||
d4==0 && dblcmp(dmult(b,c,d))<=0)
{
return 2;
}
return 0;
}