JavaScript HTML5 キャンバスを使用して N 点を通る滑らかな曲線を描く方法は? 質問する

JavaScript HTML5 キャンバスを使用して N 点を通る滑らかな曲線を描く方法は? 質問する

描画アプリケーションでは、マウスの移動座標を配列に保存し、lineTo を使用して描画しています。 結果の線は滑らかではありません。 収集したすべてのポイント間に単一の曲線を作成するにはどうすればよいでしょうか。

グーグルで検索しましたが、線を描く関数は 3 つしか見つかりませんでした。サンプル ポイントが 2 つの場合は、単に を使用しますlineTo。サンプル ポイントが 3 つの場合はquadraticCurveTo、サンプル ポイントが 4 つの場合は を使用しますbezierCurveTo

bezierCurveTo(配列内の 4 つのポイントごとに を描画しようとしましたが、連続した滑らかな曲線ではなく、4 つのサンプル ポイントごとに折れ曲がってしまいます。)

5 個以上のサンプル ポイントを持つ滑らかな曲線を描画する関数を作成するにはどうすればよいでしょうか?

ベストアンサー1

後続のサンプルポイントを、互いに素な「curveTo」タイプの関数で結合する場合の問題は、曲線が交わる部分が滑らかではないことです。これは、2 つの曲線が終点を共有しているものの、完全に素な制御点の影響を受けているためです。1 つの解決策は、次の 2 つのサンプルポイント間の中間点に「曲線を合わせる」ことです。これらの新しい補間ポイントを使用して曲線を結合すると、終点で滑らかな遷移が得られます (1 回の反復では終点であったものが、コントロールポイント言い換えれば、2 つの分離した曲線には、今では多くの共通点があることになります。

このソリューションは、書籍「Foundation ActionScript 3.0 Animation: Making things move」から抜粋したものです。p.95 - レンダリング テクニック: 複数の曲線の作成。

注: このソリューションは、私の質問のタイトルである各ポイントを実際に描画するわけではありません (むしろ、サンプルポイントを通る曲線を近似しますが、サンプルポイントを通過することはありません)。しかし、私の目的 (描画アプリケーション) では、これで十分であり、視覚的に違いはわかりません。すべてのサンプルポイントを調べるという解決策もありますが、これははるかに複雑です(http://www.cartogrammar.com/blog/actionscript-curves-update/

近似法の描画コードは次のとおりです。

// move to the first point
   ctx.moveTo(points[0].x, points[0].y);


   for (var i = 1; i < points.length - 2; i++)
   {
      var xc = (points[i].x + points[i + 1].x) / 2;
      var yc = (points[i].y + points[i + 1].y) / 2;
      ctx.quadraticCurveTo(points[i].x, points[i].y, xc, yc);
   }
 // curve through the last two points
 ctx.quadraticCurveTo(points[i].x, points[i].y, points[i+1].x,points[i+1].y);

実行可能なスニペットとして:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const points = [
  {x: 50, y: 50},
  {x: 180, y: 100},
  {x: 75, y: 120},
  {x: 40, y: 40},
];

// move to the first point
ctx.moveTo(points[0].x, points[0].y);

for (var i = 1; i < points.length - 2; i++) {
  var xc = (points[i].x + points[i + 1].x) / 2;
  var yc = (points[i].y + points[i + 1].y) / 2;
  ctx.quadraticCurveTo(points[i].x, points[i].y, xc, yc);
}

// curve through the last two points
ctx.quadraticCurveTo(
  points[i].x,
  points[i].y,
  points[i + 1].x,
  points[i + 1].y
);
ctx.stroke();
<canvas width="600" height="600"></canvas>

おすすめ記事