在看到有人討論如何判斷線段相交的問題的時候,發現自己有向量這塊基礎知識的缺失,因此寫篇筆記填個坑,以便記憶。
一、向量的基本知識
1.向量的概念:如果一條線段的端點是有次序之分的,我們把這種線段成為有向線段(directed segment)。如果有向線段p1p2的起點p1在座標原點,則將其稱為向量(vector)p2。
2.向量加減法:設二維向量p = ( x1, y1 ),q = ( x2 , y2 ),
向量加法定義為: p + q = ( x1 + x2 , y1 + y2 )
向量減法定義為: p - q = ( x1 - x2 , y1 - y2 )
顯然有性質 p + q = q + p,p - q = - ( q - p )。
第乙個可能會想到的辦法,就是判斷斜率,這個在中學時代就學過了,不過斜率需要考慮垂直的特殊情況,比較麻煩。計算兩個向量的叉積或許是乙個更好的辦法,如果兩個向量叉乘為0,則是平行或者重合的,否則兩直線相交。這裡貼出來乙個便於理解原理的**如下:
#include #include using namespace std;
using namespace cv;
struct point
;struct v
;int crossproduct(v* v1, v* v2)
int main()
輸出結果為: crossproduct: -3
如圖所示,向量p1,p2的叉乘就是圖中平行四邊形的面積=3,負號就表示向量p1在p2的逆時針方向。
三、判斷兩線段相交
經典方法,就是跨立試驗了,即如果一條線段跨過另一條線段,則線段的兩個端點分別在另一條線段的兩側。但是,還需要檢測邊界情況,即兩條線段中可能某條線段的某個端點正好落在另一條線段上。
程式模擬如下:
int direction(point* pi, point* pj, point* pk)
int onsegment(point* pi, point* pj, point* pk)
else
if (pi->y > pj->y)
else
if (minx <= pk->x && pk->x <= maxx && miny <= pk->y && pk->y <= maxy)
return 1;
else
return 0;
}int segmentintersect(point* p1, point* p2, point* p3, point* p4)
實際上,如果想改進上述演算法,還可以在跨立試驗前加一步,就是先做快速排斥試驗。那就是,先分別判斷以兩條線段為對角線的矩形是否相交,如果不相交,則兩個線段肯定不相交。
四.判斷兩條線段相交,然後計算交點
設一條線段為l0=p1p2, 另一條線段或直線為l1=q1q2, 要計算的就是l0和l1的交點。
1.首先判斷l0和l1是否相交(方法已在前文討論過), 如果不相交則沒有交點, 否則說明l0和l1一定有交點, 下面就將l0和l1都看作直線來考慮.
2.如果p1和p2橫座標相同, 即l0平行於y軸
a)若l1也平行於y軸
i.若p1的縱座標和q1的縱座標相同, 說明l0和l1共線, 假如l1是直線的話他們有無窮的交點, 假如l1是線段的話可用"計算兩條共線線段的交點"的演算法求他們的交點(該方法在前文已討論過);
ii.否則說明l0和l1平行, 他們沒有交點;
b)若l1不平行於y軸, 則交點橫座標為p1的橫座標, 代入到l1的直線方程中可以計算出交點縱座標;
3.如果p1和p2橫座標不同, 但是q1和q2橫座標相同, 即l1平行於y軸, 則交點橫座標為q1的橫座標, 代入到l0的直線方程中可以計算出交點縱座標;
4.如果p1和p2縱座標相同, 即l0平行於x軸
a)若l1也平行於x軸,
i.若p1的橫座標和q1的橫座標相同, 說明l0和l1共線, 假如l1是直線的話他們有無窮的交點, 假如l1是線段的話可用"計算兩條共線線段的交點"的演算法求他們的交點(該方法在前文已討論過);
ii.否則說明l0和l1平行, 他們沒有交點;
b)若l1不平行於x軸, 則交點縱座標為p1的縱座標, 代入到l1的直線方程中可以計算出交點橫座標;
5.如果p1和p2縱座標不同, 但是q1和q2縱座標相同, 即l1平行於x軸, 則交點縱座標為q1的縱座標, 代入到l0的直線方程中可以計算出交點橫座標;
6.剩下的情況就是l1和l0的斜率均存在且不為0的情況
a)計算出l0的斜率k0, l1的斜率k1;
b)如果k1 = k2
i.如果q1在l0上, 則說明l0和l1共線, 假如l1是直線的話有無窮交點, 假如l1是線段的話可用"計算兩條共線線段的交點"的演算法求他們的交點(該方法在前文已討論過);
ii.如果q1不在l0上, 則說明l0和l1平行, 他們沒有交點.
c)聯立兩直線的方程組可以解出交點來
這個演算法並不複雜, 但是要分情況討論清楚, 尤其是當兩條線段共線的情況需要單獨考慮, 所以在前文將求兩條共線線段的演算法單獨寫出來. 另外, 一開始就先利用向量叉乘判斷線段與線段(或直線)是否相交, 如果結果是相交, 那麼在後面就可以將線段全部看作直線來考慮. 需要注意的是, 我們可以將直線或線段方程改寫為ax+by+c=0的形式, 這樣一來上述過程的部分步驟可以合併, 縮短了**長度, 但是由於先要求出引數, 這種演算法將花費更多的時間.
鄙人才疏學淺,尚有不足還望不惜賜教。
向量的叉積
它可以用來判斷點在直線的某側。進而可以解決點是否在三角形內,兩個矩形是否重疊等問題。向量的叉積的模表示這兩個向量圍成的平行四邊形的面積。設向量p x1,y1 q x2,y2 則向量叉積定義為由 0,0 p1 p2和p1 p2所組成的平行四邊形的帶符號的面積,即 p q x1 y2 x2 y1,其結果...
向量的點積和叉積
點乘 也叫向量的內積 數量積.顧名思義,求下來的結果是乙個數.向量a 向量b a b cos 在物理學中,已知力與位移求功,實際上就是求向量f與向量s的內積,即要用點乘.叉乘 也叫向量的外積 向量積.顧名思義,求下來的結果是乙個向量,記這個向量為c.向量c 向量a 向量b a b sin 向量c的方...
向量的點積和叉積
一 向量數量積用於計算向量夾角 中學階段學空間幾何時,知道用兩個向量a,b之間的數量積來計算向量之間的夾角。這是因為三角形的餘弦定理 abc中角a b c對應的邊分別為a b c 則有cosa b c a 2bc cosb a c b 2ac cosc a b c 2ab 基於此餘弦定理 我們進一步...