題意:給出線段的端點和矩形對角線的兩個點,要判斷線段和矩形是否相交
解題:Computational Geometry(計算幾何);如果線段在矩形內部算是相交的,如果不是,就判斷線段和矩形四條邊是否有交點,所以重點就是如何判斷兩條線段相交
如圖一:若(p1,p2)和(p3,p4)相交,他們相互跨越,那麼p1,p2和(p3,p4)必然在(p3,p4)[或(p1,p2) 的兩側;就可以用向量來解決,(p1,p3)在(p1,p2)的逆時針方向,(p1,p4)在(p1,p2)的順時針方向;就可以用叉積來解決,如圖三,叉積是(0,0),a1,a2,a3(=a1+a2) 構成的平行四邊形的有向面積,或者是a1*a2 = x1y2-x2y1;若a1*a2 >0 則則表示a1在a2的順時針方向,否則是逆時針方向;
綜上所述:判斷兩線段相交,1.看叉積,兩個叉積不同號 2.如果叉積等於0,表示共線,但是由於是線段,所以在判斷點是否在線段上。
代碼:在圖下面
//uva191 Intersection
//AC By Warteac
//Runtime:0.012s
//2013-5-3
#include<iostream>
#include<cstdio>
using namespace std;
struct point{
int x,y;
point(int x1 = 0, int y1 = 0){x = x1; y = y1;}
void print(){cout << "x= " << x << " y= " << y << endl;}
};//定義點結構體
//求向量的叉積,p1*p2 > 0 => p1 在 p2的順時針方向,< 0 逆時針
int direction(point pi,point pj,point pk){
return ((pj.x - pi.x)*(pk.y - pi.y)-(pk.x - pi.x)*(pj.y - pi.y));
}
//向量共線的前提下,判斷是點pk是否在線段(pi,pj)上
bool onSegment(point pi,point pj,point pk){
if((min(pi.x,pj.x) <= pk.x && pk.x <= max(pi.x,pj.x)) && (min(pi.y,pj.y) <= pk.y && pk.y <= max(pi.y,pj.y))){
return true;
}else{
return false;
}
}
//線段(p1,p2)和線段(p3,p4)是否相交
bool segmentsIntersect(point p1,point p2,point p3, point p4){
int d1,d2,d3,d4;
d1 = direction(p3,p4,p1);
d2 = direction(p3,p4,p2);
d3 = direction(p1,p2,p3);
d4 = direction(p1,p2,p4);
//cout << d1 << " " << d2 <<" " << d3 << " " << d4 << endl;
if(((d1 > 0 && d2 < 0) || (d1 < 0 && d2 >0)) && ((d3 > 0 && d4 < 0)||(d3 < 0 && 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;
}
//線段(pa,pb)在矩形的內部
bool segmentInRectangle(point p1,point p3,point pa,point pb){
if( (min(p1.x,p3.x) <= pa.x && pa.x <= max(p1.x,p3.x)) &&
(min(p1.y,p3.y) <= pa.y && pa.y <= max(p1.y,p3.y)) &&
(min(p1.x,p3.x) <= pb.x && pb.x <= max(p1.x,p3.x)) &&
(min(p1.y,p3.y) <= pb.y && pb.y <= max(p1.y,p3.y)) )
return true;
else return false;
}
int main(){
point p1,p2,p3,p4;//矩形的四個頂點
point pa,pb;//線段的端點
int caseNum;
cin >> caseNum;
int x1,y1,x2,y2,x3,y3,x4,y4;
while(caseNum--){
cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;
pa = point(x1,y1);
pb = point(x2,y2);
p1 = point(x3,y3);
p3 = point(x4,y4);
p2 = point(x3,y4);
p4 = point(x4,y3);
if(segmentInRectangle(p1,p3,pa,pb) == true){//線段在矩形內部
cout << "T" << endl;
}else if( (segmentsIntersect(p1,p2,pa,pb))||
(segmentsIntersect(p1,p4,pa,pb))||
(segmentsIntersect(p3,p2,pa,pb))||
(segmentsIntersect(p3,p4,pa,pb)) )
cout << "T" << endl;//線段在外部,但是和矩形有交點
else cout << "F" << endl;
}
}