ベジェ曲線の弧の長さ


23

参照: Math.SEの同じ質問

ベジェ曲線の弧長を見つけるにはどうすればよいですか?たとえば、線形ベジェ曲線の長さは次のとおりです。

length = sqrt(pow(x[1] - x[0], 2) + pow(y[1] - y[0], 2));

しかし、二次、三次、またはn度ベジェ曲線はどうでしょうか?

(私の目標は、サンプリング解像度を事前に推定することでしたので、次のポイントが前のポイントに触れているかどうかをチェックする時間を無駄にする必要はありません。)


1
曲線の長さを参照するように質問を言い換える必要があります。これは、はるかに単純な(および検索可能な)用語です。
スパー

私は数学でこれを投稿することをお勧めします、私はそこにいくつかの巧妙な顔がそれらの賢いウェブフォントの1つであなたに答えを与えると確信しています:p
Tor Valamo

2
@Torを(昨日)しましたが、非常に複雑であるため非実用的であると言われました。[ math.stackexchange.com/q/12186/2736 ]
Mateen Ulhaq

おそらくクロソイド曲線/スプラインはベジェに代わるものであり、閉形式の弧長表現を持っていますが、これについてはまだよく知りません。(曲線に沿って等距離点を生成しようとしています。)カテナリーには、閉じた形のアーク長の式もありますか?
エンドリス14

回答:


9

3次ベジェの簡単な方法は、曲線をN個のセグメントに分割し、セグメントの長さを合計することです。

ただし、曲線の一部のみの長さ(たとえば、長さの30%まで)が必要になるとすぐに、円弧長のパラメーター化が有効になります。ベジエに関する私自身の質問の1つに、簡単なサンプルコードを使用して、かなり長い回答を投稿しまし


LEGO Mindstorms NXTでこれを行っていますが、これは非常に弱いプロセッサー(48Mhz)であるため、可能な限り高速にする必要があります。分割アプローチを使用して、ある程度の速度を節約し、十分に正確にします(「非リアルタイム」レンダリングの場合)。また、1.0/tresolution)と呼ばれる値を設定できるオプションがあるため、「リアルタイム」(低速のNXTでは最大で10fps)になります。すべての反復、、t += resolutionおよび新しいポイント/ラインが描画されます。とにかく、アイデアをありがとう。
Mateen Ulhaq

4

私はあなたがすでに得た答えに賛成ですが、任意の次数のベジエ曲線に使用できるシンプルでありながら強力な近似メカニズムを追加したいと思います。サブカーブのベースラインに対するサブカーブの差は、一定のイプシロンを下回ります。その場合、サブ曲線はそのベースラインによって近似できます。

実際、これはグラフィックスサブシステムがベジェ曲線を描画する必要がある場合に通常行われるアプローチだと思います。しかし、これについて私に引用しないでください、私は現時点で手元に参照を持っていません。

実際には、次のようになります(言語は無関係です)。

public static Line[] toLineStrip(BezierCurve bezierCurve, double epsilon) {
    ArrayList<Line> lines = new ArrayList<Line>();

    Stack<BezierCurve> parts = new Stack<BezierCurve>();
    parts.push(bezierCurve);

    while (!parts.isEmpty()) {
        BezierCurve curve = parts.pop();
        if (distanceToBaseline(curve) < epsilon) {
            lines.add(new Line(curve.get(0), curve.get(1)));
        } else {
            parts.addAll(curve.split(0.5));
        }
    }

    return lines.toArray(new Line[0]);
}

これは良いアプローチですが、高次ベジエ曲線の数値不安定性について聞いたことがあります。これには別のアイデアが必要です。高次曲線を小さな三次曲線に分割することです。
Mateen Ulhaq

また、最終目標が正確な推定値である場合、曲率の高い位置で推定値を過小評価しないように、線ではなく2次関数で近似することをお勧めします。
Mateen Ulhaq

2

ベジェ曲線のアーク長は、線形および二次曲線の場合にのみ閉じた形式です。キュービックの場合、閉じた解を持っているとは限りません。理由は、アーク長がラジカル積分によって定義されるためです。これは、2次多項式のみに対して閉じています。

参照用:ポイント(a、p)(b、q)および(c、r)の2次ベジェの長さは

(a ^ 2・(q ^ 2-2・q・r + r ^ 2)+ 2・a・(r-q)・(b・(p-r)+ c・(q-p))+( b・(p-r)+ c・(q-p))^ 2)・LN((√(a ^ 2-2・a・b + b ^ 2 + p ^ 2-2・p・q + q ^ 2)・√(a ^ 2 + 2・a・(c-2・b)+ 4・b ^ 2-4・b・c + c ^ 2 +(p-2・q + r)^ 2) + a ^ 2 + a・(c-3・b)+ 2・b ^ 2-b・c +(p-q)・(p-2・q + r))/(√(a ^ 2 + 2・a・(c-2・b)+ 4・b ^ 2-4・b・c + c ^ 2 +(p-2・q + r)^ 2)・√(b ^ 2-2・b・c + c ^ 2 + q ^ 2-2・q・r + r ^ 2)+ a・(b-c)-2・b ^ 2 + 3・b・c-c ^ 2 +(p-2・q + r)・(q-r)))/(a ^ 2 + 2・a・(c-2・b)+ 4・b ^ 2-4・b・c + c ^ 2 +(p-2・q + r)^ 2)^(3/2)+(√(a ^ 2-2・a・b + b ^ 2 + p ^ 2-2・p・q + q ^ 2)・(a ^ 2 + a・(c-3・b)+ 2・b ^ 2-b・c +(p-q)・(p-2・q + r))-√(b ^ 2-2・b・c + c ^ 2 + q ^ 2-2・q・r + r ^ 2)・(a・(b-c)-2・b ^ 2 + 3・b・c-c ^ 2 +(p-2・q + r)・(q-r)))/(a ^ 2 + 2・a・(c-2・b)+ 4・b ^ 2-4・b・c + c ^ 2 +(p-2・q + r)^ 2)

ここで、LNは自然対数であり、^は累乗を表し、√は平方根を表します。

したがって、LNの平方根は高価な操作であるため、多角形やシンプソンのルールのような統合スキームなど、他のルールによってアークをより簡単かつ安価に近似する必要があります。


2

3ポイントのベジエ(以下)の長さの閉形式表現を作成しました。私は4点以上の閉じたフォームを作成しようとしませんでした。これは、表現および処理が困難または複雑になる可能性が最も高いでしょう。ただし、Runge-Kutta積分アルゴリズムなどの数値近似手法は、アーク長の式を使用して積分することで非常にうまく機能します。MSE 上のRK45に関する私のQ&Aは、RK45の実装に役立つ場合があります。

ここでポイントとの3点ベジェの弧の長さのためにいくつかのJavaコードは、でありabおよびc

    v.x = 2*(b.x - a.x);
    v.y = 2*(b.y - a.y);
    w.x = c.x - 2*b.x + a.x;
    w.y = c.y - 2*b.y + a.y;

    uu = 4*(w.x*w.x + w.y*w.y);

    if(uu < 0.00001)
    {
        return (float) Math.sqrt((c.x - a.x)*(c.x - a.x) + (c.y - a.y)*(c.y - a.y));
    }

    vv = 4*(v.x*w.x + v.y*w.y);
    ww = v.x*v.x + v.y*v.y;

    t1 = (float) (2*Math.sqrt(uu*(uu + vv + ww)));
    t2 = 2*uu+vv;
    t3 = vv*vv - 4*uu*ww;
    t4 = (float) (2*Math.sqrt(uu*ww));

    return (float) ((t1*t2 - t3*Math.log(t2+t1) -(vv*t4 - t3*Math.log(vv+t4))) / (8*Math.pow(uu, 1.5)));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.