【C++】任意两个多边形相交问题

灵感

最近尝试制作游戏引擎,在侦测物体碰撞时遇到问题,借此解决。

思路

我们置一些点,依次连接,即可得到一个多边形,可能是凹多边形,也可能是凸多边形。

设两个多边形为f1和f2,多边形的每个点为p1,p2,p3,…,将p1与p2连接,p2与p3连接,直到最后一个点与第一个点连接得到封闭图形。

那么,判断f1和f2是否相交,可以将每条边用解析式表示,将两个多边形的边的解析式联立算交点,并将交点与解析式的取值范围相匹配,即可解决此问题。

解析式为y=kx+b,两点为(x1,y1),(x2,y2),那么

k = y 1 − y 2 x 1 − x 2 k=\frac{y_1-y_2}{x_1-x_2} k=x1x2y1y2

b = y 1 − y 1 − y 2 x 1 − x 2 x 1 b=y_1-\frac{y_1-y_2}{x_1-x_2}x_1 b=y1x1x2y1y2x1

两个解析式交点横坐标可以表示为
x = b 2 − b 1 k 1 − k 2 x=\frac{b_2-b_1}{k_1-k_2} x=k1k2b2b1

代码

首先,做一个将两定点表示的线段转换成k,b,和两个极值

//lines表示多边形的所有边,每个边都包括k,b,x1,x2四个参数
//f表示多边形的所有边,每个边包括两个端点的坐标x,y
//c表示多边形边数
void analyze(double lines[][4],double f[][2],int c){
	for(int i=0;i<c;i++){
		// k b x1 x2
		if(i<c-1){
			lines[i][0]=(f[i][1]-f[i+1][1])/(f[i][0]-f[i+1][0]);
			lines[i][1]=f[i][1]-(f[i+1][1]-f[i][1])/(f[i+1][0]-f[i][0])*f[i][0];
			lines[i][2]=f[i][0];
			lines[i][3]=f[i+1][0];
		}else{
		//保证首尾两点连接
			lines[i][0]=(f[i][1]-f[0][1])/(f[i][0]-f[0][0]);
			lines[i][1]=f[i][1]-(f[0][1]-f[i][1])/(f[0][0]-f[i][0])*f[i][0];
			lines[i][2]=f[i][0];
			lines[i][3]=f[0][0];
		};
	};
}

然后编写主逻辑,返回的就是交点数量

//f1和f2是用端点所表示的多变形,c1和c2分别是两者的边数
int getRelation(double f1[][2],int c1,double f2[][2],int c2){
	double lines[2][c1][4];
	//lines[0]表示以解析式(每条边用k,b,两端极值)表示的多边形f1
    //lines[1]表示以解析式(每条边用k,b,两端极值)表示的多边形f2
	int r=0;//交点数量
	analyze(lines[0],f1,c1);//进行转换
	analyze(lines[1],f2,c2);
	//将两个多边形所有边进行两两交点计算
	for(int i=0;i<c1;i++){
		for(int j=0;j<c2;j++){
			double xS=(lines[0][i][1]-lines[1][j][1])/(lines[1][j][0]-lines[0][i][0]);//交点横坐标
			double x1=lines[0][i][2],x1_=lines[0][i][3];//f1边解析式的两个极值
			double x2=lines[1][j][2],x2_=lines[1][j][3];//f2边解析式的两个极值
			//判断交点是否在两边上
			if((xS<x1&&xS>x1_)||(xS<x1_&&xS>x1))
			if((xS<x2&&xS>x2_)||(xS<x2_&&xS>x2))
				r++;
		}
	}
	return r;
};

自评

这个算法我相信不是最好的,它的计算量比较大,篇幅较多,希望有人能研究并用更好的方式解决这个问题。

你可能感兴趣的:(笔记)