原理:
我们分两步确定两条线段是否相交:
(1).快速排斥试验
设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交;
(2).跨立试验
如果两线段相交,则两线段必然相互跨立对方,P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即
( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0
上式可改写成
( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0
当( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;
同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。
所以判断P1P2跨立Q1Q2的依据是:
( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) ≥ 0
同理判断Q1Q2跨立P1P2的依据是:
( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) ≥ 0
Code:
#include<stdio.h> #include<math.h> #define N 4 typedef struct { int x; int y; }node; int max(int x,int y) { return x>y?x:y; } int min(int x,int y) { return x<y?x:y; } int fun(node a,node b,node c,node d) { node p[3]; int flag,m,n; p[0].x=b.x-a.x; p[0].y=b.y-a.y; p[1].x=c.x-a.x; p[1].y=c.y-a.y; p[2].x=d.x-a.x; p[2].y=d.y-a.y; m=(p[0].x*p[1].y-p[0].y*p[1].x); n=(p[0].x*p[2].y-p[0].y*p[2].x); if((m%1000)!=0) m=m%1000; else { while(fabs(m/10)>10) m=m/10; } if((n%1000)!=0) n=n%1000; else { while(fabs(n/10)>10) n=n/10; } if(n*m<0) flag=1; else if(m*n==0) { if((c.x>=min(a.x,b.x)&&c.x<=max(a.x,b.x))&&(c.y>=min(a.y,b.y)&&c.y<=max(a.y,b.y))||(d.x>=min(a.x,b.x)&&d.x<=max(a.x,b.x))&&(d.y>=min(a.y,b.y)&&d.y<=max(a.y,b.y))) flag=0; else flag=-1; } else flag=-1; return flag; } int main() { int n; while(scanf("%d",&n)!=EOF) { int i; for(i=0;i<n;i++) { int i,flag1,flag2; node p[N]; for(i=0;i<N;i++) scanf("%ld%ld",&p[i].x,&p[i].y); flag1=fun(p[0],p[1],p[2],p[3]); flag2=fun(p[2],p[3],p[0],p[1]); if((flag1==1&&flag2==1)||flag1==0||flag2==0||(flag1==0&&flag2==0)) printf("intersect\n"); else printf("disjoint\n"); } } return 0; }