亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++/STL實現判斷平面內兩條線段的位置關系代碼示例

2020-05-23 13:37:15
字體:
來源:轉載
供稿:網友

概念

平面內兩條線段位置關系的判定在很多領域都有著廣泛的應用,比如游戲、CAD、圖形處理等,而兩線段交點的求解又是該算法中重要的一環。本文將盡可能用通俗的語言詳細的描述一種主流且性能較高的判定算法。

外積,又稱叉積,是向量代數(解析幾何)中的一個概念。兩個二維向量v1(x1,y1)和v2(x2,y2)的外積v1×v2=x1y2-y1x2。如果由v1到v2是順時針轉動,外積為負,反之為正,為0表示二者方向相同(平行)。此外,文中涉及行例式和方程組的概念,請參閱線性代數的相關內容。

為方便計算,對坐標點的大小比較作如下定義:x坐標較大的點為大,x坐標相等但y坐標較大的為大,x與y都相等的點相等。一條線段中較小的一端為起點,較大的一端為終點。

問題

給定兩條線段的端點坐標,求其位置關系,并求出交點(如果存在)。

分析

兩條線段的位置關系大體上可以分為三類:有重合部分、無重合部分但有交點(相交)、無交點。為避免精度問題,首先要將所有存在重合的情況排除。

重合可分為:完全重合、一端重合、部分重合三種情況。顯然,兩條線段的起止點都相同即為完全重合;只有起點相同或只有終點相同的為一端重合(注意:坐標較小的一條線段的終點與坐標較大的一條線段的起點相同時應判定為相交)。要判斷是否部分重合,必須先判斷是否平行。設線段L1(p1->p2)和L2(p3->p4),其中p1(x1,y1)為第一條線段的起點,p2(x2,y2)為第一條線段的終點,p3(x3,y3)為第二條線段的起點,p4(x4,y4)為第二段線段的終點,由此可構造兩個向量:

v1(x2-x1,y2-y1),v2(x4-x3,y4-y3)

若v1與v2的外積v1×v2為0,則兩條線段平行,有可能存在部分重合。再判斷兩條平行線段是否共線,方法是用L1的一端和L2的一端構成向量vs并與v2作外積,如果vs與v2也平行則兩線段共線(三點共線)。在共線的前提下,若起點較小的線段終點大于起點較大的線段起點,則判定為部分重合。

沒有重合,就要判定兩條線是否相交,主要的算法還是依靠外積。然而外積的計算開銷比較大,如果不相交的情況比較多,可先做快速排斥實驗:將兩條線段視為兩個矩形的對角線,并構造出這兩個矩形。如果這兩個矩形沒有重疊部分(x坐標相離或y坐標相離)即可判定為不相交。

然后執行跨立試驗。兩條相交的線段必然相互跨立,簡單的講就是p1和p2兩點位于L2的兩側且p3和p4兩點位于L1的兩側,這樣就可利用外積做出判斷了。分別構造向量s1(p3,p1),s2(p3,p2),如果s1×v2與s2×v2異號(s1->v2與s2->v2轉動的方向相反),則說明p1和p2位于L2的兩側。同理可判定p3和p4是否跨立L1。如果上述四個叉積中任何一個等于0,則說明一條線段的端點在另一條線上。

當判定兩條線段相交后,就可以進行交點的求解了。當然,求交點可以用平面幾何方法,列點斜式方程來完成。但這樣作會難以處理斜率為0的特殊情況,且運算中會出現多次除法,很難保證精度。這里將使用向量法求解。

設交點為(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的常數(若為0,則說明有重合的端點,這種情況在上面已經被排除了)。1式與2式聯系,3式與4式聯立,消去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)

將含有未知數x0和y0的項移到左邊,常數項移動到右邊,得:

(y2-y1)x0+(x1-x2)y0=(y2-y1)x1+(x1-x2)y1

(y4-y3)x0+(x3-x4)y0=(y4-y3)x3+(x3-x4)y3

設兩個常數項分別為b1和b2:

b1=(y2-y1)x1+(x1-x2)y1

b2=(y4-y3)x3+(x3-x4)y3

系數行列式為D,用b1和b2替換x0的系數所得系數行列式為D1,替換y0的系數所得系數行列式為D2,則有:

|D|=(x2-x1)(y4-y3)-(x4-x3)(y2-y1)

|D1|=b2(x2-x1)-b1(x4-x3)

|D2|=b2(y2-y1)-b1(y4-y3)

由此,可求得交點坐標為:

x0=|D1|/|D|,y0=|D2|/|D|

解畢。

C++/STL實現

#include <iostream>#include <cmath>using namespace std;struct POINTF {float x; float y;};bool Equal(float f1, float f2) {  return (abs(f1 - f2) < 1e-4f);}//判斷兩點是否相等bool operator==(const POINTF &p1, const POINTF &p2) {  return (Equal(p1.x, p2.x) && Equal(p1.y, p2.y));}//比較兩點坐標大小,先比較x坐標,若相同則比較y坐標bool operator>(const POINTF &p1, const POINTF &p2) {  return (p1.x > p2.x || (Equal(p1.x, p2.x) && p1.y > p2.y));}//計算兩向量外積float operator^(const POINTF &p1, const POINTF &p2) {  return (p1.x * p2.y - p1.y * p2.x);}//判定兩線段位置關系,并求出交點(如果存在)。返回值列舉如下://[有重合] 完全重合(6),1個端點重合且共線(5),部分重合(4)//[無重合] 兩端點相交(3),交于線上(2),正交(1),無交(0),參數錯誤(-1)int Intersection(POINTF p1, POINTF p2, POINTF p3, POINTF p4, POINTF &Int) {  //保證參數p1!=p2,p3!=p4  if (p1 == p2 || p3 == p4) {    return -1; //返回-1代表至少有一條線段首尾重合,不能構成線段  }  //為方便運算,保證各線段的起點在前,終點在后。  if (p1 > p2) {    swap(p1, p2);  }  if (p3 > p4) {    swap(p3, p4);  }  //判定兩線段是否完全重合  if (p1 == p3 && p2 == p4) {    return 6;  }  //求出兩線段構成的向量  POINTF v1 = {p2.x - p1.x, p2.y - p1.y}, v2 = {p4.x - p3.x, p4.y - p3.y};  //求兩向量外積,平行時外積為0  float Corss = v1 ^ v2;  //如果起點重合  if (p1 == p3) {    Int = p1;    //起點重合且共線(平行)返回5;不平行則交于端點,返回3    return (Equal(Corss, 0) ? 5 : 3);  }  //如果終點重合  if (p2 == p4) {    Int = p2;    //終點重合且共線(平行)返回5;不平行則交于端點,返回3    return (Equal(Corss, 0) ? 5 : 3);  }  //如果兩線端首尾相連  if (p1 == p4) {    Int = p1;    return 3;  }  if (p2 == p3) {    Int = p2;    return 3;  }//經過以上判斷,首尾點相重的情況都被排除了  //將線段按起點坐標排序。若線段1的起點較大,則將兩線段交換  if (p1 > p3) {    swap(p1, p3);    swap(p2, p4);    //更新原先計算的向量及其外積    swap(v1, v2);    Corss = v1 ^ v2;  }  //處理兩線段平行的情況  if (Equal(Corss, 0)) {    //做向量v1(p1, p2)和vs(p1,p3)的外積,判定是否共線    POINTF vs = {p3.x - p1.x, p3.y - p1.y};    //外積為0則兩平行線段共線,下面判定是否有重合部分    if (Equal(v1 ^ vs, 0)) {      //前一條線的終點大于后一條線的起點,則判定存在重合      if (p2 > p3) {        Int = p3;        return 4; //返回值4代表線段部分重合      }    }//若三點不共線,則這兩條平行線段必不共線。    //不共線或共線但無重合的平行線均無交點    return 0;  } //以下為不平行的情況,先進行快速排斥試驗  //x坐標已有序,可直接比較。y坐標要先求兩線段的最大和最小值  float ymax1 = p1.y, ymin1 = p2.y, ymax2 = p3.y, ymin2 = p4.y;  if (ymax1 < ymin1) {    swap(ymax1, ymin1);  }  if (ymax2 < ymin2) {    swap(ymax2, ymin2);  }  //如果以兩線段為對角線的矩形不相交,則無交點  if (p1.x > p4.x || p2.x < p3.x || ymax1 < ymin2 || ymin1 > ymax2) {    return 0;  }//下面進行跨立試驗  POINTF vs1 = {p1.x - p3.x, p1.y - p3.y}, vs2 = {p2.x - p3.x, p2.y - p3.y};  POINTF vt1 = {p3.x - p1.x, p3.y - p1.y}, vt2 = {p4.x - p1.x, p4.y - p1.y};  float s1v2, s2v2, t1v1, t2v1;  //根據外積結果判定否交于線上  if (Equal(s1v2 = vs1 ^ v2, 0) && p4 > p1 && p1 > p3) {    Int = p1;    return 2;  }  if (Equal(s2v2 = vs2 ^ v2, 0) && p4 > p2 && p2 > p3) {    Int = p2;    return 2;  }  if (Equal(t1v1 = vt1 ^ v1, 0) && p2 > p3 && p3 > p1) {    Int = p3;    return 2;  }  if (Equal(t2v1 = vt2 ^ v1, 0) && p2 > p4 && p4 > p1) {    Int = p4;    return 2;  } //未交于線上,則判定是否相交  if(s1v2 * s2v2 > 0 || t1v1 * t2v1 > 0) {    return 0;  } //以下為相交的情況,算法詳見文檔  //計算二階行列式的兩個常數項  float ConA = p1.x * v1.y - p1.y * v1.x;  float ConB = p3.x * v2.y - p3.y * v2.x;  //計算行列式D1和D2的值,除以系數行列式的值,得到交點坐標  Int.x = (ConB * v1.x - ConA * v2.x) / Corss;  Int.y = (ConB * v1.y - ConA * v2.y) / Corss;  //正交返回1  return 1;}//主函數int main(void) {  //隨機生成100個測試數據  for (int i = 0; i < 100; ++i) {    POINTF p1, p2, p3, p4, Int;    p1.x = (float)(rand() % 10); p1.y = (float)(rand() % 10);    p2.x = (float)(rand() % 10); p2.y = (float)(rand() % 10);    p3.x = (float)(rand() % 10); p3.y = (float)(rand() % 10);    p4.x = (float)(rand() % 10); p4.y = (float)(rand() % 10);    int nr = Intersection(p1, p2, p3, p4, Int);    cout << "[(";    cout << (int)p1.x << ',' << (int)p1.y << "),(";    cout << (int)p2.x << ',' << (int)p2.y << ")]--[(";    cout << (int)p3.x << ',' << (int)p3.y << "),(";    cout << (int)p4.x << ',' << (int)p4.y << ")]: ";    cout << nr;    if (nr > 0) {      cout << '(' << Int.x << ',' << Int.y << ')';    }    cout << endl;  }  return 0;}

關于stl,貌似用的不多了,不是過時了,而是有控制的使用,每個項目都有自己的使用場景,根據自己的需要選擇合適的技術。

總結

以上就是本文關于C++/STL實現判斷平面內兩條線段的位置關系代碼示例的全部內容,希望對大家有所幫助。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91在线免费网站| 亚洲福利在线观看| 欧美在线观看一区二区三区| 欧美黄色片在线观看| 久久99国产精品自在自在app| 日本久久久久久久久| 影音先锋欧美在线资源| 69久久夜色精品国产69乱青草| 国产欧美日韩免费| 日韩av成人在线观看| 亚洲精品福利在线| 欧美激情小视频| 国产97在线|亚洲| 人人爽久久涩噜噜噜网站| 久久久久久综合网天天| 日韩欧美第一页| 国内偷自视频区视频综合| 久久久电影免费观看完整版| 久久6免费高清热精品| 欧美色videos| 日韩美女写真福利在线观看| 亚洲国产成人久久综合一区| 欧美裸体男粗大视频在线观看| 久久精品男人天堂| 日韩激情在线视频| 日韩精品视频免费| 国产美女精品视频免费观看| 亚洲а∨天堂久久精品9966| 日本精品中文字幕| 裸体女人亚洲精品一区| 欧美在线一级视频| 91精品国产高清自在线看超| 亚洲永久在线观看| 久久综合久久美利坚合众国| 精品视频久久久| 8x海外华人永久免费日韩内陆视频| 8090成年在线看片午夜| 久青草国产97香蕉在线视频| 欧美亚洲激情在线| 国产亚洲人成a一在线v站| 91久久精品久久国产性色也91| 亚洲欧美日韩天堂| 国内精品久久久久影院优| 国产成人精品视频在线观看| 亚洲精品免费av| 欧美精品999| 亚洲精品一区二区网址| 在线观看欧美视频| 最新亚洲国产精品| 亚洲精品国产拍免费91在线| 国产精品国产亚洲伊人久久| 这里只有精品在线观看| 97热精品视频官网| 中文字幕无线精品亚洲乱码一区| 日韩大陆欧美高清视频区| 国产日韩欧美中文在线播放| 欧美一区二区色| 中文字幕亚洲自拍| 久久伊人精品一区二区三区| 成人羞羞国产免费| 一本大道久久加勒比香蕉| 国产黑人绿帽在线第一区| 91色视频在线观看| 亚洲aaaaaa| 大量国产精品视频| 日韩欧美成人区| 久久综合免费视频| 日韩成人在线视频观看| 国产精品久久久久久久久久东京| 亚洲精品v欧美精品v日韩精品| 国产精品日日做人人爱| 中文欧美在线视频| 欧洲精品毛片网站| 久久中文久久字幕| 欧美激情小视频| 国产欧美日韩中文字幕在线| 日韩欧美在线播放| 久久婷婷国产麻豆91天堂| 俺去亚洲欧洲欧美日韩| 日韩电影中文字幕在线| 欧美老女人性生活| 国产成人午夜视频网址| 久久久黄色av| 久久久中文字幕| 日韩在线免费av| 欧美日韩国产限制| 91久久久久久久久久久| 中文字幕综合一区| 日韩视频免费在线观看| 成人h片在线播放免费网站| 欧美午夜视频一区二区| 国产精品香蕉av| 久久久久中文字幕2018| 在线观看精品自拍私拍| 久久久久久久久亚洲| 欧美国产在线电影| 九九热这里只有在线精品视| 欧美国产日韩一区二区三区| 91免费视频网站| 日韩电影免费观看中文字幕| 国内伊人久久久久久网站视频| 国产精品福利网| 亚洲精品黄网在线观看| 91超碰中文字幕久久精品| 久久久久国产精品免费| 中文字幕综合一区| 正在播放欧美一区| 日韩激情第一页| 精品国内亚洲在观看18黄| 国产精品白嫩初高中害羞小美女| 亚洲第一福利网站| 欧美精品在线免费播放| 日韩精品在线观看一区二区| 97超碰蝌蚪网人人做人人爽| 欧美国产视频一区二区| 亚洲成人黄色网| 欧美在线视频播放| 亚洲综合日韩中文字幕v在线| 亚洲激情视频在线| 97精品一区二区视频在线观看| 深夜福利国产精品| 2018日韩中文字幕| 日韩一区二区三区xxxx| 亚洲第一av网站| 91丝袜美腿美女视频网站| 成人午夜激情免费视频| 色综合91久久精品中文字幕| 国产亚洲精品久久久| 亚洲va男人天堂| 国产91成人video| 九九九热精品免费视频观看网站| 992tv在线成人免费观看| 国产mv免费观看入口亚洲| 日韩美女视频中文字幕| 国产成人精品亚洲精品| 国产丝袜视频一区| 在线精品播放av| 欧美电影《睫毛膏》| 国产视频精品自拍| 91国偷自产一区二区三区的观看方式| 亚洲国产天堂久久综合| 久久99精品久久久久久噜噜| 成人免费激情视频| 国产人妖伪娘一区91| 在线一区二区日韩| 动漫精品一区二区| 91美女高潮出水| 九九热这里只有精品6| 亚洲xxx视频| 久久天天躁狠狠躁夜夜爽蜜月| 综合激情国产一区| 亚洲乱码国产乱码精品精天堂| 日韩在线视频中文字幕| 亚洲专区国产精品| 亚洲精品国产欧美| 色综合天天狠天天透天天伊人| 欧美午夜丰满在线18影院| 97涩涩爰在线观看亚洲| 国产精品777| 尤物yw午夜国产精品视频| 国产精品久久久久久久9999| 亚洲老头同性xxxxx| 久久999免费视频| 成人在线小视频|