# voronoi diagram > 張恩維 ## 軟體規格書 * 輸入 1. 滑鼠在畫布上任意點擊,畫布大小為603*603 2. 輸入x軸及y軸座標 3. 隨機產生數個點 4. 讀入「輸入文字檔」 5. 讀入「輸出文字檔」,直接在畫布繪出圖形 * 輸出 1. 按下Save,輸出「輸出文字檔」 2. 輸出文字檔格式如下: 3. 輸入的座標點:P x y // 每個點佔一行,兩整數 x, y 為座標。 線段:E x1 y1 x2 y2 // (x1, y1) 為起點,(x2, y2) 為終點,其中 x1≦x2 或 x1=x2, y1≦y2 4. 座標點排列在前半段,線段排列在後半段。 5. 座標點以 lexical order順序排列(即先排序第一維座標,若相同,則再排序第二維座標;線段亦以lexical order順序排列。 ### 功能規格與介面規格 #### 主畫面 ![](https://i.imgur.com/2iOr8nK.png) #### 功能介紹 * Read Data : 輸入檔案 * Run : 開始執行 * Save : 輸出檔案 * Next set : 下一筆測資 * Clean : 清除畫布 * step by step : 執行下一步 ## 軟體說明 ### 安裝說明 下載後直接執行exe檔即可。 ### 使用說明 * 提供兩種方法輸入 1. 直接在畫布上利用滑鼠點擊 2. 以符合輸入規範的檔案(.txt)當作輸入 * 以兩種方式繪製 1. 按下"run"按鈕,一次畫完diagram. 2. 按下"step by step"按鈕,直到畫完diagram. ![](https://i.imgur.com/4KDHdM1.png) ![](https://i.imgur.com/BZtDzKd.png) * 提供一種方式輸出 1. 按下save,輸出.txt檔 ![](https://i.imgur.com/Spr6P3v.png) ## 程式設計 ### 資料結構 ![](https://i.imgur.com/KrSW0Zh.png) ↑用於divide and conquer時 ![](https://i.imgur.com/q6R7m5p.png) ↑存點的結構 ![](https://i.imgur.com/K2zdkeF.png) ↑存邊的結構 ![](https://i.imgur.com/BqP5wVU.png) ↑hyperplane的結構 ### 三點以下 利用重心公式,(a+b+c)/3,而重心一定在三角形的內部,在利用重心到各點的向量進行逆時針的排序,這樣一來可以確定法向量一定是朝外射出,接著再找到到三角形的外心,再由外心向法向量的方向畫出即可完成。在特別注意一下三點共線的情空即可。 ![](https://i.imgur.com/u1Ovubq.png) ### 四點 ``` def voronoi(pointList): pointList.sort(key = attrgetter('x', 'y')) # 先對 x 排序在對 y 排序 if(len(pointList) == 1 ): return elif(len(pointList) == 2): result = two_point(pointList) else: p_left , p_right = divide(pointList) v_left = voronoi(p_left) # 得到 左邊的voronoi diagram v_right = voronoi(p_right) # 得到 右邊的voronoi diagram result = merge(v_left, v_right) #合併整個 voronoi diagram return result # return 整個voronoi diagram ``` * Divide 其實就先將座標點先依X軸再依Y軸排序後,在將一半的的點分給左邊和右邊, 之後在以遞迴的方式下去作就可以了,中止條件是到兩個點後在兩點中間畫一條線。 * Merge 第一步要做的就是找出上切線及下切線,作為下一步找Hyper Plane 的進入點及離開點。而切線的找法就是畫出整個的Convex Hull,然後逐一掃瞄Convex Hull上鄰近的兩個點,當兩個點分別屬於左右半部的點,該線段即為我們要找的切線。而找Convex Hull 的演算法,是Andrew's Monotone Chain找到上凸包以及下凸包。在分別判斷merge後的voronoi diagram的點的convex hull分別位於在還沒merge之前兩邊凸包即可。 ![](https://i.imgur.com/dAJMtk5.png) * Hyperplane hyperplane 就是將convex hull 左右兩邊的點找出來並一步一步的往下去找,如果以hyperplane 的中垂線撞到的的中垂線,則構成hyperplane的兩點更新為那兩點,直到所有點構成的convex hull 下切線 == hyperplane,diagram 完成。 ![](https://i.imgur.com/KEQuAqa.png) ## 軟體測試與實驗結果 ### 執行環境 * 程式語言:python * 作業系統:windows 11 ![](https://i.imgur.com/kOjEZOm.png) ### 實驗結果 ![](https://i.imgur.com/0Zd2pmC.png) ![](https://i.imgur.com/5M5D45H.png) ![](https://i.imgur.com/Eeaulhw.png) ![](https://i.imgur.com/9RZaV9S.png) ![](https://i.imgur.com/4Mx9MdA.png) ![](https://i.imgur.com/IBjhvXv.png) ![](https://i.imgur.com/dP3AQP5.png) ## 結論與心得 原本是想要用c++來寫的,但因為沒用過Qt4,所以改用難度教低的python完成。 ## 附錄 我的github 程式碼都在這 https://github.com/wayne9756/voronoi-diagram.git