平面内两条线段的位置关系(相交)判定与交点求解
http://www.cnblogs.com/devymex/archive/2010/08/19/1803885.html
概念
平面內(nèi)兩條線(xiàn)段位置關(guān)系的判定在很多領(lǐng)域都有著廣泛的應(yīng)用,比如游戲、CAD、圖形處理等,而兩線(xiàn)段交點(diǎn)的求解又是該算法中重要的一環(huán)。本文將盡可能用通俗的語(yǔ)言詳細(xì)的描述一種主流且性能較高的判定算法。
外積,又稱(chēng)叉積,是向量代數(shù)(解析幾何)中的一個(gè)概念。兩個(gè)二維向量v1(x1, y1)和v2(x2, y2)的外積v1×v2=x1y2-y1x2。如果由v1到v2是順時(shí)針轉(zhuǎn)動(dòng),外積為負(fù),反之為正,為0表示二者方向相同(平行)。此外,文中涉及行例式和方程組的概念,請(qǐng)參閱線(xiàn)性代數(shù)的相關(guān)內(nèi)容。
為方便計(jì)算,對(duì)坐標(biāo)點(diǎn)的大小比較作如下定義:x坐標(biāo)較大的點(diǎn)為大,x坐標(biāo)相等但y坐標(biāo)較大的為大,x與y都相等的點(diǎn)相等。一條線(xiàn)段中較小的一端為起點(diǎn),較大的一端為終點(diǎn)。
?
問(wèn)題
給定兩條線(xiàn)段的端點(diǎn)坐標(biāo),求其位置關(guān)系,并求出交點(diǎn)(如果存在)。
?
分析
兩條線(xiàn)段的位置關(guān)系大體上可以分為三類(lèi):有重合部分、無(wú)重合部分但有交點(diǎn)(相交)、無(wú)交點(diǎn)。為避免精度問(wèn)題,首先要將所有存在重合的情況排除。
重合可分為:完全重合、一端重合、部分重合三種情況。顯然,兩條線(xiàn)段的起止點(diǎn)都相同即為完全重合;只有起點(diǎn)相同或只有終點(diǎn)相同的為一端重合(注意:坐標(biāo)較小的一條線(xiàn)段的終點(diǎn)與坐標(biāo)較大的一條線(xiàn)段的起點(diǎn)相同時(shí)應(yīng)判定為相交)。要判斷是否部分重合,必須先判斷是否平行。設(shè)線(xiàn)段L1(p1->p2)和L2(p3->p4),其中p1(x1, y1)為第一條線(xiàn)段的起點(diǎn),p2(x2, y2)為第一條線(xiàn)段的終點(diǎn),p3(x3, y3)為第二條線(xiàn)段的起點(diǎn),p4(x4, y4)為第二段線(xiàn)段的終點(diǎn),由此可構(gòu)造兩個(gè)向量:
- v1(x2-x1, y2-y1),v2(x4-x3, y4-y3)
若v1與v2的外積v1×v2為0,則兩條線(xiàn)段平行,有可能存在部分重合。再判斷兩條平行線(xiàn)段是否共線(xiàn),方法是用L1的一端和L2的一端構(gòu)成向量vs并與v2作外積,如果vs與v2也平行則兩線(xiàn)段共線(xiàn)(三點(diǎn)共線(xiàn))。在共線(xiàn)的前提下,若起點(diǎn)較小的線(xiàn)段終點(diǎn)大于起點(diǎn)較大的線(xiàn)段起點(diǎn),則判定為部分重合。
沒(méi)有重合,就要判定兩條線(xiàn)是否相交,主要的算法還是依靠外積。然而外積的計(jì)算開(kāi)銷(xiāo)比較大,如果不相交的情況比較多,可先做快速排斥實(shí)驗(yàn):將兩條線(xiàn)段視為兩個(gè)矩形的對(duì)角線(xiàn),并構(gòu)造出這兩個(gè)矩形。如果這兩個(gè)矩形沒(méi)有重疊部分(x坐標(biāo)相離或y坐標(biāo)相離)即可判定為不相交。
然后執(zhí)行跨立試驗(yàn)。兩條相交的線(xiàn)段必然相互跨立,簡(jiǎn)單的講就是p1和p2兩點(diǎn)位于L2的兩側(cè)且p3和p4兩點(diǎn)位于L1的兩側(cè),這樣就可利用外積做出判斷了。分別構(gòu)造向量s1(p3, p1), s2(p3, p2),如果s1×v2與s2×v2異號(hào)(s1->v2與s2->v2轉(zhuǎn)動(dòng)的方向相反),則說(shuō)明p1和p2位于L2的兩側(cè)。同理可判定p3和p4是否跨立L1。如果上述四個(gè)叉積中任何一個(gè)等于0,則說(shuō)明一條線(xiàn)段的端點(diǎn)在另一條線(xiàn)上。
當(dāng)判定兩條線(xiàn)段相交后,就可以進(jìn)行交點(diǎn)的求解了。當(dāng)然,求交點(diǎn)可以用平面幾何方法,列點(diǎn)斜式方程來(lái)完成。但這樣作會(huì)難以處理斜率為0的特殊情況,且運(yùn)算中會(huì)出現(xiàn)多次除法,很難保證精度。這里將使用向量法求解。
設(shè)交點(diǎn)為(x0, y0),則下列方程組必然成立:
其中k1和k2為任意不為0的常數(shù)(若為0,則說(shuō)明有重合的端點(diǎn),這種情況在上面已經(jīng)被排除了)。1式與2式聯(lián)系,3式與4式聯(lián)立,消去k1和k2可得:
將含有未知數(shù)x0和y0的項(xiàng)移到左邊,常數(shù)項(xiàng)移動(dòng)到右邊,得:
設(shè)兩個(gè)常數(shù)項(xiàng)分別為b1和b2:
- b1=(y2-y1)x1+(x1-x2)y1
- b2=(y4-y3)x3+(x3-x4)y3
系數(shù)行列式為D,用b1和b2替換x0的系數(shù)所得系數(shù)行列式為D1,替換y0的系數(shù)所得系數(shù)行列式為D2,則有:
- |D|=(x2-x1)(y4-y3)-(x4-x3)(y2-y1)
- |D1|=b2(x2-x1)-b1(x4-x3)
- |D2|=b2(y2-y1)-b1(y4-y3)
由此,可求得交點(diǎn)坐標(biāo)為:
- x0=|D1|/|D|, y0=|D2|/|D|
解畢。
判斷兩線(xiàn)段相交
經(jīng)典方法,就是跨立試驗(yàn)了,即如果一條線(xiàn)段跨過(guò)另一條線(xiàn)段,則線(xiàn)段的兩個(gè)端點(diǎn)分別在另一條線(xiàn)段的兩側(cè)。但是,還需要檢測(cè)邊界情況,即兩條線(xiàn)段中可能某條線(xiàn)段的某個(gè)端點(diǎn)正好落在另一條線(xiàn)段上。這也是算法導(dǎo)論中介紹的算法。
程序模擬如下:
總結(jié)
以上是生活随笔為你收集整理的平面内两条线段的位置关系(相交)判定与交点求解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。