ポリラインをベジェ制御点に分割する

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

2次ベジェ曲線(3点の制御点)

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

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

// 描画には最低3点必要(2点以下なら直線のままにする)
if(len(pts) > 2)
{
    // Polylineがループしているか否かは始点と終点の距離で判断する
    int isClosed = 0;
    vector start_pos = point(0, "P", pts[0]);
    vector end_pos = point(0, "P", pts[-1]);
    if(length(end_pos - start_pos) < 0.001)
        isClosed = 1;

    // ループしている場合
    if(isClosed)
    {
        // 分割点を追加していく
        int midpoint[];
        for(int i = 0; i < len(pts)-1; i++)
        {
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector p2 = lerp(p0, p1, 0.5);
            
            int pt = addpoint(0, p2);
            append(midpoint, pt);
        }
        
        for(int i = 0; i < len(pts)-1; i++)
        {
            // 始点
            if(i == 0)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[0]);
                addvertex(0, prim, pts[1]);
                addvertex(0, prim, midpoint[1]);
            }
            else if(i > 0 && i < len(pts)-2)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[i]);
                addvertex(0, prim, pts[i+1]);
                addvertex(0, prim, midpoint[i+1]);
            }
            // 終点
            else
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[-1]);
                addvertex(0, prim, pts[-1]);
                addvertex(0, prim, midpoint[0]);
            }
        }
    }
    // ループしていない場合
    else
    {
        // 分割点を追加していく
        int midpoint[];
        for(int i = 1; i < len(pts)-2; i++)
        {
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector p2 = lerp(p0, p1, 0.5);
            
            int pt = addpoint(0, p2);
            append(midpoint, pt);
        }
        
        // 分割されたポリラインを生成していく
        for(int i = 0; i < len(pts) - 2; i++)
        {
            // 始点
            if(i == 0)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, pts[0]);
                addvertex(0, prim, pts[1]);
                addvertex(0, prim, midpoint[0]);
            }
            else if(i > 0 && i < len(pts)-3)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[i-1]);
                addvertex(0, prim, pts[i+1]);
                addvertex(0, prim, midpoint[i]);
            }
            // 終点
            else
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[i-1]);
                addvertex(0, prim, pts[i+1]);
                addvertex(0, prim, pts[i+2]);
            }
        }
    }
    
    // 元のポリラインを削除
    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 div = len(pts) / 2;
        
        // 2で割った余りがあれば最後の組みがベジェ2次曲線になる
        int mod = len(pts) % 2;
        
        if (mod > 0)
             div += 1;
        
        for(int i = 0; i < div; i++)
        {
            if(i == div-1 && mod > 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 div = (len(pts) - 2) / 2;
        
        // 2で割った余りがあれば最後の組みがベジェ2次曲線になる
        int mod = (len(pts) - 2) % 2;
        
        if (mod > 0)
            div += 1;
        
        for(int i = 0; i < div; i++)
        {
            // ポイントが3つ、または
            // 余りがあれば最後はベジェ2次曲線にする
            if( (i == 0 && div == 1 && mod > 0) || (i == div-1 && mod > 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 < div-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次)の制御点ラインへ分割する
// 両隣のエッジの長さの比で分割する(2025/05/05)
// Run Over: Primitives
// input0: Polyline
//
int pts[] = primpoints(0, @primnum);

// 描画には最低3点必要(2点以下なら直線のままにする)
if(len(pts) > 2)
{
    // Polylineがループしているか否かは始点と終点の距離で判断する
    int isClosed = 0;
    vector start_pos = point(0, "P", pts[0]);
    vector end_pos = point(0, "P", pts[-1]);
    if(length(end_pos - start_pos) < 0.001)
        isClosed = 1;

    // ループしている場合
    if(isClosed)
    {
        // 分割点を追加していく
        int midpoint[];
        for(int i = 0; i < len(pts)-1; i++)
        {
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector prev = point(0, "P", pts[i-1]);
            vector next = point(0, "P", pts[i+2]);
            
            // 始点
            if(i == 0)
            {
                p0 = point(0, "P", pts[0]);
                p1 = point(0, "P", pts[1]);
                prev = point(0, "P", pts[-2]);
                next = point(0, "P", pts[2]);
            }
            // 終点
            else if(i == len(pts)-2)
            {
                p0 = point(0, "P", pts[-2]);
                p1 = point(0, "P", pts[0]);
                prev = point(0, "P", pts[-3]);
                next = point(0, "P", pts[1]);
            }
            
            float t = length(p0-prev) / (length(p0-prev) + length(next-p1));
            vector p2 = lerp(p0, p1, t);
            
            int pt = addpoint(0, p2);
            append(midpoint, pt);
        }
        
        for(int i = 0; i < len(pts)-1; i++)
        {
            // 始点
            if(i == 0)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[0]);
                addvertex(0, prim, pts[1]);
                addvertex(0, prim, midpoint[1]);
            }
            else if(i > 0 && i < len(pts)-2)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[i]);
                addvertex(0, prim, pts[i+1]);
                addvertex(0, prim, midpoint[i+1]);
            }
            // 終点
            else
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[-1]);
                addvertex(0, prim, pts[-1]);
                addvertex(0, prim, midpoint[0]);
            }
        }
    }
    // ループしていない場合
    else
    {
        int midpoint[];
        for(int i = 1; i < len(pts)-2; i++)
        {
            vector p0 = point(0, "P", pts[i]);
            vector p1 = point(0, "P", pts[i+1]);
            vector p2 = point(0, "P", pts[i+2]);
            
            vector prev = point(0, "P", pts[i-1]);
            vector next = point(0, "P", pts[i+3]);
            
            float t = length(p1 - p0) / (length(p1-p0) + length(next-p2));
            vector p3 = lerp(p0, p1, t);
            
            int pt = addpoint(0, p3);
            append(midpoint, pt);
        }
        
        for(int i = 0; i < len(pts) - 2; i++)
        {
            // 始点
            if(i == 0)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, pts[0]);
                addvertex(0, prim, pts[1]);
                addvertex(0, prim, midpoint[0]);
            }
            else if(i > 0 && i < len(pts)-3)
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[i-1]);
                addvertex(0, prim, pts[i+1]);
                addvertex(0, prim, midpoint[i]);
            }
            // 終点
            else
            {
                int prim = addprim(0, "polyline");
                addvertex(0, prim, midpoint[i-1]);
                addvertex(0, prim, pts[i+1]);
                addvertex(0, prim, pts[i+2]);
            }
        }
    }
    
    // 元のポリラインを削除
    removeprim(0, @primnum, 1);
}
タイトルとURLをコピーしました