web-dev-qa-db-ja.com

与えられた3つの点を通る2次ベジエ曲線を描きます

2Dに3つのポイントがあり、それらを通過する2次ベジェ曲線を描画したいと思います。中間制御点を計算するにはどうすればよいですか(x1およびy1 quadToのように)?私は大学で線形代数を知っていますが、これについて簡単な助けが必要です。

曲線も通過するように中間制御点を計算するにはどうすればよいですか?

25
Alex

P0、P1、P2を制御点、Pcを曲線を通過させる固定点とします。

次に、ベジェ曲線は次のように定義されます。

P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2

...ここで、tはゼロから1になります。

あなたの質問に対する答えは無限にあります。なぜなら、それはtの任意の値に対してあなたのポイントを通過する可能性があるからです...したがって、t = 0.5のように1つを選び、P1について解きます。

Pc = P0*.25 + P1*2*.25 + P2*.25

P1 = (Pc - P0*.25 - P2*.25)/.5

   = 2*Pc - P0/2 - P2/2

「P」値は(x、y)ペアであるため、方程式をxに1回、yに1回適用するだけです。

x1 = 2*xc - x0/2 - x2/2
y1 = 2*yc - y0/2 - y2/2

...ここで、(xc、yc)は通過させたいポイント、(x0、y0)は開始ポイント、(x2、y2)は終了ポイントです。これにより、t = 0.5で(xc、yc)を通過するベジェが得られます。

50
Nemo

JavaFXアプリケーションでNemos回答を使用しましたが、曲線の視覚的な転換点が常に選択した固定曲線(CP)に合うように、曲線を描くことが目標でした。

CP = ControlPoint
SP = StartPoint
EP = EndPoint
BP(t)= tが0から1の間であるベジェ曲線上の変数ポイント

これを達成するために、変数tを作成しました(0.5を修正しません)。選択したポイントCPがSPとEPの中間にない場合は、tを少し上下に変える必要があります。最初のステップとして、CPがに近いかどうかを知る必要があります。 SPまたはEP:distanceSPをCPとSP)、distanceEPをCPとEP間の距離とし、比率を次のように定義します。

ratio = (distanceSP - distanceEP) / (distanceSP + distanceEP);

次に、これを使用してtを上下に変化させます。

ratio = 0.5 - (1/3) * ratio;

注:これはまだ概算であり、1/3は試行錯誤によって選択されます。

これが私のJava関数です:(Point2DはJavaFXのクラスです)

private Point2D adjustControlPoint(Point2D start, Point2D end, Point2D visualControlPoint) {
    // CP = ControlPoint, SP = StartPoint, EP = EndPoint, BP(t) = variable Point on BeziérCurve where t is between 0 and 1
    // BP(t) = SP*t^2 + CP*2*t*(1-t) + EP*(1-t)^2
    // CP = (BP(t) - SP*t^2 - EP*(1-t)^2) / ( 2*t*(1-t) )
    // but we are missing t the goal is to approximate t
    double distanceStart  = visualControlPoint.distance(start);
    double distanceEnd    = visualControlPoint.distance(end);
    double ratio          = (distanceStart - distanceEnd) / (distanceStart + distanceEnd);
    // now approximate ratio to be t
    ratio = 0.5 - (1.0 / 3) * ratio;

    double ratioInv = 1 - ratio;
    Point2D term2 = start.multiply( ratio * ratio );
    Point2D term3 = end.multiply( ratioInv * ratioInv );
    double  term4 = 2 * ratio * ratioInv;

    return visualControlPoint.subtract(term2).subtract(term3).multiply( 1 / term4);
}

これがお役に立てば幸いです。

4
Zerlono

正確な中間点が必要ではなく、t(0から1)の値が必要な場合、式は次のようになります。

controlX = pointToPassThroughX/t - startX*t - endX*t;
controlY = pointToPassThroughY/t - startY*t - endY*t;

もちろん、これは中間点でも機能します。tを0.5に設定するだけです。シンプル! :-)

1
Craigo