[GIS算法] 判断两线段是否相交的四种方案(快速排斥+跨立实验、参数方程求解、凸多边形、点在线的哪一侧)-附C语言实现

文章目录

    • 算法一:快速排斥+跨立试验
      • 代码
    • 算法二:参数方程求解
      • 代码
    • 算法三:凸多边形
    • 算法四:点在线的哪一侧

算法一:快速排斥+跨立试验

重点掌握

【原理】利用矢量的叉乘
[GIS算法] 判断两线段是否相交的四种方案(快速排斥+跨立实验、参数方程求解、凸多边形、点在线的哪一侧)-附C语言实现_第1张图片

【图解】
[GIS算法] 判断两线段是否相交的四种方案(快速排斥+跨立实验、参数方程求解、凸多边形、点在线的哪一侧)-附C语言实现_第2张图片[GIS算法] 判断两线段是否相交的四种方案(快速排斥+跨立实验、参数方程求解、凸多边形、点在线的哪一侧)-附C语言实现_第3张图片

代码

#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是否相交

【定义】线段的参数方程:

  1. AD = A + r(b-A),r∈[0,1] (用r描述AB线段上的每个点,不再是x,y)
  2. CD = C + s(D-c),s∈[0,1]

【推算】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
[GIS算法] 判断两线段是否相交的四种方案(快速排斥+跨立实验、参数方程求解、凸多边形、点在线的哪一侧)-附C语言实现_第4张图片

【判断方法】设P为AB、CD的交点 => P=A+r(B-A) => Px=Ax+r(Bx-Ax),Py=Ay+r(By-Ay)

  1. 如果(0≤r≤1)and(0≤s≤1) => AB、CD交点存在
  2. 如果(Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)=0 => AB和CD平行
  3. 如果2成立,(Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cx)也为0 => AB和CD共线
  4. 如果AB和CD相交,而交点不位于线段AB、CD之间,则交点位置可以通过以下条件判断
    • r>1 => P位于AB的延长线上
    • r<0 => P位于BA的延长线上
    • s>1 => P位于CD的延长线上
    • s<0 => P位于DC的延长线上

代码

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;
}

算法三:凸多边形

判断是否为凸多边形 --> 凸多边形 --> 线段相交

  1. 凸多边形:当从某个点开始绕一周,要么全顺时针拐弯,要么全逆时针

[GIS算法] 判断两线段是否相交的四种方案(快速排斥+跨立实验、参数方程求解、凸多边形、点在线的哪一侧)-附C语言实现_第5张图片

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);  
}

你可能感兴趣的:(#,GIS算法基础)