线段相交——两个步骤:1、快速排斥。 2、跨立实验。
快速排斥:先最大限度的将buke不可能相交的情况给排除,例如 线段 : a——b 线段 :c——d 。(线段的表示都是点)
如果线段ab两点最大的坐标 x 的值都没有线段cd最小的x值大,这就可以确定 这两条线段肯定不相交。
总共有四种情况 线段ab的坐标x,坐标y,线段cd的坐标x坐标y。
if(min(a.y,b.y)>max(c.y,d.y) ||
max(a.x,b.x)<min(c.x,d.x) ||
min(c.y,d.y)>max(a.y,b.y) ||
max(c.x,d.x)<min(a.x,b.x) ) //当满足这四种情况那线段肯定不相交
return false;
跨立实验:线段ab与线段cd相交的话,那么肯定会有 a、b 两点在线段cd的两侧,同理 cd也是 这时就需要判断线段ac、dc的叉积乘上 线段 bc、dc 的叉积的值是否小于0 如果小于0 代表在其两侧。则相交
//跨立实验
double u = (a.x-c.x)*(d.y-c.y)-(a.y-c.y)*(d.x-c.x);
double v = (b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);
double w = (c.x-b.x)*(a.y-b.y)-(a.x-b.x)*(c.y-b.y);
double z = (d.x-b.x)*(a.y-b.y)-(a.x-b.x)*(d.y-b.y);
if(u*v<=0.0000001 && w*z<=0.0000001)
return true;
全部代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
struct node {
double x,y;
};
struct edge {
node a,b;
} e[100];
int judge(edge xx,edge yy) {
node a = xx.a;
node b = xx.b;
node c = yy.a;
node d = yy.b;
//快速排斥
if(min(a.y,b.y)>max(c.y,d.y)|| max(a.x,b.x)<min(c.x,d.x) || min(c.y,d.y)>max(a.y,b.y) || max(c.x,d.x)<min(a.x,b.x))
return false;
//跨立实验
double u = (a.x-c.x)*(d.y-c.y)-(a.y-c.y)*(d.x-c.x);
double v = (b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);
double w = (c.x-b.x)*(a.y-b.y)-(a.x-b.x)*(c.y-b.y);
double z = (d.x-b.x)*(a.y-b.y)-(a.x-b.x)*(d.y-b.y);
if(u*v<=0.0000001 && w*z<=0.0000001)
return true;
}
int main() {
scanf("%d",&n);
for(int i=0; i<n; i++) {
scanf("%lf%lf%lf%lf",&e[i].a.x,&e[i].a.y,&e[i].b.x,&e[i].b.y);
}
int res=0;
for(int i=0; i<n; i++) {
for(int j=i+1; j<n; j++) {
if(judge(e[i],e[j]))
res++;
}
}
printf("%d\n",res);
return 0;
}