ボロノイ図を作ろうと思ったが難しい
イケテルボロノイ図のデモを見ていたら、自分でも作りたくなりました。
http://codepen.io/neave/details/InhFq
ボロノイ図はものすごくざっくり言うと、各点の垂直二等分線をいい感じに繋いだものです。
HACKist » HTML5のCanvasでボロノイ図をかいてみた
でもこれを理解して、コードを書くのは難しいと思いました。どの点を選べばよいのか、どこからどこまで線を引けばよいのか。Codepenのデモにはソースが載っていますが、結構長くて理解するのが大変です。
外接円を使う
コードがわからないので、変数名の英単語を調べて、意味を理解することにしました。
そこで出ててきたのが「circumcenter:外心」という語。ボロノイ図と外心には何か関係があると思い、調べてみました。
任意の三母点の外接円を描いた時、その円の内部に他の母点が存在しない場合、その円の中心がボロノイ点となります。
ボロノイ点を結めば、ボロノイ図になります。
MAPCOM WORLD [PC-MAPPING ヒント集]
ボロノイ図をいきなり作るのはそれでも大変なので、ひとまず3つの点から外心を求めることにしました。
demo
それでできたのがこれです。
外心の座標を求める
計算式は正確なものが必要なので、下のページを参考にしました。自分で計算すると間違うかもしれないので笑。
・公式
http://homepage2.nifty.com/gis_yasu21/sub1.htm
2010-09-29
/*----------------------------------- 2点間の距離を求める -----------------------------------*/ function getDist(v0,v1){ return Math.sqrt(Math.pow(v0.x - v1.x,2)+Math.pow(v0.y - v1.y,2)); } /*----------------------------------- 余弦定理、アークコサインで角度を求める -----------------------------------*/ function LawOfCosines(a,b,c){ return Math.acos((b*b+c*c-a*a)/(2*b*c)); } /*----------------------------------- 外心を求める -----------------------------------*/ function circumcenter(v0,v1,v2){ var edgeA,edgeB,edgeC, angleA,angleB,angleC, a,b,c, x,y, vc; //辺の長さ edgeA = getDist(v1,v2); edgeB = getDist(v2,v0); edgeC = getDist(v0,v1); //角度 angleA = LawOfCosines(edgeA,edgeB,edgeC); angleB = LawOfCosines(edgeB,edgeC,edgeA); angleC = LawOfCosines(edgeC,edgeA,edgeB); a = Math.sin(2*angleA); b = Math.sin(2*angleB); c = Math.sin(2*angleC); //外心のX,Y座標 x = ((v0.x*a+v1.x*b+v2.x*c) / (a+b+c)); y = ((v0.y*a+v1.y*b+v2.y*c) / (a+b+c)); //外心を生成 vc = new Vertex(x,y,"#191919"); circumcenters.push(vc); //ステージに追加 stage.addChild(vc); //外接円を描画 drawOrbit(x,y,edgeA/(2*Math.sin(angleA))); }
cosAからsin2Aを求めるのはめんどくさいなあと思っていたましたが、プログラミングなので手計算は必要ありません。ということで素直に逆余弦を求めて、角度を導くのがポイントだと思います。