判斷兩條線段是否相交 (向量叉乘)

2022-05-04 20:12:27 字數 3209 閱讀 8804

問題:給出兩條線段,問兩線段是否相交?

向量叉乘(行列式計算):向量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#include

#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";}}

view code

參考部落格:

向量叉乘 判斷兩條線段是否相交

向量叉乘 行列式計算 向量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向量...