首先引出計算幾何學中一個最基本的問題:如何判斷向量在
的順時針方向還是逆時針方向?
把p0定為原點,p1的坐標是(x1,y1),p2的坐標是(x2,y2)。向量的叉積(cross product)實際上就是矩陣的行列式:
當叉積為正時,說明在
的順時針方向上;叉積為0說明兩向量共線(同向或反向)。
當同時滿足:
(1)和
在
的兩側(即一個順時針方向上,一個在逆時針方向上)
(2)和
在
的兩側
時可肯定和
相交。
圖1
圖1是線段相交的一般情形。
圖2只滿足第(1)條,不滿足第(2)條所以不能證明和
相交。
圖2
圖3和圖4是一種特殊情況,它不滿足第(2)條,因為和
重合,即
和
的叉積為0。
可見當叉積為0時要分情況討論,當p3在線段p1p2上時兩線段相交;當p3在線段p1p2的延長線上時兩線段不相交。
double direction(pair<double,double> p1,pair<double,double> p2,pair<double,double> p3){ pair<double,double> d1=make_pair(p3.first-p1.first,p3.second-p1.second); pair<double,double> d2=make_pair(p2.first-p1.first,p2.second-p1.second); return d1.first*d2.second-d1.second*d2.first; }
direction函數用於計算和
的叉積。
bool OnSegment(pair<double,double> p1,pair<double,double> p2,pair<double,double> p3){ double x_min,x_max,y_min,y_max; if(p1.first<p2.first){ x_min=p1.first; x_max=p2.first; }else{ x_min=p2.first; x_max=p1.first; } if(p1.second<p2.second){ y_min=p1.second; y_max=p2.second; }else{ y_min=p2.second; y_max=p1.second; } if(p3.first<x_min || p3.first>x_max || p3.second<y_min || p3.second>y_max) return false; else return true; }
當p3在直線p1p2上時,OnSegment函數用於確認p3在上,還是在
的延長線上。
下面是用於判斷兩線段是否相交的主函數。
bool SegmentIntersect(pair<double,double> p1,pair<double,double> p2,pair<double,double> p3,pair<double,double> p4){ double d1=direction(p3,p4,p1); double d2=direction(p3,p4,p2); double d3=direction(p1,p2,p3); double d4=direction(p1,p2,p4); if(d1*d2<0 && d3*d4<0) return true; else if(d1==0 && OnSegment(p3,p4,p1)) return true; else if(d2==0 && OnSegment(p3,p4,p2)) return true; else if(d3==0 && OnSegment(p1,p2,p3)) return true; else if(d4==0 && OnSegment(p1,p2,p4)) return true; else return false; }
測試函數:
int main(){ double x1,y1,x2,y2,x3,y3,x4,y4; cout<<"Please input x1,y1,x2,y2,x3,y3,x4,y4 by order"<<endl; cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4; pair<double,double> p1=make_pair(x1,y1); pair<double,double> p2=make_pair(x2,y2); pair<double,double> p3=make_pair(x3,y3); pair<double,double> p4=make_pair(x4,y4); if(SegmentIntersect(p1,p2,p3,p4)) cout<<"YES"<<endl; else cout<<"NO"<<endl; return 0; }