not good but great

プログラミング、アート、映画・本の感想について書きます。

CreateJSで外心と外接円を描画してみた

ボロノイ図を作ろうと思ったが難しい

イケテルボロノイ図のデモを見ていたら、自分でも作りたくなりました。
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を求めるのはめんどくさいなあと思っていたましたが、プログラミングなので手計算は必要ありません。ということで素直に逆余弦を求めて、角度を導くのがポイントだと思います。