Catmull-Romスプラインをベジェ曲線に変換する

公開 更新

Catmull-Romスプラインの接線ベクトルを使うことで3次ベジェ曲線の制御点を生成することができる。 Catmull-Romスプライン曲線

計算式

Catmull-Romスプラインの接線ベクトルV0V_0V1V_1を利用する。

3次ベジェ曲線の定義は P=(1t)3P0+3(1t)2tP1+3(1t)t2P2+t3P3P = (1-t)^3P_0+3(1-t)^2tP_1+3(1-t)t^2P_2+t^3P_3

制御点はそれぞれ P0P_0=始点 P3P_3=終点 P1=P0+13V0P_1 = P_0+\frac{1}{3}V_0 P2=P313V1P_2 = P_3-\frac{1}{3}V_1

Catmull-Romスプラインの接線ベクトル(速度)に13\frac{1}{3}を掛けると制御点になる。ベジェ曲線の1階微分を求めると3倍の係数がでるため、1/3にスケールダウンすることで整合が取れる。

コード

Catmull-Romスプラインを描画するコードに追加する形で制御点のポリラインを生成している。

//
// Cutmul-Rom曲線とベジェ制御点を描く
// Run Over: Detail
//
for(int i = 0; i < npoints(0)-1; i++)
{
    vector p0 = point(0, "P", i-1);
    vector p1 = point(0, "P", i);
    vector p2 = point(0, "P", i+1);
    vector p3 = point(0, "P", i+2);
    
    // 始点の速度ベクトル
    vector v0;
    if(i > 0)
        v0 = (p2 - p0) / 2;
    else // 始点
        v0 = (p2 - p1);
        
    // 終点の速度ベクトル
    vector v1;
    if(i < npoints(0)-2)
        v1 = (p3 - p1) / 2;
    else // 終点
        v1 = p2 - p1;
    
    // p1-p2間でカーブを描く
    int prim = addprim(0, "polyline");
    int num = 100;
    for(int j = 0; j < num; j++)
    {
        float t = j / float(num-1);
        vector pos = (-2*(p2-p1)+v1+v0)*t*t*t + (3*(p2-p1)-v1-2*v0)*t*t + v0*t + p1;
        
        int pt = addpoint(0, pos);
        addvertex(0, prim, pt);
    }
    
    // 制御点
    prim = addprim(0, "polyline");
    
    vector c0 = p1;
    int pt = addpoint(0, c0);
    addvertex(0, prim, pt);
    
    vector c1 = p1 + v0 / 3;
    pt = addpoint(0, c1);
    addvertex(0, prim, pt);
    
    vector c2 = p2 - v1 / 3;
    pt = addpoint(0, c2);
    addvertex(0, prim, pt);
    
    vector c3 = p2;
    pt = addpoint(0, c3);
    addvertex(0, prim, pt);
    
    setprimgroup(0, "guide", prim, 1);
}

← 記事一覧へ