曲線の描画

ベジエ曲線を描画する方法を説明します。

Processingではベジエ曲線を描画することもできます。

ベジエ曲線について、想像している曲線をコードで書くにはかなり慣れる必要があると思います。

曲線は次の関数で描画できます。

bezier(x1,y1,x2,y2,x3,y3,x4,y4)
x1(float): 始点のx座標
y1(float): 始点のy座標
x2(float): 1つ目の制御点のx座標
y2(float): 1つ目の制御点のy座標
x3(float): 2つ目の制御点のx座標
y3(float): 2つ目の制御点のy座標
x4(float): 終点のx座標
y4(float): 終点のy座標

次のコードは公式サイトのサンプルを引用していますが、bezier()で指定する座標の順番を少し変えています。

size(400,400);
noFill();
stroke(255, 102, 0);
line(340, 80, 40, 40);
line(360, 360, 60, 320);
stroke(0);
bezier(340, 80, 40, 40, 60, 320, 360, 360);
//bezier(340, 80, 40, 40, 360, 360, 60, 320);

4〜5行目はどのような曲線になるかわかるように補助線となっています。

7行目でこの2本の直線で指定している座標で曲線を描いています。

8行目はコメントにしていますが、座標の順番を変えると曲線が変わることを表しています。

Wikipediaに記載している説明を引用しどのようにこの曲線を描画しているかを説明します。

この曲線を描画するのに指定した座標をP0,P1,P2,P3としこれらは制御点になります。

このP0から各座標を接続した線分の比率t(0<t<1)の座標を使い次のように曲線となる座標を算出しています。

  1. 制御点を順に結んで得られる3つの線分 P0-P1, P1-P2, P2-P3(オレンジ線)をそれぞれ「t : 1 – t」の比率で分割する点、P4, P5, P6 を求めます。
  2. これらの点を順に結んで得られる2つの線分 P4-P5, P5-P6(水色線)を再びそれぞれ「t : 1 – t」の比率で分割する点 P7, P8 を求めます。
  3. この2点を結ぶ線分 P7-P8(赤線)をさらに「t : 1 – t」の比率で分割する点 P9 を求めると、この点がベジエ曲線上の点となります。

1〜3を線分の比率0 < t < 1 の範囲で繰り返し行うことにより、P0, P1, P2, P3 を制御点とするベジエ曲線を描くことができます。(出典:Wikipedia)

このとき座標の指定はP0->P1->P2->P3となり、始点->終点となります。「t : 1 – t」の比率で分割するときはすべての線分は始点から終点へ同じ比率で分割します。

そのため、上記コードでコメントとしているbezier()は、P0->P1->P3->P2となっているため、P2,P3の始点と終点は逆になるため曲線の形が変わります。

規則性のある線分の座標を使うと曲線のイメージをし易いです。

size(400,400);
noFill();
stroke(255, 102, 0);
line(50,50,50,350);
line(350,50,350,350);
line(50,50,350,50);
line(50,350,350,350);
stroke(0);
bezier(50,50,50,350,350,50,350,350);
bezier(50,50,350,50,50,350,350,350);

4〜5行目の線分は左と右の縦の線です。

6〜7行目の線分は上と下の横の線です。

9行目は縦の線分の座標からベジエ曲線を描画しています。

10行目は横の線分の座標からベジエ曲線を描画しています。

曲線を繋いだものを図形にすることもできます。

size(400,400);
noFill();
stroke(255, 102, 0);
stroke(0);
fill(0,255,0);
beginShape();
vertex(50,50);
bezierVertex(50,350,350,50,350,350);
bezierVertex(50,350,350,50,50,50);
endShape();

先ほどのコードで描画した曲線をつながっているところを図形にしています。

bezierVertex()を使うのですが、vertex()とは少し違う使い方をします。

最初に始点となる座標をvertex()で指定します。

7行目ではvertex()で始点となる(50,50)を指定しています。

8〜9行目でbezierVertex()を使って曲線を描くのですが、7行目で指定した座標の続きの座標の残り3つを指定します。

そのためbezierVertex()で指定する座標は3つです。

9行目のbezierVertex()は始点は7行目のvertex()と同じなので、続きの3つの指定します。

beginShape()とendShape()は多角形のときと同じく記録の開始と終了です。