問題:給出兩條線段,問兩線段是否相交?
向量叉乘(行列式計算):向量a(x1,y1),向量b(x2,y2
首先我們要明白乙個定理:向量a×向量b(×為向量叉乘),若結果小於0,表示向量b在向量a的順時針方向;若結果大於0,表示向量b在向量a的逆時針方向;若等於0,表示向量a與向量b平行。(順逆時針是指兩向量平移至起點相連,從某個方向旋轉到另乙個向量小於180度)。如下圖:
在上圖中,oa×ob = 2 > 0, ob在oa的逆時針方向;oa×oc = -2 < 0,oc在oa的順勢針方向。即叉乘結果大於0,後乙個在前乙個的逆時針方向;小於零,後乙個在前乙個的順時針方向。
那如何來判斷兩線段是否相交呢?
假設有兩條線段ab,cd,若ab,cd相交,我們可以確定:
1.線段ab與cd所在的直線相交,即點a和點b分別在直線cd的兩邊;
2.線段cd與ab所在的直線相交,即點c和點d分別在直線ab的兩邊;
上面兩個條件同時滿足是兩線段相交的充要條件,所以我們只需要證明點a和點b分別在直線cd的兩邊,點c和點d分別在直線ab的兩邊,這樣便可以證明線段ab與cd相交了。
那判斷兩線段是否相交與一開始提到的向量叉乘定理有什麼關係呢?有,我們可以通過叉乘來證明上面說的充要條件。看下圖:
在上圖中,線段ab與線段cd相交,於是我們可以得到兩個向量ac,ad,c和d分別在ab的兩邊,向量ac在向量ab的逆勢針方向,ab×ac > 0;向量ad在向量ab的順勢針方向,ab×ad < 0,兩叉乘結果異號。
這樣,方法就出來了:如果線段cd的兩個端點c和d,與另一條線段的乙個端點(a或b,只能是其中乙個)連成的向量,與向量ab做叉乘,若結果異號,表示c和d分別在直線ab的兩邊,若結果同號,則表示cd兩點都在ab的一邊,則肯定不相交。
當然,不能只證明c,d在直線ab的兩邊,還要用相同的方法證明a,b在直線cd的兩邊,兩者同時滿足才是線段相交的充要條件。
不過,線段相交還有一些特殊情況:
1.只有1點相交,如下圖:
上圖中,線段ab與cd相交於c點,按照之前介紹的方法,我們可以連成兩向量ad和ac,這時候,我們發現,ac與ab共線,ab×ac = 0;而ab×ad < 0;兩者並不異號,可實際上仍然相交。所以當出現兩叉乘結果中,有一方為0,也可以看成點cd在直線ab的兩邊。
2.兩條線段重合,如下圖:
在上圖中,線段ab與線段cd重合,重合部分為cb,這種重合的情況要特殊判斷:
首先,我們給沒條線段的兩個端點排序,大小判斷方法如下:橫座標大的點更大,橫座標相同,縱座標大的點更大。
排好序後,每條線段中,小的點當起點,大的當終點。我們計算向量ab×向量cd,若結果為0,表示線段ab平行cd,平行才有了重合的可能;但平行也分共線和不共線,只有共線才有可能重合,看下圖:
上圖中,第一種情況不共線,第二種情況共線。那如何來判斷是否共線呢?
我們可以在兩條線段中各取一點,用這兩點組成的向量與其中一條線段進行叉乘,結果若為0,就表示兩線段共線,如下圖:
我們取向量bc,若bc×cd = 0,表示兩點共線,即是第二種情況,否則就是第一種情況。第一種情況肯定不相交。猴子為什麼不喜歡平行線?因為他們沒有相交。。。(尬)
然然然然然而,即使他們共線,卻還是不一定重合,就如上圖中第二種情況。這時候,之前給點排序的妙處就體現出來了:
若一條線段ab與另一條線段cd共線,且線段ab的起點小於等於線段cd的起點,但線段ab的終點(注意是終點)大於等於線段cd的起點(注意是起點),或者交換一下順序,cd的起點小於ab的起點......只要滿足其中乙個,就表示有重合部分。
下面來道例題:51nod1264(模板)
**:
#include#includeview code#include
#include
#include
#include
#include
#include
#include
#define eps 1e-7
#define ll long long
#define inf 0x3f3f3f3f
#define pi 3.141592653589793238462643383279
using
namespace
std;
struct
node;
double cmp(node a,node b) //
給線段的座標排序
double compute(double x1,double y1,double x2,double y2) //
計算叉乘的結果
int compare(node a,node b) //
比較座標的大小
intmain()
else flag = 0
; }
else
if(compute(po[0].x-po[1].x , po[0].y-po[1].y , po[2].x-po[3].x , po[2].y-po[3].y) !=0 ) //
若不平行
else flag = 0
;
if(flag) cout<
yes\n";
else cout<
no\n";}}
參考部落格:
向量叉乘 判斷兩條線段是否相交
向量叉乘 行列式計算 向量a x1,y1 向量b x2,y2 首先我們要明白乙個定理 向量a 向量b 為向量叉乘 若結果小於0,表示向量b在向量a的順時針方向 若結果大於0,表示向量b在向量a的逆時針方向 若等於0,表示向量a與向量b平行。順逆時針是指兩向量平移至起點相連,從某個方向旋轉到另乙個向量...
判斷兩條線段是否相交
如上圖,判斷線段ab和線段cd相交。分析 如果線段ab和線段cd相交,只能是圖中的兩種相交情況。可以用向量叉乘來判斷。如果 向量ab叉乘向量ac 向量ab叉乘向量ad 0 並且 向量cd叉乘向量ca 向量cd叉乘向量cb 0,那麼說明線段ab與線段cd相交。設a x1,y1 b x2,y2 c x3...
判斷兩條線段是否相交
題目 給定兩條線段,判斷這兩條線段是否相交,線段ab的表示形式是a x1,y1 b x2,y2 線段cd的表示形式為c x3,y3 d x4,y4 那麼我們如何判斷線段ab與線段cd是否相交。解析 在介紹如何解決線段相交問題之前,我們先介紹向量的叉積。如下圖所示 下面的圖 1 表示p1向量在p2向量...