📐

【ドロネー三角形分割】GISを作るデータ構造とアルゴリズム【計算幾何学】

に公開

概要

前回の記事では, GISの基本機能のひとつ, ボロノイ分割を説明した.

今回は, ドロネー三角形分割について説明する. 地理空間情報では等高線の3Dモデルの作成, コンピューターグラフィックスでは有限点のメッシュ生成, などが利用例である.

ドロネー三角分割は, 有限個の点をもとに三角形の面を作成する, 三角形の領域に分割する処理である. (通常の)三角分割に加え, 綺麗な三角分割をつくる, そんな目的の分割方法である.

今回も「コンピュータ・ジオメトリ 第3版 計算幾何学:アルゴリズムと応用」や, レンセラー工科大学の講義資料を参考に説明する.

ドロネー三角分割

点集合Pにはいくつかの分割方法が存在する.どの分割方法でも良いかと言えばそうではない. では, 望ましい分割とはなにか?まず目的物をはっきりしよう.

角度最適

ここでTPの三角形分割として, そこにm個の三角形が含まれるとする. m個の三角形には計3m個の内角が存在し,それぞれを\alpha_i (i=1,..,.3m)とする. さらに,3m個の内角を大小で昇順にソートした列を取得し, A(T):= (\alpha_1,\alpha_2,...,\alpha_{3m})のように書く. これをT角度ベクトルと呼ぶ.

次に, Pの別の三角形分割としてT'を考える. 同様に,3m個の内角を\alpha_i' (i=1,..,.3m), そしてA(T'):= (\alpha_1',\alpha_2',...,\alpha_{3m}')を求める.

ここで, 分割方法に序列を導入したい. 具体的には, A(T)が辞書式順序で A(T')より後にある, ことをA(T) > A(T')という関係式で表す.

辞書式順序とはつまり, 次式を満たすようなインデックスi(ただし,1 \leq i \leq 3m)が存在するとき, Tの角度ベクトルはT'の角度ベクトルより大きい, とする.

すべての j < i に対して \alpha_j = \alpha_j' かつ \alpha_i = \alpha_i'

そして, Pの考えられる三角形分割T'に対し, A(T) \geq A(T')が成り立つとき, その三角形分割は角度最適(angle-optimal) とよぶ.

このような状態の三角形分割を探索したい, というのがドロネー三角分割の狙いである.

正当な三角分割

つぎに,どのような条件を満たすときに三角形分割が角度最適になるのか見ていく. 情報として,ターレスの定理を導入する.

次に, 以下の例を考える. 四つの点p_i, p_j,p_k,p_lを三角形分割したA(T)ができている. この四つの点の三角形分割にはもう一つパターンがある. それは, 辺\bar{p_ip_j}を, 辺\bar{p_kp_l}へと繋ぎ直した三角形分割A(T')である.

同じ頂点群に対し, 頂点の結び方を入れ替える方法を辺フリップ(Edge Flip) とよぶ.
つまり, 四つの点p_i, p_j,p_k,p_lを三角形分割するとA(T)A(T')が考えうるが,さてどちらが求める三角形分割であるか.

角度最適の式を言い換えると, 次のような条件を満たすとき, その三角形分割は不当であると呼ぶ.

\min_{1 \leq i \leq 6} \alpha_i < \min_{1 \leq i \leq 6} \alpha_i'

式を口語的に読むと, 辺フリップの結果, 三角形分割後の内角のうち最小のものの大きさが局所的に大きなる場合, その元の辺は不当である,ということだ.

この条件に従えば, いくつかの候補がある三角形分割について,良いものを抽出できる.

さらに良いこと, 不当な辺を検出するために, わざわざ内角の大きさを計算で求める必要はない.
便利な方法をとして,

  1. 三角形分割を構成する各三角形の3つの頂点を結ぶ外接円を求める.
  2. 1のとき, この外接円に3点以外の点が含まれている場合, その三角形には不当な辺を含んでいると判定する.

実際にこの方法で判定できるのかさきほどの図形でみてみる. (上図) すると, 不当な辺を含むA(T)では, それぞれの外接円が4番目の頂点を内部に含んでいるが, 不当な辺を含まないA(T')では, それぞれの外接円の内部に別の点が含まれていない.

アルゴリズム

基本戦術

さて, 上述した辺フリップを駆使すれば, ある初期状態の三角形分割をスタートに, 徐々に角度最適な三角形分割A(T)を作っていけそうだ.

簡単な話, とりあえず何かしらの三角形分割を構成後, すべての辺に対し,正当か不当な辺であるかを判定し, 辺フリップを繰り返せばよい. 結果, これ以上辺フリップの余地がなくなればそのとき, 角度最適な三角形分割A(T)が得られている.

この方法は実のところ適切に稼働する. そして, 必ず収束するのだ. 詳細な証明は書籍に任せるが, 辺フリップにより角度ベクトルは単調に増大していくが, 上界があるために, どこかで必ず停止せざるを得ないからだ(無限大には発散できない)

この方法はとてもシンプルに実装できる.
が, 問題としては計算効率が非常に悪いということだ.

乱択逐次構成法

実際のところ, ドロネー三角形分割を求める方法はいくつか考えられる. ここでは, 乱択逐次構成法(randomized incremental algorithm) を用いた実装方法を扱う.

この乱択逐次構成法は, 入力となる点集合P={p_1,p_2,...,p_n}をシャッフルし, ランダムに選択した点を既存の三角形分割に加え, 新たな三角形分割を構成するといった逐次的にドロネー三角形分割を管理する, というものだ.

既存の三角形に新たな点p_rを加える, その三角形の3頂点と点p_rを結んだ辺を加える. あるいは, 既存の三角形のどこかの辺e上に新たな点p_rが乗った場合, 辺eを共有している2つの三角形の対角頂点と$p_r $を結ぶ辺を加える. 図示例は以下のとおりだ.

p_rが既存三角形の内部あるいは辺上に加わると, 周辺の点と点p_rを結ぶことで,この時点での三角形分割ができる. しかし, この三角形分割はドロネー三角形分割か,というとそうではない. 既存の三角形分割はドロネー三角形分割だったとしても, 点を追加後はどこかの辺が不当な辺に変わっている可能性がある. そのため,辺フリップを駆使して再度ドロネー三角形分割を構成しないといけない.

例えば先ほどの例だと, 少なくとも追加した点を内包する三角形および四角形の外周辺は不当なものである可能性がある. そのため, 外周円判定を行い, 必要に応じて辺フリップを行う必要がある.

さらに, 辺フリップを行うことで, これらの三角形および四角形の外にあった三角形にまで不当なものにしてしまう可能性がある. そこで今度は不当な辺を含んでいるかもしれない外側の三角形もチェックする... といった再起処理を, 全体で不当な辺がなくなるまで行うのだ.[1]

以下にこのアルゴリズムの疑似コードを載せておく.また, 処理のイメージを掴みたい読者は後の章を読むと理解の助けになると思う.


アルゴリズム: DelaunayTriangulation(P)
入力: 平面上のn個の点の集合P
出力: Pのドロネー三角形分割

  1. p_0を辞書式順序で最も高い位置にあるPの点とする. すなわち, 最大のy座標をもつ点の中で最も右にある点である.
  2. p_{-1}p_{-2}を十分に遠くにあるR^2の2点で, P全体が三角形p_0p_{-1}p_{-2}に含まれるように作成する.
  3. ただ1つの三角形p_0p_{-1}p_{-2}からなる三角形分割としてTを初期化する.
  4. P \ {p_0}のランダム順列p_1,p_2,...,p_nを求める.
  5. for r \leftarrow to n
  6. ---- do (p_rTに挿入する):
  7. -------- p_rを含む三角形p_ip_jp_k \in Tを求める.
  8. -------- if p_rを含む三角形p_ip_jp_kの内部にある.
  9. ------------- then p_rからp_ip_jp_kの三頂点への辺を加える. これによって,p_ip_jp_kは3つの三角形にさらに分割される.
  10. ------------ LegalizeEdge(p_r, \bar{p_ip_j}, T)
  11. ------------ LegalizeEdge(p_r, \bar{p_jp_k}, T)
  12. ------------ LegalizeEdge(p_r, \bar{p_kp_i}, T)
  13. ------- else p_rp_ip_jp_kの辺, たとえば\bar{p_ip_j}上にある.
  14. ------------ p_rからp_kへの辺を加え, さらに\bar{p_ip_j}に接するもう1つの三角形の第3の頂点p_lp_rを辺で結ぶことによって, \bar{p_ip_j}に接するこれら2つの三角形を4つの三角形に分割する.
  15. ------------ LegalizeEdge(p_r, \bar{p_ip_l}, T)
  16. ------------ LegalizeEdge(p_r, \bar{p_lp_j}, T)
  17. ------------ LegalizeEdge(p_r, \bar{p_jp_k}, T)
  18. ------------ LegalizeEdge(p_r, \bar{p_kp_i}, T)
  19. 2点p_{-1},p_{-2}と,これらに接続する辺をすべてTから取り除く.
  20. Return T


関数: LegalizeEdge(p_r, \bar{p_ip_j}, T)

  1. (挿入しようとしている点がp_rで, \bar{p_ip_j}はフリップする必要があるかもしれないTの辺である.)
  2. if \bar{p_ip_j}が正当ではない.
  3. ---- then p_ip_jp_k\bar{p_ip_j}p_rp_ip_jと隣接する三角形とする.
  4. ---- (\bar{p_ip_j}のフリップ)\bar{p_ip_j}\bar{p_rp_k}で置き換える.
  5. ---- LegalizeEdge(p_r,\bar{p_ip_k},T)
  6. ---- LegalizeEdge(p_r,\bar{p_kp_j},T)

補足点として,

  • DelaunayTriangulation(P)内の2-4行目では,点Pの外界となる巨大な三角形を先に作っている. その理由として, 新規の点を既存三角形に加えて分割する再帰的な処理を動かすための初期状態をつくるためである. もちろん, この巨大な三角形は点Pのドロネー三角形分割では本来ないため, 19行目で排除している.
  • LegalizeEdge(p_r, \bar{p_ip_j}, T)の2行目の\bar{p_ip_j}が正当性判定は, 上述した外接円判定を行う. 外接円判定についてはとても簡単な行列式があるので利用するとよいだろう.

イメージ

乱択逐次構成法によるドロネー三角形分割の処理の流れを確認する. 以下の事例はFelkel先生の講義資料から引用している.

スタートとして,新規の点pを加えることを考える.
いま,既存の三角形分割のうち,三角形abcの内部に入ったとする.(①) すると, 三角形abcの各頂点と点pを結んだ辺を作る. これらは正当な辺である. (②)
次に, 三角形abc外周の辺のチェックをする(例えば,辺ab). 不当な辺となった場合, 辺フリップにより正当な辺へ切り替える(③, 例では, 辺ab->辺pd).
この辺フリップにより, さらに隣接する三角形の辺に影響がないかチェックする(④)

以降, 全体で不当な可能性のある辺(図では赤い辺)を全てチェックしていく. 最後に, 不当な可能性のある辺がなくなれば, 新規の点pを追加後のドロネー三角形分割が構成されている.(⑧)

まとめ

今回は, 「ドロネー三角形分割」 を説明した. 乱択逐次構成法と辺フリップによる三角形分割の修正処理を構成したアルゴリズムを紹介した.

実は, ドロネー三角形分割は以前と紹介したボロノイ分割と密接な関係があり, 言ってしまえばボロノイ分割が求まればドロネー三角形分割も同時に構成できる.
このように, ドロネー三角形分割はほかにも作り方がある. 例えば, Bowyer-Watson アルゴリズムと呼ばれる処理もある. (コード付き)

https://www.gorillasun.de/blog/bowyer-watson-algorithm-for-delaunay-triangulation/

次回はいよいよ 「地理情報の検索」の仕組みに焦点を当てていく.

脚注
  1. この再帰処理は必ず収束する.なぜなら辺フリップにより角度ベクトルは大きくなっていくが, それには上界があるためどこかで止まらざるを得ないからだ ↩︎

Discussion