算法 & 數(shù)據(jù)結構——多邊形填充

在很多圖形相關的編輯器里都會有選區(qū)功能达布,有的只能按某種固定形狀選擇,比如:矩形逾冬,圓形……,有的可以按任意形狀選擇粉渠,有的甚至可以分析圖片自動選區(qū)(例如:Photoshop魔法棒工具),今天來說說任意形狀選區(qū)怎么實現(xiàn)霸株。

通過鼠標描點,再用線段連接集乔,組合成一個幾何選區(qū)去件,這看似沒有難度扰路,它實際上……的確沒有難度。如果要填充選區(qū)內(nèi)部汗唱,這就有一丟丟難度(至少很久前我被這個問題困住很久)。

計算機圖形接口

在計算機里授霸,圖片普遍都是矩形的际插,當渲染一張圖片到屏幕時,這張圖片會被拆成兩個三角形框弛,這兩個三角形將圖片斜角對折切開,然后提交到渲染管道斗搞,而這個渲染管道則由顯卡接管慷妙。

至于為什么會被拆成三角形,因為計算機3D渲染技術已經(jīng)非常成熟景殷,而3D渲染完全可以渲染2D圖像澡屡,因此顯卡只需要按3D渲染的架構設計就可以了驶鹉,但是铣墨,3D圖形比2D圖形復雜的多,因為2D形狀統(tǒng)統(tǒng)都可以在一個矩形的圖片上畫出來伊约,而3D要顯示一個形狀需要模型姚淆,而怎么構建這個模型就成了問題屡律。例如:立方體模型,六個面搏讶,那可以用六個正方形來構建霍殴。但是球形或更復雜的模型,純用正方形去拼湊完全不可能妒蔚,因此這可能需要各種各樣的形狀月弛,從而導致非常凌亂。如果有一種圖元可以拼湊出任意形狀的模型尊搬,那一切都完美,三角形正是這樣的圖元幌墓,它雖然不能完美拼湊任意形狀的模型冀泻,卻可以在硬件允許的情況下無限近似任意形狀的模型。當前流行的顯卡通常只支持三角形硬件加速胳施,聽說俄羅斯還有人搞圓形硬件加速的肢专?
上面大概已經(jīng)說明三角形和渲染管道的關系了焦辅,下面進入正題椿胯。

閉合路徑

要填充一個不規(guī)則的選區(qū),要把它拆分成多個三角形前方,而怎么拆分成三角形就是問題所在廉油。

任意形狀選區(qū)

在拆分三角形之前,需要計算出選區(qū)內(nèi)包含的所有閉合路徑班巩,因為一個選區(qū)可能會有多個閉合路徑十兢,就像上圖顯示,選區(qū)包含了兩個閉合路徑,要填充這兩個閉合路徑.

選區(qū)的數(shù)據(jù)結構是一組頂點列表[p0, p1, p2...pN]
從 p2 開始遍歷:
pi -> p(i+1) 正好構成一條線段卫袒,將這條線段與前面的線段做相交檢測,一旦相交宝穗,則說明此時遇到了一個閉合路徑.
記錄交點CrossP码秉,
記錄交點線段的起點CrossA,
記錄交點線段的終點CrossB.
[CrossP, CrossB, ..., pi] 頂點列表則是該閉合路徑.
隨后將這個閉合路徑的頂點列表從原始頂點列表中剔除须鼎,并將CrossP插入到CrossB的位置.
直到把原始頂點列表遍歷完畢府蔗,則所有的閉合路徑都被計算出來了.

三角形切割

已經(jīng)得到了所有的閉合路徑,接下來就可以切割三角形了.這非常容易赡译,因為每一個閉合路徑都是一個多邊形不铆,只需要求得這個多邊形的中點裹唆,再從中點依次連接到各個頂點就可以了.

切割三角形

從圖中可以清楚的看到閉合路徑的中心只洒,以及從中心連接到各個頂點的線段,因為圖中的閉合路徑只有四個頂點舞吭,因此只需要切割四個三角形就足夠了.
計算多邊形中心的公式:

(p[i] + p[i+1] + p[N]) / N

如果一切都是這么容易析珊,那活著就舒坦了,幾何學告訴我們惧浴,上述算法并不是總是湊效.

凹多邊形切割

凹多邊形閉合路徑

從圖中可以看出奕剃,閉合路徑只有一個,但這個路徑是凹多邊形柿顶,按上述的方法求得中心很可能在多邊形外面操软,連接出來的三角形并不正確.需要先把凹多邊形切割成凸多邊形,這非常容易.

只需要在多邊形的凹點處家乘,延伸出一條線段藏澳,連接到最近的邊,這條線段作為交界翔悠,劃分出兩個多邊形,再分別將這兩個多邊形重復此步驟腻要,直到?jīng)]有凹點涝登,則這個多邊形是凸多邊形.

首先需要知道如何判斷一個多邊形是凹的還是凸的.
以左上角為原點的2D坐標系來說.

當一個順時針排列的多邊形,某一條邊往左拐趟济,這個多邊形是凹多邊形.
當一個逆時針排列的多邊形,某一條邊往右拐顷编,這個多邊形是凹多邊形.
計算邊的拐向很容易媳纬,只要判斷兩條邊的向量積符號是正是負就行了.
//    向量拐向公式
//    具體拐向跟坐標系有關,在本例中钮惠,順時針排列,向量積小于零是左拐.
Cross(p0p1, p1p2) < 0? "左拐?右拐?": "左拐?右拐?"

因為頂點順序是隨機的蔑赘,因此可能是順時針排列也可能是逆時針排列预明,所以要先計算出這個多邊形的排列順序,計算思路非常容易:
只需要遍歷多邊形頂點酥馍,對所有邊計算拐向阅酪,如果左拐向多余右拐向,則是逆時針排列,否則是順時針排列.

float Cutting::Polygon::CheckOrder(const math::Points & points)
{
    auto order0 = 0;    //  順時針
    auto order1 = 0;    //  逆時針
    for (auto i = 0; i != points.size(); ++i)
    {
        auto & a = points.at(INDEX(i    , points.size()));
        auto & b = points.at(INDEX(i + 1, points.size()));
        auto & c = points.at(INDEX(i + 2, points.size()));
        if (CheckOrder(a, b, c) < 0)
        {
            ++order1;
        }
        else
        {
            ++order0;
        }
    }
    return order0 > order1 ? 1.0f : -1.0f;
}

整個算法到這就結束了术吗,下圖是凹多邊形切割后的形狀帆精,很容易發(fā)現(xiàn),多了幾根線段卓练,這些線段正是切分成凸多邊形的線段,而閉合路徑也由1個變成了3個嘱么,再用上述的方法計算三角形就容易多了.

切割凹多邊形
填充選區(qū)

效果展示

png
png
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末几迄,一起剝皮案震驚了整個濱河市冰评,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌解孙,老刑警劉巖抛人,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異娱据,居然都是意外死亡盅惜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門结啼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屈芜,“玉大人,你說我怎么就攤上這事属铁」蹋” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵例嘱,是天一觀的道長宁舰。 經(jīng)常有香客問我,道長蛮艰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任低葫,我火速辦了婚禮,結果婚禮上实柠,老公的妹妹穿的比我還像新娘善涨。我一直安慰自己,他們只是感情好蟹漓,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布源内。 她就那樣靜靜地躺著,像睡著了一般嗽交。 火紅的嫁衣襯著肌膚如雪颂斜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天盒让,我揣著相機與錄音司蔬,去河邊找鬼。 笑死俊啼,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播炒辉,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼黔寇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颊郎,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤姆吭,失蹤者是張志新(化名)和其女友劉穎唁盏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厘擂,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡刽严,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了眨补。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹏氧。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖实蓬,靈堂內(nèi)的尸體忽然破棺而出吊履,到底是詐尸還是另有隱情,我是刑警寧澤艇炎,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布缀踪,位于F島的核電站,受9級特大地震影響驴娃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔗草,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望镶柱。 院中可真熱鬧模叙,春花似錦、人聲如沸向楼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昭抒。三九已至,卻和暖如春灭返,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背罚缕。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工邮弹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腌乡。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像兔簇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蹦肴,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 對于三月冗尤,我總是懷有一種別樣的感覺。三月的天空不再如二月般晦澀皆看,潤濕的空氣,夾雜著早春泥土的芳香腰吟,迎春花的氣息徙瓶,迎...
    記憶的抽象畫閱讀 279評論 0 0
  • ZaleJ閱讀 225評論 0 0
  • 今天小編在逛貼吧時偶然看到一條帖子的標題十分醒目壳繁,名為“直播,上男朋友的貼吧號蒿赢,然后直播封他所有的lol號渣触!“ 作...
    f伐木累閱讀 214評論 0 0
  • 媽媽 多么親切的字眼 心中最溫暖的港灣 給予了我們寶貴的生命 無微不至地呵護孩子成長 孩子是她的心頭肉、眼中寶 老...
    淺陌心語閱讀 226評論 0 0
  • 凡心所向灼擂,素履以往觉至,生如逆旅,一葦以航语御。 時間很慢,慢的讓我們開始疲倦纤控,暢想著充滿未知的明天碉纺,時間很快船万,快的令我們...
    田仁雲(yún)閱讀 376評論 1 6