16

Android アプリケーションの 1 つに 3 次ベジエ曲線ロジックを実装しています。

カスタム ビューの onDraw でキャンバスに 3 次ベジエ曲線コードを実装しました。

// Path to draw cubic bezier curve
Path cubePath = new Path();

// Move to startPoint(200,200) (P0)
cubePath.moveTo(200,200);

// Cubic to with ControlPoint1(200,100) (C1), ControlPoint2(300,100) (C2) , EndPoint(300,200) (P1)
cubePath.cubicTo(200,100,300,100,300,200);

// Draw on Canvas
canvas.drawPath(cubePath, paint);

上記のコードを次の画像に視覚化します。

上記コードの出力

[更新しました]

Logic for selecting first control points, I've taken ,
baseX = 200 , baseY = 200 and curve_size = X of Endpoint - X of Start Point

Start Point     : x = baseX and y = baseY
Control Point 1 : x = baseX and y =  baseY - curve_size
Control Point 2 : x = baseX + curve_size and y =  baseY - curve_size
End Point       : x = baseX + curve_size and y = baseY

ユーザーがカーブの上の EndPoint を変更できるようにしたいのですが、新しい End ポイントに基づいて、キャンバスを無効にします。

しかし、問題は、Curve が 2 つの制御点によって維持されることです。これは、EndPoint の変更時に再計算する必要があります。

同様に、EndPoint が (300,200) から (250,250) に変化したときに新しいコントロール ポイントを見つけたいだけです。

次の画像のように:

新しいイメージ

曲線の形状が以前の終点と同じに維持される新しい終点に基づいて、2 つの新しい制御点を計算するのを手伝ってください。

検索時に次の参照リンクを参照します。

http://pomax.github.io/bezierinfo/

http://jsfiddle.net/hitesh24by365/jHbVE/3/

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

http://cubic-bezier.com/

この質問への回答として、参照リンクも高く評価されています。

4

4 に答える 4

12

端点を変更するということは、P1 に沿った回転と倍率という 2 つのことを意味します。

倍率 (s と呼びましょう) は len(p1 - p0) / len(p2 - p0) です。

回転係数 (r と呼びましょう)については、 Android の 3 点間の角度を計算することをお勧めします。これにより、プラットフォーム固有の実装も提供されますが、p0 に対して p1 をスケーリング/回転することで正確性を確認できます。取得する必要があります。結果としてp2。

次に、c1 と c2 に p0 に対するスケーリングと回転を適用します。便宜上、新しい c1 を「d1」、新しい d2 と呼びます。

d1 = rot(c1 - p0, factor) * s + p0
d2 = rot(c2 - p0, factor) * s + p0

rot() の疑似コードを定義する (ローテーションhttp://en.wikipedia.org/wiki/Rotation_%28mathematics%29 )

rot(point p, double angle){
  point q;
  q.x = p.x * cos(angle) - p.y * sin(angle);
  q.y = p.x * sin(angle) + p.y * cos(angle);
}

ベジエ曲線は、p1 を p2 に変更して、p0 に対してスケーリングおよび回転されます。

于 2013-04-19T10:40:41.327 に答える
6

まず、次の記事をご覧ください。

  1. ベジェ曲線
  2. なぜ B スプライン曲線
  3. B-スプライン曲線のまとめ

実装しようとしているのは、区分的な複合ベジエ曲線です。n コントロール ポイント (開始/終了を含む) の [概要] ページから、(n - 1)/3 個の区分ベジエ曲線を取得します。

制御点は文字通り曲線を形成します。新しい点で適切な制御点を与えないと、滑らかに接続されたベジェ曲線を作成できません。それらの生成は複雑すぎて、普遍的に受け入れられている方法がないため、機能しません。

余分な制御点を持たない/与えたくない場合は、Catmull-Rom スプラインを使用する必要があります。これはすべての制御点を通過し、C1 連続になります (導関数は曲線上の任意の点で連続します)。

java/android の Catmull Rom Spline のリンク:

要点は、コントロール ポイントがない場合は、3 次ベジエ曲線を使用しないことです。それらを生成することは問題であり、解決策ではありません。

于 2013-04-20T06:59:04.923 に答える
6

ここでは、下の 2 点がわかっている正方形を回転およびスケーリングしているようで、他の 2 点を計算する必要があります。2 つの既知の点は、他の 2 つの点と 2 つの三角形を形成するため、三角形の 3 番目の点を見つけるだけで済みます。終点が x1、y1 であるとします。

PointF c1 = calculateTriangle(x0, y0, x1, y1, true); //find left third point
PointF c2 = calculateTriangle(x0, y0, x1, y1, false); //find right third point

cubePath.reset();
cubePath.moveTo(x0, y0);
cubePath.cubicTo(c1.x, c1.y, c2.x, c2.y, x1, y1);


private PointF calculateTriangle(float x1, float y1, float x2, float y2, boolean left) {
                PointF result = new PointF(0,0);
                float dy = y2 - y1;
                float dx = x2 - x1;
                float dangle = (float) (Math.atan2(dy, dx) - Math.PI /2f);
                float sideDist = (float) Math.sqrt(dx * dx + dy * dy); //square
                if (left){
                    result.x = (int) (Math.cos(dangle) * sideDist + x1);
                    result.y = (int) (Math.sin(dangle) * sideDist + y1);                    
                }else{
                    result.x = (int) (Math.cos(dangle) * sideDist + x2);
                    result.y = (int) (Math.sin(dangle) * sideDist + y2);
                }
                return result;
            }

...

パスまたはイベントの形状の最初と最後のポイントの間にいくつのポイントがあるかは関係ありません。

//Find scale
Float oldDist = (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
Float newDist = (float) Math.sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0)); 
Float scale = newDist/oldDist;

//find angle
Float oldAngle = (float) (Math.atan2(y1 - y0, x1 - x0) - Math.PI /2f);
Float newAngle = (float) (Math.atan2(y2 - y0, x2 - x0) - Math.PI /2f);
Float angle = newAngle - oldAngle;

//set matrix
Matrix matrix = new Matrix();
matrix.postScale(scale, scale, x0, y0);
matrix.postRotate(angle, x0, y0);

//transform the path
cubePath.transform(matrix);
于 2013-04-24T17:38:25.117 に答える