日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

平面内两条线段的位置关系(相交)判定与交点求解

發(fā)布時(shí)間:2024/9/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 平面内两条线段的位置关系(相交)判定与交点求解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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),則下列方程組必然成立:

  • x0-x1=k1(x2-x1)
  • y0-y1=k1(y2-y1)
  • x0-x3=k2(x4-x3)
  • y0-y3=k2(y4-y3)
  • 其中k1和k2為任意不為0的常數(shù)(若為0,則說(shuō)明有重合的端點(diǎn),這種情況在上面已經(jīng)被排除了)。1式與2式聯(lián)系,3式與4式聯(lián)立,消去k1和k2可得:

  • x0(y2-y1)-x1(y2-y1)=y0(x2-x1)-y1(x2-x1)
  • x0(y4-y3)-x3(y4-y3)=y0(x4-x3)-y3(x4-x3)
  • 將含有未知數(shù)x0和y0的項(xiàng)移到左邊,常數(shù)項(xiàng)移動(dòng)到右邊,得:

  • (y2-y1)x0+(x1-x2)y0=(y2-y1)x1+(x1-x2)y1
  • (y4-y3)x0+(x3-x4)y0=(y4-y3)x3+(x3-x4)y3
  • 設(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)論中介紹的算法。
    程序模擬如下:

  • int direction(point* pi, point* pj, point* pk){
  • ???? point p1, p2;
  • ????
  • ???? p1.x = pk->x - pi->x;
  • ???? p1.y = pk->y - pi->y;
  • ????
  • ???? p2.x = pj->x - pi->x;
  • ???? p2.y = pj->y - pi->y;
  • ????
  • ????return crossProduct(&p1, &p2);
  • }
  • int onSegment(point* pi, point* pj, point* pk){
  • ????int minx, miny, maxx, maxy;
  • ????if (pi->x > pj->x){
  • ???????? minx = pj->x;
  • ???????? maxx = pi->x;???
  • ???? }
  • ????else{
  • ???????? minx = pi->x;
  • ???????? maxx = pj->x;
  • ???? }
  • ????
  • ????if (pi->y > pj->y){
  • ???????? miny = pj->y;
  • ???????? maxy = pi->y;???
  • ???? }
  • ????else{
  • ???????? miny = pi->y;
  • ???????? maxy = pj->y;
  • ???? }
  • ????
  • ????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){
  • ????int d1 = direction(p3, p4, p1);
  • ????int d2 = direction(p3, p4, p2);
  • ????int d3 = direction(p1, p2, p3);
  • ????int d4 = direction(p1, p2, p4);
  • ????if (d1 * d2 < 0 && d3 * d4 < 0)
  • ????????return 1;
  • ????else if (!d1 && onSegment(p3, p4, p1))
  • ????????return 1;
  • ????else if (!d2 && onSegment(p3, p4, p2))
  • ????????return 1;
  • ????else if (!d3 && onSegment(p1, p2, p3))
  • ????????return 1;
  • ????else if (!d4 && onSegment(p1, p2, p4))
  • ????????return 1;
  • ????else
  • ????????return 0;
  • }

  • 總結(jié)

    以上是生活随笔為你收集整理的平面内两条线段的位置关系(相交)判定与交点求解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。