https://www.cnblogs.com/little-w/p/3579603.html
轉自:http://blog.csdn.net/acmaker/article/details/3188177
1、目錄
一些歷史:
1978年, M.I. Shamos's Ph.D. 的論文"Computational Geometry"標誌着計算機科學的這一領域的誕生。 當時他發表成果的是一個尋找凸多邊形直徑的一個很是簡單的算法, 即根據多邊形的一對點距離的最大值來肯定。後來直徑演化爲由一對對踵點對來肯定。 Shamos提出了一個簡單的 O(n) 時間的算法來肯定一個凸 n 角形的對踵點對。 由於他們最多隻有 3n/2 對, 直徑能夠在 O(n) 時間內算出。
如同Toussaint後來提出的, Shamos的算法就像繞着多邊形旋轉一對卡殼。 所以就有了術語「旋轉卡殼」。 1983年, Toussaint發表了一篇論文, 其中用一樣的技術來解決許多問題。 今後, 基於此模型的新算法就確立了, 解決了許多問題。
他們包括:
- 計算距離
- 凸多邊形直徑
- 凸多邊形寬
- 凸多邊形間最大距離
- 凸多邊形間最小距離
- 外接矩形
- 最小面積外接矩形
- 最小周長外接矩形
- 三角剖分
- 洋蔥三角剖分
- 螺旋三角剖分
- 四邊形剖分
- 凸多邊形屬性
- 合併凸包
- 找共切線
- 凸多邊形交
- 臨界切線
- 凸多邊形矢量和
- 最薄截面
- 最薄橫截帶
2、計算距離
1.凸多邊形直徑
咱們將一個多邊形上任意兩點間的距離的最大值定義爲多邊形的直徑。 肯定這個直徑的點對數可能多於一對。 事實上, 對於擁有 n 個頂點的多邊形, 就可能有 n 對「直徑點對」存在。
一個多邊形直徑的簡單例子如左圖所示。 直徑點對在圖中顯示爲被平行線穿過的黑點 (紅色的一對平行線). 直徑用淺藍色高亮顯示。html
顯然, 肯定一個凸多邊形 P 直徑的點對不可能在多邊形 P 內部。 故搜索應該在邊界上進行。 事實上, 因爲直徑是由多邊形的平行切線的最遠距離決定的, 因此咱們只須要查詢對踵點。 Shamos (1978) 提供了一個 O(n) 時間複雜度計算n點凸包對踵點對的算法。直徑經過遍歷頂點列表, 獲得最大距離便可。 以下是1985年發表於 Preparata 和 Shamos 文章中的 Shamos 算法的僞代碼。
輸入是一個多邊形 P={p1,...,pn}.
begin p0:=pn; q:=NEXT[p]; while (Area(p,NEXT[p],NEXT[q]) > Area(p,NEXT[p],q)) do q:=NEXT[q]; q0:=q; while (q != p0) do begin p:=NEXT[p]; Print(p,q); while (Area(p,NEXT[p],NEXT[q]) > Area(p,NEXT[p],q) do begin q:=NEXT[q]; if ((p,q) != (q0,p0)) then Print(p,q) else return end; if (Area(p,NEXT[p],NEXT[q]) = Area(p,NEXT[p],q)) then if ((p,q) != (q0,p0)) then Print(p,NEXT[q]) else Print(NEXT[p],q) end end.此處
Print(p,q)
表示將 (p,q) 做爲一個對踵點對輸出, Area(p,q,r)
表示三角形 pqr 的有向面積。 雖然直觀上看這個過程與常規旋轉卡殼算法不一樣, 但他們在本質上是相同的, 而且避免了全部角度的計算。
以下是一個更直觀的算法:
- 計算多邊形 y 方向上的端點。 咱們稱之爲 ymin 和 ymax 。
- 經過 ymin 和 ymax 構造兩條水平切線。 因爲他們已是一對對踵點, 計算他們之間的距離並維護爲一個當前最大值。
- 同時旋轉兩條線直到其中一條與多邊形的一條邊重合。
- 一個新的對踵點對此時產生。 計算新的距離, 並和當前最大值比較, 大於當前最大值則更新。
- 重複步驟3和步驟4的過程直到再次產生對踵點對 (ymin,ymax) 。
- 輸出肯定最大直徑的對踵點對。
2. 凸多邊形的寬度
咱們假設存在一個線段 [a,b], 以及兩條經過 a 和 b 的平行線。 經過繞着這兩個點旋轉這兩條線, 使他們之間的距離遞增或遞減。 特別的, 總存在一個 特定旋轉方向 使得兩條線之間的距離經過旋轉變小。
這個簡單的結論能夠被應用於寬度的問題中: 不是全部的方向都須要考慮。 假設給定一個多邊形, 同時還有兩條平行切線。 若是他們都未與邊重合, 那麼咱們總能經過旋轉來減少他們之間的距離。 所以, 兩條平行切線只有在其中至少一條與邊重合的狀況下才可能肯定多邊形的寬度。
這就意味着「對踵點 點-邊」以及「邊-邊」對須要在計算寬度過程當中被考慮。

一個凸多邊形寬度的示意圖。 直徑對如圖由平行切線(紅線)穿過的黑點所示。 直徑如高亮的淡藍色線所示。算法
一個與計算直徑問題很是類似的算法能夠經過遍歷多邊形對踵點對列表獲得, 肯定頂點-邊以及邊-邊對來計算寬度。 選擇過程以下:
- 計算多邊形 y 方向上的端點。 咱們稱之爲 ymin 和 ymax。
- 經過 ymin 和 ymax 構造兩條水平切線。若是一條(或者兩條)線與邊重合, 那麼一個「對踵點 點-邊」對或者「邊-邊」對已經確立了。 此時, 計算兩線間的距離, 而且存爲當前最小距離。
- 同時旋轉兩條線直到其中一條與多邊形的一條邊重合。
- 一個新的「對踵點 點-邊」對(或者當兩條線都與邊重合,「邊-邊」對)此時產生。 計算新的距離, 並和當前最小值比較, 小於當前最小值則更新。
- 重複步驟3和步驟4(卡殼)的過程直到再次達到最初平行邊的位置。
- 將得到的最小值的對做爲肯定寬度的對輸出。
更爲直觀的算法再次由於須要引進角度的計算而體現出其不足。 然而, 就如在凸多邊形間最大距離問題中同樣, 有時候更爲簡單、直觀的旋轉卡殼算法必須被引入計算。學習
3.凸多邊形間最大距離
給定兩個凸多邊形 P 和 Q, 目標是須要找到點對 (p,q) (p 屬於 P 且 q 屬於 Q) 使得他們之間的距離最大。
很直觀地,這些點不可能屬於他們各自多邊形的內部。 這個條件事實上與直徑問題很是類似:
兩凸多邊形 P 和 Q 間最大距離由多邊形間的對踵點對肯定。
雖說法同樣, 可是這個定義與給定凸多邊形的對踵點對的不一樣。
與凸多邊形間的對踵點對本質上的區別在於切線是有向且反向的。 下圖展現了一個例子:
上述結論暗示不單純只是頂點對須要檢測, 而僅僅是特定的頂點對須要被考慮到。 事實上他們只檢測一個基於旋轉卡殼模式的算法確立的平行切線。
考慮以下的算法, 算法的輸入是兩個分別有 m 和 n 個順時針給定頂點的凸多邊形 P 和 Q。測試
- 計算 P 上 y 座標值最小的頂點(稱爲 yminP ) 和 Q 上 y 座標值最大的頂點(稱爲 ymaxQ)。
- 爲多邊形在 yminP 和 ymaxQ 處構造兩條切線 LP 和 LQ 使得他們對應的多邊形位於他們的右側。 此時 LP和 LQ 擁有不一樣的方向, 而且 yminP 和 ymaxQ 成爲了多邊形間的一個對踵點對。
- 計算距離(yminP,ymaxQ) 而且將其維護爲當前最大值。
- 順時針同時旋轉平行線直到其中一個與其所在的多邊形的邊重合。
- 一個新的對踵點對產生了。 計算新距離, 與當前最大值比較, 若是大於當前最大值則更新。 若是兩條線同時與邊發生重合, 此時總共三個對踵點對(先前頂點和新頂點的組合)須要考慮在內。
- 重複執行步驟4和步驟5, 直到新的點對爲(yminP,ymaxQ)。
- 輸出最大距離。
旋轉卡殼模式確保了全部的對踵點對都被考慮到。 此外, 整個算法擁有線性的時間複雜度, 由於(除了初始化), 執行步數與頂點數相同。
相似的算法能夠被用於凸多邊形間最小距離問題中。ui
4.凸多邊形間最小距離
給定兩個非鏈接(好比不相交)的凸多邊形 P 和 Q, 目標是找到擁有最小距離的點對 (p,q) (p 屬於 P 且 q 屬於Q)。事實上, 多邊形非鏈接十分重要, 由於咱們所說的多邊形包含其內部。 若是多邊形相交, 那麼最小距離就變得沒有意義了。 然而, 這個問題的另外一個版本, 凸多邊形頂點對間最小距離對於相交和非相交的狀況都有解存在。
回到咱們的主問題: 直觀的, 肯定最小距離的點不可能包含在多邊形的內部。 與最大距離問題類似, 咱們有以下結論:
兩個凸多邊形 P 和 Q 之間的最小距離由多邊形間的對踵點對確立。 存在凸多邊形間的三種多邊形間的對踵點對, 所以就有三種可能存在的最小距離模式:
- 「頂點-頂點」的狀況
- 「頂點-邊」的狀況
- 「邊-邊」的狀況
換句話說, 肯定最小距離的點對不必定必須是頂點。 下面的三個圖例代表了以上結論:



給定結果, 一個基於旋轉卡殼的算法天然而然的產生了:
考慮以下的算法, 算法的輸入是兩個分別有 m 和 n 個順時針給定頂點的凸多邊形 P 和 Q。
- 計算 P 上 y 座標值最小的頂點(稱爲 yminP ) 和 Q 上 y 座標值最大的頂點(稱爲 ymaxQ)。
- 爲多邊形在 yminP 和 ymaxQ 處構造兩條切線 LP 和 LQ 使得他們對應的多邊形位於他們的右側。 此時 LP和 LQ 擁有不一樣的方向, 而且 yminP 和 ymaxQ 成爲了多邊形間的一個對踵點對。
- 計算距離(yminP,ymaxQ) 而且將其維護爲當前最小值。
- 順時針同時旋轉平行線直到其中一個與其所在的多邊形的邊重合。
- 若是隻有一條線與邊重合, 那麼只須要計算「頂點-邊」對踵點對和「頂點-頂點」對踵點對距離。 都將他們與當前最小值比較, 若是小於當前最小值則進行替換更新。 若是兩條切線都與邊重合, 那麼狀況就更加複雜了。 若是邊「交疊」, 也就是能夠構造一條與兩條邊都相交的公垂線(但不是在頂點處相交), 那麼就計算「邊-邊」距離。 不然計算三個新的「頂點-頂點」對踵點對距離。 全部的這些距離都與當前最小值進行比較, 若小於當前最小值則更新替換。
- 重複執行步驟4和步驟5, 直到新的點對爲(yminP,ymaxQ)。
- 輸出最大距離。
最小距離和最大距離的問題代表了旋轉卡殼模型能夠用在不一樣的條件下(與先前的直徑和寬度問題比較)。 這個模型能夠應用於兩個多邊形的問題中。
「最小盒子」問題(最小面積外接矩形)經過同一多邊形上兩個正交切線集合展現了另外一種條件下旋轉卡殼的應用。
3、外接矩形
1.凸多邊形最小面積外接矩形
給定一個凸多邊形 P , 面積最小的能裝下 P (就外圍而言)的矩形是怎樣的呢? 從技術上說, 給定一個方向, 能計算出 P 的端點而且構由此造出外接矩形。 可是咱們須要測試每一個情形來得到每一個矩形來計算最小面積嗎? 謝天謝地, 咱們沒必要那麼幹。
對於多邊形 P 的一個外接矩形存在一條邊與原多邊形的邊共線。
上述結論有力地限制了矩形的可能範圍。 咱們不只沒必要去檢測全部可能的方向, 並且只須要檢測與多邊形邊數相等數量的矩形。
spa
圖示上述結論: 四條切線(紅色), 其中一條與多邊形一條邊重合, 肯定了外接矩形(藍色)。.net
一個簡單的算法是依次將每條邊做爲與矩形重合的邊進行計算。 可是這種構造矩形的方法涉及到計算多邊形每條邊端點, 一個花費 O(n) 時間(由於有 n 條邊)的計算。 整個算法將有二次時間複雜度。
一個更高效的算法已經發現。 利用旋轉卡殼, 咱們能夠在常數時間內實時更新, 而不是從新計算端點。
實際上, 考慮一個凸多邊形, 擁有兩對和 x 和 y 方向上四個端點相切的切線。 四條線已經肯定了一個多邊形的外接矩形。 可是除非多邊形有一條水平的或是垂直的邊, 這個矩形的面積就不能算入最小面積中。
然而, 能夠經過旋轉線直到條件知足。 這個過程是下屬算法的核心。 假設按照順時針順序輸入一個凸多邊形的n 個頂點。 設計
- 計算所有四個多邊形的端點, 稱之爲 xminP, xmaxP, yminP, ymaxP。
- 經過四個點構造 P 的四條切線。 他們肯定了兩個「卡殼」集合。
- 若是一條(或兩條)線與一條邊重合, 那麼計算由四條線決定的矩形的面積, 而且保存爲當前最小值。 不然將當前最小值定義爲無窮大。
- 順時針旋轉線直到其中一條和多邊形的一條邊重合。
- 計算新矩形的面積, 而且和當前最小值比較。 若是小於當前最小值則更新, 並保存肯定最小值的矩形信息。
- 重複步驟4和步驟5, 直到線旋轉過的角度大於90度。
- 輸出外接矩形的最小面積。
由於兩對的「卡殼」肯定了一個外接矩形, 這個算法考慮到了全部可能算出最小面積的矩形。 進一步, 除了初始值外, 算法的主循環只須要執行頂點總數屢次。 所以算法是線性時間複雜度的。
一個類似可是不爲人知的問題是最小周長外接矩形問題。 有趣的是這兩個問題是徹底不一樣的問題, 由於存在(儘管極少)最小面積外接矩形和最小周長外接矩形多邊形不重合的多邊形。code
2.凸多邊形最小周長外接矩形
這個問題和最小面積外接矩形類似。 咱們的目標是找到一個最小盒子(就周長而言)外接多邊形 P 。
有趣的是一般狀況下最小面積的和最小周長的外接矩形是重合的。 有人不由想問這是否是總成立的。 下面的例子回答了這個問題: 多邊形(灰色的)及其最小面積外接矩形(左邊的)和最小周長外接矩形(右邊的)。
orm
如今, 給定一個方向, 咱們能夠算出 P 的端點, 以此來肯定一個外接矩形。 可是, 就如同面積問題中同樣, 因爲有下面的結論, 咱們沒必要檢測每一個狀態來得到擁有最小周長的矩形:
凸多邊形 P 的最小周長外接矩形存在一條邊和多邊形的一條邊重合。
這個結論經過枚舉多邊形的一條重合邊有力地限制了矩形的可能範圍。
圖示上述結論: 四條切線(紅色), 其中一條與多邊形邊重合, 肯定了外接矩形(藍色)。
由於與其面積問題至關, 這個問題能夠經過一個基於旋轉卡殼的類似的算法來解決。
下屬算法的輸入是順時針順序給定的一個凸多邊形的 n 個頂點。
- 計算所有四個多邊形的端點, 稱之爲 xminP, xmaxP, yminP, ymaxP。
- 經過四個點構造 P 的四條切線。 他們肯定了兩個「卡殼」集合。
- 若是一條(或兩條)線與一條邊重合, 那麼計算由四條線決定的矩形的面積, 而且保存爲當前最小值。 不然將當前最小值定義爲無窮大。
- 順時針旋轉線直到其中一條和多邊形的一條邊重合。
- 計算新矩形的周長, 而且和當前最小值比較。 若是小於當前最小值則更新, 並保存肯定最小值的矩形信息。
- 重複步驟4和步驟5, 直到線旋轉過的角度大於90度。
- 輸出外接矩形的最小周長。
由於兩對的「卡殼」肯定了一個外接矩形, 這個算法考慮到了全部可能算出最小周長的矩形。 進一步, 除了初始值外, 算法的主循環只須要執行頂點總數屢次。 所以算法是線性時間複雜度的。
問題處理一樣包含三角形。 有兩個特例, 具體參見洋蔥三角剖分和螺旋三角剖分。
4、三角剖分
1.洋蔥三角剖分
給定一個平面上的點集, 目標是構造一個點集的三角剖分。
從Lennes 1911年二次時間複雜度的源算法到Chazelle 1991線性時間複雜度的算法, 前人已經作了許多關於提升三角剖分算法效率的研究。
這裏的焦點是關於一種特殊的三角剖分, 一種基於對點集進行「剝洋蔥皮」操做。
考慮平面上一個有 n 個點的集合 S 。 計算 S 的凸包, 而且設 S' 爲在凸包內的點集。 而後計算 S' 的凸包而且反覆執行這個操做直到沒有點剩下。 最後剩下了一個像鳥巢同樣層層覆蓋的凸包序列, 稱爲洋蔥皮集合 S 。 感謝Chazelle的算法, 這個結構可以在 O(n log n) 時間操做內實現。
一個點集的洋蔥皮。 注意除了凸多邊形外, 最裏面的結構多是一條線段或者是一個單一點。 這個圖給出了點的層次信息, 好比點間哪一個相對更「深」。
兩個嵌套的凸包間的區域稱爲一個環面。 Toussaint在1986年發表了一個利用旋轉卡殼計算環面三角剖分的簡單算法。 利用這個方法, 一旦構造出洋蔥皮, 就能在現行時間內構造出三角剖分。 進一步, 這個三角剖分有兩個特色: 他的子圖仍然是洋蔥皮, 而且他是一個哈密爾頓圖, 即三角剖分圖的頂點能夠是鏈狀的。
一個環面的三角剖分算法是很是簡單的。 算法輸入一個被凸包 P 包裹的凸包 Q, 他們的頂點都是順時針序的。
- 將凸包的邊做爲三角剖分的邊插入。
- 計算 P 和 Q 的 x 座標最小的點, 分別稱爲 xmin(P) 和 xmin(Q) 。
- 在 xmin(P) 和 xmin(Q) 處構造兩條鉛垂切線, 稱之爲 LP 和 LQ 。
- 將 (xmin(P), xmin(Q)) 做爲三角剖分的一條邊插入。
- 當前 LP 和 LQ 對應的 p 和 q 點分別是 xmin(P) 和 xmin(Q)。
- 將線順時針旋轉直到其中一個與一條邊重合。 一個新的頂點由此被一條線「擊」出。
- 若是他屬於 P (稱爲 p'), 插入 (p', q) 到三角剖分中。 更新當前的點爲 p' 和 p' 。
- 若是他屬於 Q (稱爲 q'), 插入 (p, q') 到三角剖分中。 更新當前的點爲 p 和 q' 。
- 對於平行邊的狀況, 兩條切線都和邊重合, 而且兩個新的頂點被「擊」出(稱他們爲 p' 和 q')。 而後插入 (p', q') , 以及 (p, q') 和 (p', q) 到三角剖分中。 更新當前的點爲 p' 和 q' 。
- 重複執行上述步驟直到達到開始的最小點。
一個換面的三角剖分以下所示:
上述的算法擁有線性時間複雜度。 當對於一個點集進行三角剖分的時候, 一個凸包在整個過程當中遍歷(最多)兩次, 最裏面和最外部的凸包都只執行遍歷一次。 所以對於一個 n 個點的三角剖分的總運行時間是 O(n) 。
另外一個有效且與三角剖分有關的問題是基於點集的凸螺旋線的螺旋三角剖分。
2.螺旋三角剖分
點集的螺旋三角剖分是基於集合螺旋凸包的三角剖分圖。
凸螺旋線能夠經過以下方法構造:
- 從一個特定的端點開始(好比給定方向上的最小點), 這裏取有最小 x 座標的點。
- 經過那個點構造一條鉛垂線。
- 按照一個給定的方向旋轉線(總保持順時針或者是逆時針方向), 直到線「擊」 出另外一個頂點。
- 將兩個點用一條線段鏈接。
- 重複步驟3和步驟4, 可是總忽略已經擊出的點。
大致上, 這個過程相似於計算凸包的捲包裹算法, 可是不一樣在於其循環永遠不會中止。 對於一個凸包上有 h 個點的點集, 存在 2h 個凸螺旋線: 對於每一個起點有順時針和逆時針螺旋線兩種。
一個點集(左邊), 及其順時針凸螺旋線, 以最小的 x 座標點做爲初始點。
有趣的是, 一個點集的凸螺旋線和洋蔥皮能夠在線性時間內相互轉換。 進一步的, 相似於洋蔥三角剖分, 咱們能夠定義一個點集的子圖爲凸螺旋線的螺旋三角剖分。
構造螺旋三角剖分的算法, 雖然是基於環面三角剖分的, 可是卻更爲複雜, 由於螺旋線必須被分割爲合適的凸包鏈。 假設輸入是一個點集的順時針凸螺旋線 C , 且有 C = { p1 , ... , pn } 。
- 將凸螺旋線的邊做爲三角剖分的邊插入。
- 從 p1 開始, 尋找點集凸螺旋線上的最後一個點 ph 。
- 延長凸螺旋線上的最後一條邊 [p(n-1),pn] 直到其與凸螺旋線相交。 標記交點爲 q' 。
- 構造與 C 切於點 q' 的切線。 逆時針旋轉那條線直到他與 C 相交於一點 q 而且平行於 [p(n-1),pn] 。
- 將 [p(n-1),q] 插入三角剖分中。
- 此操做後將凸螺旋鏈分割稱了兩個部分: 鏈外的部分和鏈內的多邊形區域。 設 Co = { p1 , ... , q } 且 Ci = { ph , ... , q , ... , pn } 。 這個構造過程以下圖所示:
左上角: 構造過程。 右上角: 螺旋外和內部的多邊形區域。 底部: 外部和內部的凸鏈 Co 和Ci 。
- 外部螺旋區域能夠如環面同樣進行三角剖分。 Co 和 Ci 此時能夠被當作一個嵌套凸包。
- 內部的多邊形區域能夠很容易的在 pn 處星型劃分造成三角剖分。
- 這兩個三角剖分的組合構成了整個螺旋三角剖分的結構。
一個螺旋凸包的例子和其三角剖分以下所示:
上述的算法是線性時間複雜度的, 算法的時間依賴於環面剖分的運行時間。
3.四邊形剖分
雖然三角剖分是一個更經常使用的結構, 但最近四邊形剖分在某些特定條件下顯得更適用, 好比 scattered data interpolation 以及 finite element method 等。
一個四邊形剖分其實是一個點集的四邊形分割。 一些與三角剖分本質上的區別(除了特別明顯的)應該引發注意:
首先, 不是全部的點集都存在四邊形剖分。 事實上, 只有偶數點集纔有。 對於奇數點集, 有時須要附加點(稱爲Steiner點)到原集合中, 從而構造一個四邊形剖分。
同時, 人們常常指望四邊形剖分構造擁有一些「好的」性質, 好比凸的。 這個與三角剖分是不一樣的。
有許多簡單的四邊形剖分算法。 好比, 首先考慮點集的三角剖分, 而後加入一個Steiner點到每一個三角形內部, 以及每條邊的中間。 鏈接這些新點構成了四邊形剖分(這是DeBerg提出的)。
Bose 和 Toussaint 在1997年提出從一個點集的螺旋三角剖分開始, 來構造一個o四邊形剖分。
若是點集是偶數的, 那麼每隔一個的對角線(在螺旋三角剖分算法中加入的)移除, 構造了一個四邊形剖分。 若是是奇數個點, 那麼從最後一條對角線開始每一個隔一條對角線(好比最後一個, 倒數第三個等)進行移除, 在被移除的第一條對角線附近加入一個Steiner點。 下圖展現第一種狀況(偶數個點的點集)。 螺旋三角剖分(左邊), 和最終的四邊形剖分(右邊)。
由於對角線的移除過程(和必要的更新)花費 O(n) 的時間, 這個四邊形剖分算法與螺旋三角剖分有相同的時間複雜度。 這個算法的優勢在於便於理解與實現(一旦凸螺旋線創建), 而且事實上其產生了一個比許多競爭者「更好的」四邊形剖分算法。
下一個問題集是關於凸多邊形, 特別的, 關於凸包上的操做, 好比合並凸包。
5、凸多邊形屬性
1.合併凸包
考慮以下問題: 給定兩個凸多邊形, 包含他們並的最小凸多邊形是怎樣的? 答案即合併凸包後獲得的凸多邊形。合併凸包能夠經過一個低效的方式實現: 給定兩個多邊形的全部頂點, 計算這些點對應的凸包。 更高效的方法是存在的, 他依賴於多邊形間的 橋 的查找。 下圖描述了這個概念:
兩個不相交的凸多邊形。 合併後的凸包包含兩個多邊形中的凸包鏈(途中藍色粗實線), 經過多邊形間的橋進行鏈接(途中藍色虛線)
給定兩個不相交的多邊形, 在多邊形間存在兩條橋。 多邊形相交時, 擁有和頂點數一樣數量的橋, 以下圖所示:
兩個相交的凸多邊形。 合併凸包只包含多邊形間的橋(圖中虛線所示)。 存在鏈接八個頂點的八個橋。
合併操做的核心是分治方法。 他一樣用於多邊形中。 一個獲取凸包的十分簡單的方法是將點集分爲兩部分, 分別計算兩個較小點集的凸包, 而且將他們合併。 每一個集合再次被分割, 直到元素的個數足夠小(好比說三個或者更少) 所以凸包就能被很容易得到了。
Toussaint 提出利用旋轉卡殼來尋找兩個凸多邊形間的橋。 這個方法的主要優勢在於其利用回溯, 而且多邊形能夠交疊(其餘的算法要求多邊形不相交)。 下述結論是他的算法的主要過程:
給定凸多邊形 P = { p(1) , ... , p(m) } 和 Q = { q(1) , ... , q(n) },一個點對 (p(i), q(j)) 造成 P 和 Q 之間的橋當且僅當:
- (p(i), q(j)) 造成一個並踵點對。
- p(i-1), p(i+1), q(j-1), q(j+1) 都位於由 (p(i), q(j)) 組成的線的同一側。
- 分別計算 P 和 Q 擁有最大 y 座標的頂點。 若是存在不止一個這樣的點, 取 x 座標最大的。
- 構造這些點的遂平切線, 以多邊形處於其右側爲正方向(所以他們指向 x 軸正方向)。
- 同時順時針旋轉兩條切線直到其中一條與邊相交。 獲得一個新的並踵點對 (p(i), q(j)) 。 對於平行邊的狀況, 獲得三個並踵點對。
- 對於全部有效的並踵點對 (p(i), q(j)): 斷定 p(i-1), p(i+1), q(j-1), q(j+1) 是否都位於鏈接點 (p(i), q(j)) 造成的線的同一側。 若是是, 這個並踵點對就造成了一個橋, 並標記他。
- 重複執行步驟3和步驟4直到切線回到他們原來的位置。
- 全部可能的橋此時都已經肯定了。 經過連續鏈接橋間對應的凸包鏈來構造合併凸包。
一個凸多邊形間的橋實際上肯定了另外一個有用的概念:多邊形間公切線。 同時, 橋也是計算凸多邊形交的算法核心。
2.找共切線
公切線是同時與多邊形相切的簡單直線, 而且兩個多邊形都位於線的同一側。 換句話說, 一條公切線是一條與兩個多邊形都相切的線。 一個例子以下圖所示:
兩個不相交的凸多邊形和一條他們的公切線
事實上, 公切線能夠經過多邊形間的一些肯定橋的點對來確立。 所以, 給定兩個不相交的多邊形, 就存在兩個多邊形間兩條公切線, 而且當多邊形相交時, 還有可能存在與頂點數同樣多的公切線。
用來計算兩多邊形間橋的算法(如歸併算法)一樣能夠用來肯定公切線。
另外一個「版本」的兩多邊形的公切線是關鍵切線。 那種狀況下多邊形分立於線的兩側。
橋能夠用來計算多邊形的交。
3.凸多邊形交
給定兩個多邊形, 咱們第一個須要討論的問題應該是:「他們相交嗎?」。 Chazelle 和 Dobkin 1980年在他們的一篇叫作「Detection is easier than computation」的論文中發表了一個對數時間級的算法(論文的名字很貼切)。 對於多邊形的交, 許多算法能計算出交集。 有趣的是一個結論(由Guibas提出)證實了多邊形交點和和他們之間的橋是一一對應關係。
兩個多邊形(淺紅色和藍色)和他們的交集(淺紫色)。 交點以紅色標記。 每一個交點與一個多邊形之間的橋(標記爲紅色點劃線)有關。
Toussaint在1985年的文獻中利用Guibas的結論, 加上他先前的關於查找橋的算法來計算交點集。 他的算法利用橋來計算交點集。 一旦他們被找到, 與合併凸包的操做相似, 凸鏈以及交點集造成了多邊形的交集。
算法的細節, 特別是從橋到交點的計算能夠在Toussaint的論文中找到:
G.T. Toussaint. A simple linear algorithm for intersecting convex polygons. The Visual Computer. 1: 118-123. 1985.
下一個問題設計尋找兩個凸多邊形的臨界切線。
4.臨界切線
兩個凸多邊形間的臨界切線(通常被叫作CS線)是使得兩個多邊形分居線不一樣側的切線。 換句話說, 他們分隔了多邊形。CS線能夠應用於motion planning, visibility 和 range fitting。
下圖是關於兩個多邊形和他們的兩條臨界切線。
這裏要注意的一點是假設數據是以標準形式給出的, CS線只會在兩個頂點處與兩個多邊形相交。 所以, 一條CS線由多邊形間頂點對肯定。
以下的結論描述了這個點對:
給定兩個凸多邊形 P, Q, 兩個頂點 p(i), q(j) (分別屬於 P 和 Q) 肯定一條CS線當且僅當:
- p(i), q(j) 構成多邊形間對踵點對。
- p(i-1),p(i+1) 位於線 (p(i), q(j)) 一側,同時q(j-1),q(j+1) 位於另外一次。
- 計算 P 上 y 座標值最小的頂點(稱爲 yminP ) 和 Q 上 y 座標值最大的頂點(稱爲 ymaxQ)。
- 爲多邊形在 yminP 和 ymaxQ 處構造兩條切線 LP 和 LQ 使得他們對應的多邊形位於他們的右側。 此時 LP 和 LQ擁有不一樣的方向, 而且 yminP 和 ymaxQ 成爲了多邊形間的一個對踵點對。
- 令 p(i)= yminP, q(j)= ymaxQ。 (p(i), q(j)) 構成了多邊形間的一個對踵點對。 檢測是否有 p(i-1),p(i+1) 在線 (p(i),q(j)) 的一側, 而且 q(j-1),q(j+1) 在另外一側。 若是成立, (p(i), q(j)) 肯定了一條CS線。
- 旋轉這兩條線, 直到其中一條和其對應的多邊形的邊重合。
- 一個新的對踵點對肯定了。 若是兩條線都與邊重合, 總共三對對踵點對(原先的頂點和新的頂點的組合)須要考慮。 對於全部的對踵點對, 執行上面的測試。
- 重複執行步驟4和步驟5, 直到新的點對爲(yminP,ymaxQ)。
- 輸出CS線。
這個算法基本經過繞着多邊形旋轉切線, 順序查找全部多邊形間的對踵點對。 每次一對對踵點肯定後, 執行全部必要的測試。 在上述過程執行完後, 全部的臨界切線都被找到了。
算法的運行時間由步驟1和步驟6決定, 他們都花費 O(n) 的時間(全部的檢測都花費常數時間。 由於有 O(n) 的對踵點對, 總的花費爲 O(n))。
關於凸多邊形的學習, 最後的操做是凸多邊形矢量和。
5.凸多邊形矢量和
給定平面上兩個凸多邊形 P 和 Q , P 和 Q 的矢量和, 記爲 P + Q 定義以下:P + Q = { p + q } 全部的分別屬於 P 和 Q 的 p 和 q 。多邊形矢量和在 motion planning 中也稱爲 Minkowski 總數。
考慮上述的定義, 許多問題能夠經過詢問集合 P + Q 的組成, 他擁有的性質等等。 下屬結果幫助咱們描述多邊形矢量和。
- P + Q 是一個凸多邊形。
- 頂點集 P + Q 是頂點集 P 和 Q 的和。
- 頂點集 P + Q 是 P 和 Q 間的並踵點對集。
- 給定分別有 m 和 n 個頂點的 P 和 Q , P + Q 有很少於 m + n 個頂點。
最後, 下屬結論不只僅描述了這個問題, 同時也提供了一個一個個頂點的增量式計算矢量和的計算方法。
給定 P + Q 集合的第 k 個向量 z(k), 知足 z(k) = p(i) + q(j)。 構造在 p(i) 和 q(j) 處構造兩條平行切線, 使得多邊形同時位於各自線的右側。 兩條線分別在 p(i) 和 q(j) 處肯定了角 theta(i) 和 phi(j) (以下圖所示)
所以下一個向量 z(k+1) 等於:
- p(i+1) + q(j) 若 theta(i) < phi(j)
- p(i) + q(j+1) 若 theta(i) > phi(j)
- p(i+1) + q(j+1) 若 theta(i) = phi(j)
下述的多邊形和他們的矢量和做爲一個例子。
兩個凸多邊形。 第一個多邊形的邊用紅色標記, 第二個用藍色。
上述多邊形的矢量和。 其邊的顏色與原多邊形的一致。
用上述的結果, 咱們十分容易的就能構造出一個算法來計算矢量和。 第一個向量能夠是在給定方向上邊界向量的和(如 y 軸負方向)。 切線構造後, 在計算角度時候更新, 下一個點就很明確了。 咱們須要作的只是同時旋轉兩條線到新的位置來肯定新的角度。
算法的正確性來自主要的結論; 他是線性時間複雜度的, 由於每一步只有一個所要求的向量和集合中的向量被肯定, 而且他們只有 m + n 個, 所以總運行時間是 m + n 。
6、最薄截面
1.最薄橫截帶
考慮下述設備放置問題:一個「消費羣體羣」的集合是以個體呈現爲平面上凸多邊形的一個家庭 F 給出的。 咱們的目標是找到一個「設備」, 一條平面上的直線, 使得線到消費者的最大距離最小。最後一點須要澄清。 直線與任何一個多邊形的距離都是指多邊形上一點到線的正交距離的最小值。 所以,每一個多邊形到線的距離是惟一的。
如今, 給定家庭中各個呈多邊形的成員和平面上的一條直線, 每一個多邊形都有一個到線的距離。 所以, 對於整個家庭存在一個最大的線-多邊形距離。 這個距離同時依賴於線與各個家庭成員多邊形。
這個問題的目標是: 給定一個特定的家庭成員多邊形集, 找到使得這個最大距離最小的線。 這個問題一樣存在着其餘版本, 常見的有找一條線使得距離和最小, 或是使得多邊形帶權距離和最小。
這裏的提出的結論是Robert和Toussaint在1990年發表的。
主問題等價於找到一個寬最小的帶(一個平面上由兩條平行線爲邊界的區域)和全部的家庭成員多邊形相交。所以, 帶的中心(與帶的邊界線平行等距的線)就是所求的使得最大距離最小的線。
爲了討論這個問題咱們作以下定義:
平面上的一條直線 l , 其方程爲 ax + by + c = 0 (且 b > 0 或 a = -1)將平面分爲兩個區域:上半平面 Hu(l) 中的點 p = (px,py) 知足 apx + apy + c >= 0 , 且下半平面 Hl(l) 中的點 p = (px,py) 知足 apx + apy + c <= 0 。
經過上面的定義, 若是線是鉛直的, 上半平面爲 x 軸的負方向。
進一步地, 一個帶能夠定義爲一條線的上半平面和另外一條(平行)線的下半平面的交集。
給定一個凸多邊形 P , 一個方向角 theta , 下切線 tl(P, theta) 是一條與 x 軸正半軸夾角爲 theta 的線, 他與 P相交而且 P 在 tl(P, theta) 的上半平面。 交點(可能不止一個)稱爲下頂點。
一樣的, 定義上切線和上頂點。
給定一個家庭的多邊形集合和一個固定的方向角, 就肯定了一個下頂點集和上頂點集。
最後, 考慮下面的結論:
給定家庭 F 的多邊形集, 和一個方向角 theta , 一個帶 S (由 Hu(l1) 和 Hl(l2) 大於0的交集獲得)是 F (在此方向上)最小寬度帶, 當且僅當 F 中存在兩個多邊形 P 和 Q 有
- P 和 Hu(l1) 的交在 l1 上。
- Q 和 Hl(l2) 的交在 l2 上。
其主要的結論是: 一個家庭 F 的凸多邊形集的最小寬度帶(一個給定方向 theta 上)由 l1 和 l2 肯定當
l1=tl(CH(UP(F, theta)), theta) 且
l2=tu(CH(LP(F, theta)), theta) 成立。
一個家庭的凸多邊形集, 以及給定角度上的最小帶寬。 下頂點和上頂點的凸包, 上述的結論如圖所示。 注意到兩個多邊形和帶的交都只在一個頂點上出現。
所以, 只要肯定了家庭多邊形集的下頂點和上頂點的序列, 就能經過計算凸包獲得給定方向上最小寬度帶。就如Robert和Toussaint解釋的, 幸運的是這些凸包不須要每次都徹底從新計算: 他們須要更新便可。 實際上, 考慮兩個接近的方向:許多(或者是所有)多邊形對於這兩個方向擁有相同的上頂點和下頂點。 這個結果一樣暗示這隻有有限的方向上(當下頂點或上頂點變化時)須要檢測。
這裏的焦點在於旋轉卡殼模型, 而非關係到算法的細節。 本文打算利用旋轉卡殼來計算多邊形的上頂點和下頂點。下面是算法的主要實現過程。 給定一個凸多邊形 P :
- 找到擁有最小和最大 y 座標的頂點。 標記爲 p 和 q 而且經過他們構造水平切線。
- 逆時針將切線旋轉過 theta 角直到其中一條與其中一個多邊形的邊平行。
- 若是頂點在 p 後被擊出(按照逆時針方向), 那麼 p 就是對於角度0(包括)到角度 theta(不包括) 之間的下頂點。 若是頂點是在 q 後被擊出, 那麼 q 就是一樣角度範圍內的上頂點。 這兩個狀況當邊平行的時候也可能同時發生。
- 更新當前點爲新擊出的頂點, 並更新當前角度。
- 重複執行步驟2到步驟4, 同時跟新角度區間, 知道新的角度大等於180度(在哪一點先回到了最初的位置, 但此時次序顛倒)。
線與其中一個多邊形的一條邊平行的方向稱之爲 臨界方向 。 他們只在上頂點和下頂點處發生變化。 對於一個臨界方向, 由於線穿過兩個頂點, 當逆時針旋轉時下頂點或是上頂點之一被定義爲多邊形與線的一個交點。
一旦臨界方向(按照順序給出)獲得, 一個帶就能在第一個方向上進行計算。 而後, 在第二個臨界方向上, 至少一個上頂點或是下頂點被更新。 所以, 凸包此時須要更新, 而非從新計算一次。 一旦完成上述步驟, 新的帶就構形成功了, 而且他的寬度(邊界間的正交距離)被算出。 對全部臨界方向重複這個操做。 注意到若是任何點處若是產生了一個寬度爲0的帶f, 這個過程就可以由於找到一條穿過全部家庭多邊形的線而終止了。
對於完整的算法描述, 正確性討論和運行時間分析, 見做者的論文:
J.-M. Robert, G.T. Toussaint. Computational geometry and facility location. Proc. Internatioanl Conf. on Operations Research and Management Science, Manila, The Philippines, Dec. 11-15, 1990. pp B-1 to B-19.