ボロノイ図、ボロノイ領域

概要

ボロノイ図関連について、定義はボロノイ図 - Wikipedia参照

高速にボロノイ図を求めるアルゴリズム(フォーチュンのアルゴリズム?)は存在しているのだが、ここでは1つのボロノイ領域をO(n(n+m))くらい?で求める方法を考える。(n:点の数、m:凸領域の頂点の数)

アルゴリズム

全体の領域をRとする。
ボロノイ領域を求めたい点と、他の点に対して、垂直二等分線でRを切断し、注目点を含む方の領域を新たにRとする。
これを全ての点に対して繰り返し行えば、ボロノイ領域を得ることができる。

実装

データ構造、ccw、crosspointは全てSpaghetti Sourceのもの。下のconvex_cutはSpaghettiSourceを少し修正したもの。
convex_cutは凸多角形を直線で切断し左側の部分を残す。
bisectorは、点a,bを結ぶ線分の垂直二等分線を求める。この垂直二等分線の向きはa->bを半時計回りに90度回転した向き。これで凸多角形を切断すれば、点aを含む方を残すことが出来る。

G convex_cut(const G& g, const L& l) {
  G Q;
  REP(i, g.size()) {
    P A = g[i], B = g[(i+1)%g.size()];
    if (ccw(l[0], l[1], A) != -1) Q.push_back(A);
    if (ccw(l[0], l[1], A)*ccw(l[0], l[1], B) < 0)
      Q.push_back(crosspoint(L(A, B), l));
  }
  return Q;
}
L bisector(P a, P b) {
  P A = (a+b)*P(0.5,0);
  return L(A, A+(b-a)*P(0, PI/2));
}
G voronoi_cell(G g, vector<P> v, int s) {
  REP(i, v.size())
    if (i!=s)
      g = convex_cut(g, bisector(v[s], v[i]));
  return g;
}

もっとスマートな方法があったら教えてください