PHPでベジエ曲線を描く

(1/1)
ベジエ曲線(Bézier Curve)は、コンピュータ・グラフィックで滑らかな曲線を描く時に使われるもので、HTMLのSVGやcanvasで使えるほか、PHPでもメソッド ImagickDraw::bezier を使って描くことができる。
今回は、これらの機能を使わず、PHPで数式をプログラミングし、任意次元のベジエ曲線を描くプログラムを作る。

(2022年4月24日)パラメータ定数化,PHP8対応,リファラ・チェック改良

目次

サンプル・プログラム:実行例

PHPでベジエ曲線を描く

サンプル・プログラム

圧縮ファイルの内容
BezierCurve.phpサンプル・プログラム本体

ベジエ曲線とは

ベジエ曲線の軌跡は、バーンスタイン基底関数によって次のように表現できる。
 mimetex 
2点間を結ぶ直線
まず、2点P0, P1 を結ぶ直線を考える。
2次ベジエ曲線
3点P0, P1, P2 を通るベジエ曲線が左図である。個の3点を制御点と呼び、始点と終点を含み、軌跡は途中の点に引っ張られるが、通過はしない。
制御点が3つあるものを2次ベジエ曲線と呼ぶ。
3次ベジエ曲線
制御点が4つになったものが、左図の3次ベジエ曲線となる。
SVGやcanvas、Adobe Flash Player 11.0以降では3次ベジエ曲線まで描くことができる。

準備:制御点

  42: //表示幅(ピクセル)
  43: define('WIDTH', 600);
  44: //表示高(ピクセル)
  45: define('HEIGHT', 400);
  46: //マージン(ピクセル)
  47: define('MARGIN', 20);
  48: 
  49: //制御点
  50: $p = array(
  51: array(MARGIN, MARGIN),                      //制御点(0) 始点
  52: array(MARGIN, HEIGHT - MARGIN),             //制御点(1)
  53: array(WIDTH - MARGIN, MARGIN),              //制御点(2)
  54: array(WIDTH - MARGIN, HEIGHT - MARGIN),     //制御点(3) 終点
  55: );

配列変数 $p に制御点の座標(X, Y)を用意する。
ここでは、制御点が4つある3次ベジエ曲線を描くが、制御点の座標及び数(次数)は任意に設定可能である。

解説:ベジエ曲線の座標計算

 214: /**
 215:  * ベジエ曲線の座標計算
 216:  * @param   array  $p[$n][0] 制御点のX座標
 217:  *                       [1] 制御点のY座標
 218:  *                   $n = 0 は始点
 219:  * @param   float  $t 0.0≦$t≦1.0
 220:  * @return  array(X, Y)
 221: */
 222: function BezierCurve($p, $t) {
 223:     $len = count($p);
 224:     if ($len == 1)  return $p[0];
 225: 
 226:     $left  = BezierCurve(array_slice($p, 0, $len - 1), $t);
 227:     $right = BezierCurve(array_slice($p, 1, $len), $t);
 228: 
 229:     return array((int)((1 - $t* $left[0+ $t * $right[0]), (int)((1 - $t* $left[1+ $t * $right[1]));
 230: }

これを再帰手続きで実装したのが、ユーザー関数 BezierCurve である。
呼び出す側で、引数 $t を0.0から1.0の間で変化させることで、対応する座標(X, Y)を配列として戻す。

解説:ベジエ曲線を描く

 232: /**
 233:  * ベジエ曲線を描く
 234:  * @param   array  $p[$n][0] 制御点のX座標
 235:  *                       [1] 制御点のY座標
 236:  *                   $n = 0 は始点
 237:  * @param   obj   $image イメージストリーム
 238:  * @param   int   $color 色ID(描画色)
 239:  * @param   int   $thick 太さ(省略時=1)
 240:  * @return  array(X, Y)
 241: */
 242: function drawBezierCurve($p, $image, $color, $thick=1) {
 243:     $n = count($p- 1;
 244: 
 245:     //始点
 246:     list($x1, $y1) = array($p[0][0], $p[0][1]);
 247: 
 248:     //ベジエ曲線
 249:     for ($t = 0$t <1$t +0.01) {
 250:         list($x2, $y2) = BezierCurve($p, $t);
 251:         imagesetthickness($image, $thick);
 252:         $res = imageline($image, $x1, $y1, $x2, $y2, $color);
 253:         if ($res == FALSE)  return FALSE;
 254:         list($x1, $y1) = array($x2, $y2);
 255:     }
 256: 
 257:     //終点
 258:     list($x2, $y2) = array($p[$n][0], $p[$n][1]);
 259:     imagesetthickness($image, $thick);
 260:     $res = imageline($image, $x1, $y1, $x2, $y2, $color);
 261: 
 262:     return $res;
 263: }

ユーザー関数 drawBezierCurve は、前述の BezierCurve を呼び出し、ベジエ曲線を描く。

参考サイト

(この項おわり)
header