判断两条线段是否相交(C++)

背景

在做51nod上的第1951题时,需要根据给出的两条线段来判断这两条线段是否相交。所以在这里记录一下。

判断两条线段是否相交有两步:
①快速排斥计算
②跨立计算

快速排斥
给出线条AB、CD,如果以AB、CD为对角线的矩形不相交,那么AB、CD也必不可能相交;如果矩形相交,那么需要再通过跨立计算进行判断。对于矩形不相交,有下面两种情况:
判断两条线段是否相交(C++)_第1张图片
对于上面两种情况,可以分成四类来讨论:
①AB两坐标中最大的x值 小于 CD两坐标中最小x值
②CD两坐标中最大的x值 小于 AB两坐标中最小x值
③AB两坐标中最大的y值 小于 CD两坐标中最小y值
④CD两坐标中最大的y值 小于 AB两坐标中最小y值

只要满足了以上四种的其中一种,就可以认为AB与CD不相交。

跨立计算

首先,这里需要用到向量叉乘的算法:其中ABCD是三维空间上的向量,与xOy平面平行。
判断两条线段是否相交(C++)_第2张图片
其次,如下图。AB与CD相交必然有A、B在线段CD两边,C、D在线段AB两边。
根据上面的公式和右手螺旋法则,如果相交,AB X AC的z坐标值z1与AB X AD的z坐标值z2必然异号;同样的,DC X DA的z坐标值z3与DC X DB的z坐标值z4也必然异号。
特别的,如果B在CD上时,求得的z坐标值是0。所以只要同时满足z1 X z2 ≤ 0,z3 X z4 ≤ 0,就能保证必然相交
判断两条线段是否相交(C++)_第3张图片

参考代码(C++)

class line{
public:
	int xa;
	int ya;
	int xb;
	int yb;
	line(){}
	line(int xa, int ya, int xb, int yb){
		this->xa = xa;
		this->ya = ya;
		this->xb = xb;
		this->yb = yb;
	}
	int get_max_x(){
		return xa > xb ? xa : xb;
	}
	int get_min_x(){
		return xa > xb ? xb : xa;
	}
	int get_max_y(){
		return ya > yb ? ya : yb;
	}
	int get_min_y(){
		return ya > yb ? yb : ya;
	}
};

bool is_intersect(line myline1, line myline2){
	if(myline1.get_max_x() < myline2.get_min_x() || 
	   myline2.get_max_x() < myline1.get_min_x() ||
	   myline1.get_max_y() < myline2.get_min_y() || 
	   myline2.get_max_y() < myline1.get_min_y())   return false;
	int res1 = (myline1.xa - myline1.xb) * (myline2.ya - myline1.yb) - (myline1.ya - myline1.yb) * (myline2.xa - myline1.xb);
	int res2 = (myline1.xa - myline1.xb) * (myline2.yb - myline1.yb) - (myline1.ya - myline1.yb) * (myline2.xb - myline1.xb);
	
	int res3 = (myline2.xa - myline2.xb) * (myline1.ya - myline2.yb) - (myline2.ya - myline2.yb) * (myline1.xa - myline2.xb);
	int res4 = (myline2.xa - myline2.xb) * (myline1.yb - myline2.yb) - (myline2.ya - myline2.yb) * (myline1.xb - myline2.xb);
	if(res1 * res2 <= 0 && res3 * res4 <= 0) return true;
	else return false;
}

参考文章:
两条线段相交判断学习理解
判断两条线段是否相交—(向量叉乘)

你可能感兴趣的:(OJ学习,算法,c++)