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次ベジエ曲線まで描くことができる。

準備:制御点

0042: //表示幅(ピクセル)
0043: define('WIDTH', 600);
0044: //表示高(ピクセル)
0045: define('HEIGHT', 400);
0046: //マージン(ピクセル)
0047: define('MARGIN', 20);
0048: 
0049: //制御点
0050: $p = array(
0051: array(MARGINMARGIN),                      //制御点(0) 始点
0052: array(MARGINHEIGHT - MARGIN),              //制御点(1)
0053: array(WIDTH - MARGINMARGIN),               //制御点(2)
0054: array(WIDTH - MARGINHEIGHT - MARGIN),       //制御点(3) 終点
0055: );

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

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

0214: /**
0215:  * ベジエ曲線の座標計算
0216:  * @param   array  $p[$n][0] 制御点のX座標
0217:  *                       [1] 制御点のY座標
0218:  *                   $n = 0は始点
0219:  * @param   float  $t 0.0≦$t≦1.0
0220:  * @return  array(X, Y)
0221: */
0222: function BezierCurve($p$t) {
0223:     $len = count($p);
0224:     if ($len == 1)  return $p[0];
0225: 
0226:     $left  = BezierCurve(array_slice($p, 0, $len - 1), $t);
0227:     $right = BezierCurve(array_slice($p, 1, $len), $t);
0228: 
0229:     return array((int)((1 - $t) * $left[0] + $t * $right[0]), (int)((1 - $t) * $left[1] + $t * $right[1]));
0230: }

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

解説:ベジエ曲線を描く

0232: /**
0233:  * ベジエ曲線を描く
0234:  * @param   array  $p[$n][0] 制御点のX座標
0235:  *                       [1] 制御点のY座標
0236:  *                   $n = 0は始点
0237:  * @param   obj   $imageイメージストリーム
0238:  * @param   int   $color 色ID(描画色)
0239:  * @param   int   $thick太さ(省略時=1)
0240:  * @return  array(X, Y)
0241: */
0242: function drawBezierCurve($p$image$color$thick=1) {
0243:     $n = count($p) - 1;
0244: 
0245:     //始点
0246:     list($x1$y1) = array($p[0][0]$p[0][1]);
0247: 
0248:     //ベジエ曲線
0249:     for ($t = 0; $t <= 1; $t += 0.01) {
0250:         list($x2$y2) = BezierCurve($p$t);
0251:         imagesetthickness($image$thick);
0252:         $res = imageline($image$x1$y1$x2$y2$color);
0253:         if ($res == FALSE)  return FALSE;
0254:         list($x1$y1) = array($x2$y2);
0255:     }
0256: 
0257:     //終点
0258:     list($x2$y2) = array($p[$n][0]$p[$n][1]);
0259:     imagesetthickness($image$thick);
0260:     $res = imageline($image$x1$y1$x2$y2$color);
0261: 
0262:     return $res;
0263: }

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

参考サイト

(この項おわり)
header