7

html5キャンバスで楕円形を描きたいのですが、stackoverflowでそのための良い方法を見つけましたが、別の質問があります。

function drawEllipse(ctx, x, y, w, h) {
  var kappa = 0.5522848;
      ox = (w / 2) * kappa, // control point offset horizontal
      oy = (h / 2) * kappa, // control point offset vertical
      xe = x + w,           // x-end
      ye = y + h,           // y-end
      xm = x + w / 2,       // x-middle
      ym = y + h / 2;       // y-middle

  ctx.beginPath();
  ctx.moveTo(x, ym);
  ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  ctx.closePath();
  ctx.stroke();
}

上記のリンクのメソッドでは、bezierCurveToを使用して楕円を描画していますが、bezierCurveToを4回描画しています。しかし、 2つのbezierCurveToだけで楕円を描くことができると思います。次のようになります。

ここに画像の説明を入力してください

でも数学が苦手ですが、「コントロールポイント」と「オーバルポイント」の関係を教えてもらえますか?または、楕円を描くために4つのベジェ曲線を描く必要がありますか?

みんなありがとう

4

5 に答える 5

6

私のバックグラウンドは数学ではないので、間違っていれば誰かが私を修正すると確信していますが、私の理解から、2つの立方ベジェ曲線だけで楕円のかなり良い近似を描くことができます、座標は少しトリッキーになります。

楕円形の点と制御点の関係についての質問に答えるには、補間に精通している場合は選択した点から、そうでない場合は最初からこのビデオを見るのが最善だと思います。短いので心配しないでください。

おそらく遭遇する問題の1つは、上から始めてbezierCurveを実行すると、長方形の角(同じ幅と高さ)を制御点として楕円の下部に、楕円の幅が長方形よりも小さくなります。必要なサイズの.75倍。したがって、それに応じてコントロールポイントをスケーリングできます。

コントロールポイントのxは、次のように調整されます(幅が楕円の幅であり、原点からのオフセットを取得するために2で割ると仮定します)

var cpx = (width / .75) / 2;

幅と高さで遊んで、描かれた楕円を見ることができる視覚化をまとめます。

赤い楕円は私たちが描きたかった方法であり、内側の楕円はコントロールポイントを再配置しなかった場合にどのように描かれるかを示しています。線は、ビデオで示されたDeCasteljauのアルゴリズムを示しています。

これが視覚化のスクリーンショットです ここに画像の説明を入力してください

于 2013-01-05T11:15:07.373 に答える
2

楕円を描くのに必要なのは、2つの立方ベジェ曲線だけです。これは、指定した元の関数の引数を使用するDerekRのコードの簡略化されたバージョンです。ただし、xとyを楕円の中心にします。

jsFiddle

function drawEllipse(ctx, x, y, w, h) {
    var width_over_2 = w / 2;
    var width_two_thirds = w * 2 / 3;
    var height_over_2 = h / 2;

    ctx.beginPath();
    ctx.moveTo(x, y - height_over_2);
    ctx.bezierCurveTo(x + width_two_thirds, y - height_over_2, x + width_two_thirds, y + height_over_2, x, y + height_over_2);
    ctx.bezierCurveTo(x - width_two_thirds, y + height_over_2, x - width_two_thirds, y - height_over_2, x, y -height_over_2);
    ctx.closePath();
    ctx.stroke();
}
于 2013-12-14T10:31:52.783 に答える
2

BKHに感謝します。私は彼のコードを2つのベジェ曲線で使用して、任意の回転角度で楕円の描画を完成させました。また、ベジェ曲線によって描画された楕円とネイティブのellipse()関数(現在はChromeでのみ実装されています)の比較デモを作成しました。

function drawEllipseByBezierCurves(ctx, x, y, radiusX, radiusY, rotationAngle) {
var width_two_thirds = radiusX * 4 / 3;

var dx1 = Math.sin(rotationAngle) * radiusY;
var dy1 = Math.cos(rotationAngle) * radiusY;
var dx2 = Math.cos(rotationAngle) * width_two_thirds;
var dy2 = Math.sin(rotationAngle) * width_two_thirds;

var topCenterX = x - dx1;
var topCenterY = y + dy1;
var topRightX = topCenterX + dx2;
var topRightY = topCenterY + dy2;
var topLeftX = topCenterX - dx2;
var topLeftY = topCenterY - dy2;

var bottomCenterX = x + dx1;
var bottomCenterY = y - dy1;
var bottomRightX = bottomCenterX + dx2;
var bottomRightY = bottomCenterY + dy2;
var bottomLeftX = bottomCenterX - dx2;
var bottomLeftY = bottomCenterY - dy2;

ctx.beginPath();
ctx.moveTo(bottomCenterX, bottomCenterY);
ctx.bezierCurveTo(bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY);
ctx.bezierCurveTo(topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY);
ctx.closePath();
ctx.stroke();

}

于 2014-02-26T08:30:59.127 に答える
1

これについては、 http://pomax.github.io/bezierinfo/#circles_cubicで少し数学に基づいて説明されていますが、要点は、通常、4分の1回転以上に3次ベジェ曲線を使用することはお勧めできません。ありがたいことに、4つの曲線を使用すると、必要な制御点を簡単に見つけることができます。円から始めます。この場合、各四分円は(1,0)-(1,0.55228)-(0.55228,1)-(0,1)で、楕円の座標がスケーリングされます。+/-記号を入れ替えて4回描画し、完全な円を作成し、寸法を拡大縮小して楕円を作成します。

2つの曲線を使用する場合、座標は(1,0)-(1,4 / 3)-(-1,4 / 3)-(-1,0)になり、楕円に合わせてスケーリングされます。それでもアプリケーションでは十分に適切に見える場合があります。これは、描画が最終的にどれだけ大きくなるかに少し依存します。

于 2013-04-19T11:59:03.943 に答える
0

数学的に証明できるのは、どの程度のベジェ曲線でも円を描くことができないということです。近似することで「ほぼ円」を作ることができます。

[0,0]の周りに4分の1の円を描きたいとします。キュービックベジェ座標は次のとおりです。

[0   , 1   ]
[0.55, 1   ]
[1   , 0.55]
[1   , 0   ]

これは非常に良い近似です。線形に変換して、エルピスを取得します。

于 2013-11-07T17:54:54.623 に答える