背景
在做51nod上的第1951题时,需要根据给出的两条线段来判断这两条线段是否相交。所以在这里记录一下。
判断两条线段是否相交有两步:
①快速排斥计算
②跨立计算
快速排斥
给出线条AB、CD,如果以AB、CD为对角线的矩形不相交,那么AB、CD也必不可能相交;如果矩形相交,那么需要再通过跨立计算进行判断。对于矩形不相交,有下面两种情况:
对于上面两种情况,可以分成四类来讨论:
①AB两坐标中最大的x值 小于 CD两坐标中最小x值
②CD两坐标中最大的x值 小于 AB两坐标中最小x值
③AB两坐标中最大的y值 小于 CD两坐标中最小y值
④CD两坐标中最大的y值 小于 AB两坐标中最小y值
只要满足了以上四种的其中一种,就可以认为AB与CD不相交。
跨立计算:
首先,这里需要用到向量叉乘的算法:其中AB与CD是三维空间上的向量,与xOy平面平行。
其次,如下图。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++)
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;
}