Voronoi圖和Delaunay三角形和凸包

來源:互聯網
上載者:User

標籤:處理過程   ...   超過   程式   斷點   時間   str   代碼   第一個   

 寫一下最近寫的一點東西...

最近在上演算法課,上課老師講到了維諾圖,自己覺得很有意思就研究了一下,並用java寫了一個簡單的se程式用來顯示維諾圖和Delaunay三角形還有凸包。

首先介紹一下凸包,凸包在數學裡是很常見的,給定一些點,然後找出包含這些的最小凸包,一般是這麼做的。至於凸包的定義維基百科或者百度都行,自己查一查就知道,通俗的講就是延長每一條邊,剩下的圖形總在邊的一邊。

(介面有點醜)

這邊給出一下我程式運行出來的凸包

 

然後是Delaunay三角形,這個三角形是這樣的,可以在凸包裡面進行插入點,然後串連各個節點和插入點,然後會形成三角形,再插入還會再次分割三角形,並且形成的三角形是不包括第四個點的。

Voronoi圖在上述三角形的基礎上求得每一個三角形外接圓的圓心,串連各個這樣的圓心可以得到這麼一個voronoi圖。

 

 

好了這是我的效果展示圖,具體代碼我上傳到Github上供大家學習參考,有些一點注釋,但因為寫的比較匆忙不是寫的很詳細,大家有問題可以一起討論討論。

Github地址:https://github.com/monster5475/JAVACore/tree/master/

接下來說一下我做這個過程中遇到的一些問題和一些事情,首先要感謝一下給我協助蠻多的幾篇部落格。

https://www.cnblogs.com/zhiyishou/p/4430017.html 這篇主要講三角形的切割形成

50808360 這篇主要講用graphScan的方法形成的凸包

48208983 這是一個參考部落格。

52244123 這是我主要參考的,按照實現的部落格,這個部落格寫的挺好的,我基本參考這個思路走的。

忘了補充一下Bowyer-Watson演算法,我還查看《基於Bowyer_Watson三角網產生演算法的研究_周雪梅》這篇文章中的一些虛擬碼。

真的是前人栽樹,後人乘陰,感謝前輩!

現在來介紹一下主要思路

(1)首先是java表單設計,以及一些按鈕的綁定什麼的,畫圖,大概一天完成的,表單畫圖有點忘了。

(2)然後是第一步隨機產生點函數,這個沒什麼難度,主要要注意不要產生重複點,然後不要超過邊界。(一開始以為會存在畫圖x y和現實中x y的差距,後來發現不用考慮)

(3)得到一個point的arraylist,先找到y最低點,得到一個扇形圖類似如此

然後p0就一定是凸包上的一個點,p1點也必定是凸包上的一點,然後將這兩個點進棧,開始判斷其他點,這邊首先要瞭解一下叉乘的概念,向量a叉乘向量b,得到的結果向量是垂直於向量a和b組成的平面,方向是根據a和b的叉乘的順序根據右手法則判斷的,那麼我們就可以通過叉乘的結果的正負來確定點的位置比如在向量p0p1 和向量p1p2的叉乘中(注意叉乘首先要讓兩個向量是同一個起點),根據右手法則得到的就是一個垂直紙面向外的向量,那麼就可以說明點p2在向量p0p1的逆時針一邊。如果p2在p0p1在的順時針一邊,則叉乘結果應該是垂直紙面向內的向量。根據這一點,我們就可以一個一個判斷,比如p0p1判斷完p2是我們要的點,那麼進棧,這個時候棧中元素為(p0,p1,p2)p2位棧頂元素,這時候我們再串連p2p3,用向量p1p2(棧頂的兩個點)叉乘p2p3,發現結果向量垂直紙面向內,那麼點p3是在p1p2的順時針的方向,那麼就跟我們凸包的定義出錯,因為我們在之前說了凸包上的所有點會在邊的同一側,現在p3在順時針一邊,p0在逆時針一邊,所以p2不是凸包上的一點,將p2出棧,p3入棧,如此如此 直到最後。。這個是Graham掃描法,因為我們一開始選定是從逆時針方向,所以判斷的時候相關,當然我們也可以選擇順時針方向,那時候我們就是從p12 p11那邊算起,那時候我們就要判斷點是否在當前棧的兩個點組成的邊的順時針方向。

(4)然後我們得到了這些點組成的凸包,現在我們將要進行Delaunay三角形的構造,我一開始是確定用Bowyer-Watson演算法進行產生,但是在其中第二步的時候我有些疑惑,後來自己想了一種辦法解決,不知道是否有漏洞,但是畫圖畫出來倒是都ok的,我這邊拷貝一下上面連結中一個博主發的話

Delaunay剖分是一種三角剖分的標準,實現它有多種演算法。本次採用Bowyer-Watson演算法,演算法的基本步驟是:
(1)構造一個超級三角形,包含所有散點,放入三角形鏈表。
(2)將點集中的散點依次插入,在三角形鏈表中找出其外接圓包含
插入點的三角形(稱為該點的影響三角形),刪除影響三角形的公用邊,將插入點同影響三角形的全部頂點串連起來,從而完成一個點在Delaunay三角形鏈表中的插入。
(3)根據最佳化準則對局部新形成的三角形進行最佳化。將形成的三角形放入Delaunay三角形鏈表。
(4)迴圈執行上述第2步,直到所有散點插入完畢。

關鍵步驟2如所示:

步驟3的局部最佳化的準則指的是:
1.對新形成的三角形進行最佳化,將兩個具有共同邊的三角形合成一個多邊形。
2.以最大空圓準則作檢查,看其第四個頂點是否在三角形的外接圓之內。
3.如果在,修正對角線即將對角線對調,即完成局部最佳化過程的處理。

LOP (Local Optimization Procedure)處理過程如所示:

---------------------本文來自 Dablelv 的CSDN 部落格 ,全文地址請點擊:52244123?utm_source=copy 

我這邊疑惑的是第二步中怎麼去“刪除影響三角形的公用邊,將插入點同影響三角形的全部頂點串連起來”,後來在寫代碼中想到了一種方法,我現在在這裡進行一下說明,首先我們得到了凸包,現在我們在凸包中插入一個點,那麼怎麼進行三角形的劃分呢?是不是直接拿各個凸包的點和插入點串連就可以完成了三角形的劃分,得到一個Triangles,然後我們現在進行第二個點的插入,我們檢測Triangle的外接圓發現這個點在三個三角形內,我們稱這三個三角形是受影響的三角形,我們可以判斷這三個三星形是連在一起的,我們將這三個三角形從Triangles中刪除,並用這三個三角形的邊形成了一個多邊形,然後這個插入點就在這個多邊形中間,這是不是就是變成我們插入第一個點的情況。。我們只需串連各個點與插入點就可以得到全新的三星形集合,加入Triangles即可。這邊還值得注意的是局部最佳化修正過程,一開始不是很理解這個情況,後來自己想了一下這種情況應該是要避免外接圓中的剛好兩個點是直徑的情況然後第四個點在園內,要修改對角線,形成小的外接圓,將其中一個點分叉出去。

等以上工作全部做完以後你就可以得到一個Triangles的列表,畫出來就可以

(5)最後一步是維諾圖的建立,其實維諾圖的建立在Delaunay三角形上就已經很方便了,只要找出上一步的各個Triangle的外接圓圓心,然後將具有共同邊的外接圓圓心串連起來就可以得到我們需要的初步維諾圖,還有的是值得注意的是維諾圖中存在一些射線。我就是在畫圖過程中被這些射線搞得煩死了。只有真正有畫圖的需求才知道射線好難決定。。我也說不清楚,如果按我寫的代碼中我處理很複雜,雖然是畫出來了,但是還有一點點問題。可能有時候會失效。。

上面就是我寫這個小項目的過程,其中用了一些java8的stream特性,覺得java8還挺好用的。。加油加油。

 

下面放幾個類的小,給也想要試一下你的一些感覺,當然你可以去看看My Code。如果覺得我還可以的,麻煩給我Github的項目小星星~~~

這是主要演算法類:Algorithm

這是Edge的類 主要重寫了equals和tostring

這是表單類

 

 這是畫板類

 

 稍微貼幾張圖,具體可以去看代碼~~~

這是自己實現的一個代碼,發現網上資料有是有,但是沒看到一個真正可以跑起來的,自己做一個例子happy一下,額~這個大概用了我五天的時間去寫完。當然是斷斷續續,因為最近也在上課了。

 

Voronoi圖和Delaunay三角形和凸包

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.