ベジェ曲線のガイドカーブをつくる

ガイド用に作成したポリラインをベジェ曲線用に分割していく。ループにも対応しています。

2次ベジェ曲線用(3点のカーブ)

最初と最後以外の直線を分割して、3点ずつカーブをつくり、つないでいく。

//
// ポリラインをベジェ曲線(2次)のガイドラインへ分割する
//
// Run Over: Primitives
// input0: Polyline
//
int pts[] = primpoints(0, @primnum);

// 描画には最低3点必要(2点以下なら直線のままにする)
if(len(pts) > 2)
{
    // Polylineが連環しているか否か
    int isClosed = primintrinsic(0, "closed", 0);
    
    if(isClosed)
    {
        for(int i = 0; i < len(pts); i++)
        {
            // ベジェ曲線のための3点を選ぶ
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[(i+1)%len(pts)]);
            vector p2 = point(0, "P", pts[(i+2)%len(pts)]);
            
            p0 = (p0 + p1) / 2;
            p2 = (p1 + p2) / 2;
            
            // ポリラインを生成
            int prim = addprim(0, "polyline");
            int pt = addpoint(0, p0);
            addvertex(0, prim, pt);
            pt = addpoint(0, p1);
            addvertex(0, prim, pt);
            pt = addpoint(0, p2);
            addvertex(0, prim, pt);
            
            float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
            setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));

        }
    }
    else
    {
        for(int i = 0; i < len(pts) - 2; i++)
        {
            // ベジェ曲線のための3点を選ぶ
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector p2 = point(0, "P", pts[i+2]);
            
            // 始点
            if(i == 0)
            {
                if(len(pts) > 3)
                    p2 = (p1 + p2) / 2;
            }
            // 中間のポイント
            else if(i > 0 && i < len(pts)-3)
            {
                p0 = (p0 + p1) / 2;
                p2 = (p1 + p2) / 2;
            }
            // 終点(の2つ前)
            else
            {
                p0 = (p0 + p1) / 2;
            }
            
            // ポリラインを生成
            int prim = addprim(0, "polyline");
            int pt = addpoint(0, p0);
            addvertex(0, prim, pt);
            pt = addpoint(0, p1);
            addvertex(0, prim, pt);
            pt = addpoint(0, p2);
            addvertex(0, prim, pt);
            
            float iteration = (len(pts)-2) * random(i);
            float hue = (iteration / (float)((len(pts)-2) * 1)) * -1 + 0.6;
            setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));
        }
    }
    
    // 元のポリラインを削除
    removeprim(0, @primnum, 1);
}

3次ベジェ曲線用(4点のカーブ)

カーブのポイント数から2を引き、
2で割った商→3次ベジェ曲線の数
余りがあれば→最後の組が2次のベジェ曲線

//
// ポリラインをベジェ曲線(3次)のガイドラインへ分割する
//
// Run Over: Primitives
// input0: Polyline
//
int pts[] = primpoints(0, @primnum);

// 描画には最低3点必要(2点以下なら直線のままにする)
if(len(pts) > 2)
{
    // Polylineが連環しているか否か
    int isClosed = primintrinsic(0, "closed", 0);
    
    if(isClosed)
    {
        // ポイント総数N(N角形)から2で割った数がベジェ3次曲線の組数
        int q = len(pts) / 2;
        
        // 2で割った余りがあれば最後の組みがベジェ2次曲線になる
        int r = len(pts) % 2;
        
        if (r > 0) q += 1;
        
        for(int i = 0; i < q; i++)
        {
            if(i == q-1 && r > 0)
            {
                // ベジェ2次曲線のための3点を選ぶ
                vector p0 = point(0, "P", pts[i*2]);
                vector p1 = point(0, "P", pts[(i*2+1)%len(pts)]);
                vector p2 = point(0, "P", pts[(i*2+2)%len(pts)]);
                
                p0 = (p0 + p1) / 2;
                p2 = (p1 + p2) / 2;
    
                // ポリラインを生成
                int prim = addprim(0, "polyline");
                int pt = addpoint(0, p0);
                addvertex(0, prim, pt);
                pt = addpoint(0, p1);
                addvertex(0, prim, pt);
                pt = addpoint(0, p2);
                addvertex(0, prim, pt);
                
                float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
                setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));

            }
            else
            {
                // ベジェ曲線のための4点を選ぶ
                vector p0 = point(0, "P", pts[i*2]);
                vector p1 = point(0, "P", pts[(i*2+1)%len(pts)]);
                vector p2 = point(0, "P", pts[(i*2+2)%len(pts)]);
                vector p3 = point(0, "P", pts[(i*2+3)%len(pts)]);
                
                p0 = (p0 + p1) / 2;
                p3 = (p2 + p3) / 2;
                
                // ポリラインを生成
                int prim = addprim(0, "polyline");
                int pt = addpoint(0, p0);
                addvertex(0, prim, pt);
                pt = addpoint(0, p1);
                addvertex(0, prim, pt);
                pt = addpoint(0, p2);
                addvertex(0, prim, pt);
                pt = addpoint(0, p3);
                addvertex(0, prim, pt);
                
                float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
                setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));

            }
        }
            
    }
    else
    {
        // ポイント総数から-2して2で割った数がベジェ3次曲線の組数
        int q = (len(pts) - 2) / 2;
        
        // 2で割った余りがあれば最後の組みがベジェ2次曲線になる
        int r = (len(pts) - 2) % 2;
        
        if (r > 0) q += 1;
        
        for(int i = 0; i < q; i++)
        {
            // ポイントが3つ、または
            // 余りがあれば最後はベジェ2次曲線にする
            if( (i == 0 && q == 1 && r > 0) || (i == q-1 && r > 0))
            {
                // ベジェ2次曲線のための3点を選ぶ
                vector p0 = point(0, "P", pts[i*2]);
                vector p1 = point(0, "P", pts[i*2+1]);
                vector p2 = point(0, "P", pts[i*2+2]);
                
                if(i > 0)
                    p0 = (p0 + p1) / 2;

                // ポリラインを生成
                int prim = addprim(0, "polyline");
                int pt = addpoint(0, p0);
                addvertex(0, prim, pt);
                pt = addpoint(0, p1);
                addvertex(0, prim, pt);
                pt = addpoint(0, p2);
                addvertex(0, prim, pt);
                
                float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
                setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));

            }
            else
            {
                // 3次ベジェ曲線のための4点を選ぶ
                vector p0 = point(0, "P", pts[i*2]);
                vector p1 = point(0, "P", pts[i*2+1]);
                vector p2 = point(0, "P", pts[i*2+2]);
                vector p3 = point(0, "P", pts[i*2+3]);
                
                // 始点
                if(i == 0)
                {
                    if(len(pts) > 4)
                        p3 = (p2 + p3) / 2;
                }
                // 中間のポイント
                else if(i > 0 && i < q-1)
                {
                    p0 = (p0 + p1) / 2;
                    p3 = (p2 + p3) / 2;
                }
                // 終点(の2つ前)
                else
                {
                    p0 = (p0 + p1) / 2;
                }
                
                // ポリラインを生成
                int prim = addprim(0, "polyline");
                int pt = addpoint(0, p0);
                addvertex(0, prim, pt);
                pt = addpoint(0, p1);
                addvertex(0, prim, pt);
                pt = addpoint(0, p2);
                addvertex(0, prim, pt);
                pt = addpoint(0, p3);
                addvertex(0, prim, pt);
                
                float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
                setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));

            }
        }
    }
    
    // 元のポリラインを削除
    removeprim(0, @primnum, 1);
}

カーブの長さの比でラインを分割する

2次ベジェ曲線用と同じ3点のカーブで分割していくが、中間点の位置を隣の辺の長さの比にしている。

//
// ポリラインをベジェ曲線(2次)のガイドラインへ分割する
// 両隣のエッジの長さの比で分割する
//
// Run Over: Primitives
// input0: Polyline
//
int pts[] = primpoints(0, @primnum);

// 始点と終点が同じインデックスで取得されてしまう場合は最後のインデックスを削除する
if(pts[0] == pts[-1])
    removeindex(pts, -1);
//printf('pts:' + sprintf('%g', pts) + '\n');

if(len(pts) > 1)
{
    // Polylineが連環しているか否か
    int isClosed = primintrinsic(0, "closed", 0);
    
    if(isClosed)
    {
        // 連環している場合は終点が始点と同じなのでその1つ前はpts[-2]になる
        for(int i = 0; i < len(pts); i++)
        {
            // 3点を選ぶ
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector p2 = point(0, "P", pts[i+2]);
            
            if(i == 0)
            {
                // p(-1)-p0、p1-p2の比でp0をスライド
                // p0-p1とp2-p3の比でp2をスライド
                vector prev = point(0, "P", pts[i-1]);
                
                vector p3 = point(0, "P", pts[i+3]);
                float t0 = length(p0 - prev) / (length(p0 - prev) + length(p2 - p1));
                float t1 = length(p1 - p0) / (length(p1 - p0) + length(p3 - p2));
                p0 = p0 * (1-t0) + p1 * t0;
                p2 = p1 * (1-t1) + p2 * t1;
            }
            // 
            else if(i > 0 && i < len(pts)-1)
            {
                // p(-1)-p0、p1-p2の比でp0をスライド
                // p0-p1とp2-p3の比でp2をスライド
                vector prev = point(0, "P", pts[i-1]);
                vector p3 = point(0, "P", pts[(i+3)%len(pts)]);
                float t0 = length(p0 - prev) / (length(p0 - prev) + length(p2 - p1));
                float t1 = length(p1 - p0) / (length(p1 - p0) + length(p3 - p2));
                p0 = p0 * (1-t0) + p1 * t0;
                p2 = p1 * (1-t1) + p2 * t1;
            }
            // 終点と終点のひとつ前
            else
            {
                // p(-1)-p0、p1-p2の比でp0をスライド
                vector prev = point(0, "P", pts[i-1]);
                p1 = point(0, "P", pts[(i+1)%len(pts)]);
                p2 = point(0, "P", pts[(i+2)%len(pts)]);
                vector p3 = point(0, "P", pts[(i+3)%len(pts)]);
                float t0 = length(p0 - prev) / (length(p0 - prev) + length(p2 - p1));
                float t1 = length(p1 - p0) / (length(p1 - p0) + length(p3 - p2));
                p0 = p0 * (1-t0) + p1 * t0;
                p2 = p1 * (1-t1) + p2 * t1;
            }
            
            //
            // ポリラインを生成
            //
            {
                int prim = addprim(0, "polyline");
                int pt = addpoint(0, p0);
                addvertex(0, prim, pt);
                pt = addpoint(0, p1);
                addvertex(0, prim, pt);
                pt = addpoint(0, p2);
                addvertex(0, prim, pt);
                
                float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
                setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));
            }
        }
    }
    else
    {
        for(int i = 0; i < len(pts)-2; i++)
        {
            // 3点を選ぶ
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector p2 = point(0, "P", pts[i+2]);
            
            // 始点
            if(i == 0)
            {
                // p0-p1とp2-p3の比でp2の位置を移動する
                if(len(pts) > 3)
                {
                    vector p3 = point(0, "P", pts[i+3]);
                    float t = length(p1 - p0) / (length(p1 - p0) + length(p3- p2));
                    p2 = p1 * (1 - t) + p2 * t;
                }
            }
            // 
            else if(i > 0 && i < len(pts)-3)
            {
                // p(-1)-p0、p1-p2の比でp0をスライド
                // p0-p1とp2-p3の比でp2をスライド
                vector prev = point(0, "P", pts[i-1]);
                vector p3 = point(0, "P", pts[i+3]);
                float t0 = length(p0 - prev) / (length(p0 - prev) + length(p2 - p1));
                float t1 = length(p1 - p0) / (length(p1 - p0) + length(p3 - p2));
                p0 = p0 * (1-t0) + p1 * t0;
                p2 = p1 * (1-t1) + p2 * t1;
            }
            // 終点(の2つ前)
            else
            {
                // p(-1)-p0、p1-p2の比でp0をスライド
                vector prev = point(0, "P", pts[i-1]);
                float t = length(p0 - prev) / (length(p0 - prev) + length(p2 - p1));
                p0 = p0 * (1-t) + p1 * t;
            }
            
            //
            // ポリラインを生成
            //
            int prim = addprim(0, "polyline");
            int pt = addpoint(0, p0);
            addvertex(0, prim, pt);
            pt = addpoint(0, p1);
            addvertex(0, prim, pt);
            pt = addpoint(0, p2);
            addvertex(0, prim, pt);
            
            // デバッグのためのカラー
            float hue = (i / (float)((len(pts)-2) * 2)) * -1 + 0.6;
            setprimattrib(0, "Cd", prim, hsvtorgb(hue, 1, 1));
        }
    }
    // 元のポリラインを削除
    removeprim(0, @primnum, 1);
}
タイトルとURLをコピーしました