重点掌握
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
typedef struct{
double x;
double y;
}Point;
typedef struct{
Point A,B;
}Line;
// 线段L与C的位置关系
// 返回值:>0即C在L的顺时针方向(下方);<0即C在L的逆时针方向(上方);=0同线
double PointLineLocation(Point &C, Line &L) {
double AB_x,AB_y; //矢量AB
double AC_x,AC_y; //矢量AC
AB_x=L.A.x-L.B.x; AB_y=L.A.y-L.B.y; //矢量A->B
AC_x=L.A.x-C.x; AC_y=L.A.y-C.y; //矢量A->C
return AB_x*AC_y-AB_y*AB_x; //矢量AB、AC叉乘
}
int Intersection(Line &L1, Line &L2) { //L1和L2是否相交
//快速排斥
if ( max(L1.A.x, L1.B.x)<min(L2.A.x, L2.B.x) ) return 0;
if ( max(L1.A.y, L1.B.y)<min(L2.A.y, L2.A.y) ) return 0;
if ( max(L2.A.x, L2.B.x)<min(L1.A.x, L1.A.x) ) return 0;
if ( max(L2.A.y, L2.B.y)<min(L1.A.y, L1.A.y) ) return 0;
//跨立实验
if ( PointLineLocation(L1.A, L2)*PointLineLocation(L1.B, L2)>0 ) //L1的两端点都在L2的同侧
return 0;
if ( PointLineLocation(L2.A, L1)*PointLineLocation(L2.B, L1)>0 ) //L2的两端点都在L1的同侧
return 0;
return 1; //相交
}
线段AB、线段CD是否相交
【定义】线段的参数方程:
【推算】Ax,Ay表示A的横坐标、纵坐标
如果AB、CD相交 => A+r(B-A)=C+s(D-c) => Ax+r(Bx-Ax)=Cx+s(Dx-Cx),Ay+r(By-Ay)=Cy+s(Dy-Cy), r、s∈[0,1] => 解方程,得到r,s
【判断方法】设P为AB、CD的交点 => P=A+r(B-A) => Px=Ax+r(Bx-Ax),Py=Ay+r(By-Ay)
bool IsIntersection(Point a,Point b,Point c,Point d) {
//AB = A + r(B-A), r 在[0,1]
//CD = C + t(D-C),s 在[0,1]
double r, s;
double deno = (b.X - a.X) * (d.Y - c.Y) - (b.Y - a.Y) * (d.X - c.X);
double mem1 = (a.Y - c.Y) * (d.X - c.X) - (a.X - c.X) * (d.Y - c.Y);
double mem2 = (a.Y - c.Y) * (b.X - a.X) - (a.X - c.X) * (b.Y - a.Y);
r = mem1 / deno;
s = mem2 / deno;
if (r > 1 || r < 0)
return false;
if (s > 1 || s < 0)
return false;
return true;
}
判断是否为凸多边形 --> 凸多边形 --> 线段相交
typedef struct vector{
double x,y;
}Vector; //向量
/*
* 由两个点构造一个向量
*/
Vector VectorConstruct(Point A, Point B) {
Vector v;
v.x = B.x - A.x;
v.y = B.y - A.y;
return v;
}
// 向量的叉积
double CrossProduct(Vector a, Vector b) {
return a.x * b.y - a.y * b.x;
}
/*
* 判断两线段(线段AB和CD)是否相交,是返回1,否0
* 判断四边形ACBD是否是一个凸四边形
*/
int SegmentIntersection(Point A, Point B, Point C, Point D) {
double c[4];
Vector AC = VectorConstruct(A, C);
Vector CB = VectorConstruct(C, B);
Vector BD = VectorConstruct(B, D);
Vector DA = VectorConstruct(D, A);
c[0] = CrossProduct(AC, CB);
c[1] = CrossProduct(CB, BD);
c[2] = CrossProduct(BD, DA);
c[3] = CrossProduct(DA, AC);
int f1=0, f2=0; // 计算正数,负数的个数
int i;
for (i=0; i<4; i++) {
if (c[i] > 0) f1++;
if (c[i] < 0) f2++;
}
if (f1 > 0 && f2 > 0) // 有正,有负,返回无交集
return 0;
else
return 1;
}
//功能:求点在有向直线左边还是右边
//返回:0共线、1左边、-1右边
int left_right(point a,point b,double x,double y) {
double t;
a.x -= x;
b.x -= x;
a.y -= y;
b.y -= y;
t = a.x*b.y-a.y*b.x;
return t==0 ? 0 : (t>0?1:-1); //注意:double类型t==0应该改成fabs(t)<10e-6
}
//功能:线段c,d和直线a,b是否相交
bool intersect1(point a,point b,point c,point d) {
return left_right(a,b,c.x,c.y)^left_right(a,b,d.x,d.y)==-2;
}
//功能:判断线段c,d和线段a,b是否相交
bool intersect(point a,point b,point c,point d) {
return intersect1(a,b,c,d) && intersect(c,d,a,b);
}