计算几何中最基本重要的算法之一~判断线段相交基础。
只需判断线段是否同时满足
1.快速排斥实验:
设以线段P1P2为对角线的矩形为T,以Q1Q2线段为对角线的矩形为R,那么下图这种状态时P1P2和Q1Q2肯定不相交
判断P1 P2 Q1 Q2是否满足这种关系就是快速排斥实验。
max(p1.x,p2.x) < min(q1.x,q2,x) || max(q1.x,q2.x) < min(p1,x,p2,x) ||max(p1.y,p2.y) < min(q1.y,q2,y) || max(q1.y,q2.y) < min(p1.y,p2.y)
上式为真,则表明两个矩形不想交,一般是取上式的否定,直接判断是否满足矩形相交,即。
min(p1.x,p2.x) <= max(q1.x,q2,x) && min(q1.x,q2.x) <= max(p1,x,p2,x) &&min(p1.y,p2.y) <= max(q1.y,q2,y) && min(q1.y,q2.y) <= max(p1.y,p2.y)
2.跨立实验
前提:如果两线段相交,必定互相跨立。
也即是说:
1.P1 P2 在Q1Q2的两侧
2.Q1Q2 在P1P2的两侧
判断两点是否在一条直线的两侧就用到叉乘了。
(Q1P1 x Q1Q2) * (Q1Q2 x Q1P2) <= 0 表示P1P2在Q1Q2的两侧
(P1Q2 x P1P2) * (P1P2 x P1Q2) <= 0 表示Q1Q2在P1P2的两侧
这就满足跨立实验的要求了~
小试一下:HDU 1086 http://acm.hdu.edu.cn/showproblem.php?pid=1086
#include<cstdio> #include<cstdlib> //注意题目说了线段与线段之间最多只有一个交点,不存在重合或者在一条直线的情况 struct line{ double x1,y1; double x2,y2; }; long Judge(struct line Line1,struct line Line2)//跨立实验 { double Xa1 = Line1.x1; double Ya1 = Line1.y1; double Xa2 = Line1.x2; double Ya2 = Line1.y2; double Xb1 = Line2.x1; double Yb1 = Line2.y1; double Xb2 = Line2.x2; double Yb2 = Line2.y2; if(((Xa2-Xa1)*(Yb1-Ya1)-(Xb1-Xa1)*(Ya2-Ya1))*((Xa2-Xa1)*(Yb2-Ya1)-(Xb2-Xa1)*(Ya2-Ya1))>0) return 0; if(((Xb2-Xb1)*(Ya1-Yb1)-(Xa1-Xb1)*(Yb2-Yb1))*((Xb2-Xb1)*(Ya2-Yb1)-(Xa2-Xb1)*(Yb2-Yb1))>0) return 0; return 1; } int main() { struct line Line[100]; int num; while(scanf("%d",&num) != EOF && num) { int count = 0; for(int i = 0 ; i < num ; ++i) scanf("%lf%lf%lf%lf",&Line[i].x1,&Line[i].y1,&Line[i].x2,&Line[i].y2); for(int i = 0 ; i < num - 1 ; ++i) for(int j = i + 1 ; j < num ; ++j) if(Judge(Line[i],Line[j])) count++; printf("%d\n",count); } return 0; }