PHPで雪の結晶を描く

(1/1)
PHPで雪の結晶を描く
PHP で樹木曲線を描く」の応用で、雪の結晶(のようなもの)を描いてみることにする。

樹木曲線の枝を 3 本に増やし、中心から角度を変えて複数生やしてやることで、雪の結晶のような図形ができあがる。

サンプル・プログラム

解説:再帰図形

0143: /**
0144:  * 結晶を増殖させる(再帰呼び出し)
0145:  * @param int $n 再帰の深さ
0146:  * @param float  $len 枝の長さ
0147:  * @param float  $fac 枝の発生位置
0148:  * @param double $angle 枝の傾き(ラジアン)
0149:  * @return -
0150: */
0151: function tree3($n$len$fac$angle) {
0152:     $turn = deg2rad(60);
0153: 
0154:     $dx = $len * sin($angle);
0155:     $dy = $len * cos($angle);
0156:     $this->setPenThick($n);
0157:     $this->movePen($dx$dyTRUE);
0158:     if ($n > 0) {
0159:         $this->tree3($n - 1, $len * $fac$fac$angle + $turn);
0160:         $this->tree3($n - 1, $len * $fac$fac$angle);
0161:         $this->tree3($n - 1, $len * $fac$fac$angle - $turn);
0162:     }
0163:     $this->movePen(0 - $dx, 0 - $dyFALSE);
0164: }
0165: 
0166: /**
0167:  * 雪の結晶を描く
0168:  * @param int   $corner 結晶の角の数
0169:  * @param int   $recur  再帰回数
0170:  * @param float $fac    枝の発生位置
0171:  * @return -
0172: */
0173: function CrystalSnow($corner$recur$fac) {
0174:     $angle = deg2rad(360 / $corner);     //回転角(度)
0175: 
0176:     $this->setPenThick($recur);
0177:     $this->movePen(4, 2, FALSE);
0178:     for ($i = 0; $i < $corner$i++) {
0179:         $this->tree3($recur, 1, $fac$angle * $i);
0180:     }
0181: }

主要処理はクラス pahooCrystalSnow として定義している。

再帰図形の描き方は、「PHP で樹木曲線を描く」とほぼ同じである。

ユーザー関数 CrystalSnow では、中心から結晶の角の数(デフォルトでは正六角形)だけ回転させ、tree3 を呼び出す。

tree3 は再帰呼び出しによる樹木曲線で、枝を 2 本から 3 本に増やしている。

解説:太さのある直線

0066: /**
0067:  * 太さのある直線を描画する
0068:  * @param obj  $image イメージストリーム
0069:  * @param float ($x1, $y1) - ($x1, $y2)  線分の座標
0070:  * @param int  $color ペンの色
0071:  * @param foat $thick ペンの太さ(省略時=1)
0072:  * @return bool TRUE:成功/FALSE:失敗
0073: */
0074: function imagelinethick($image$x1$y1$x2$y2$color$thick = 1) {
0075:     //太さ = 1
0076:     if ($thick == 1) {
0077:         return imageline($image$x1$y1$x2$y2$color);
0078:     }
0079:     //太さ > 1
0080:     $t = $thick / 2 - 0.5;
0081:     if ($x1 == $x2 || $y1 == $y2) {
0082:         return imagefilledrectangle($imageround(min($x1$x2) - $t), round(min($y1$y2) - $t), round(max($x1$x2) + $t), round(max($y1$y2) + $t), $color);
0083:     }
0084:     $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
0085:     $a = $t / sqrt(1 + pow($k, 2));
0086:     $points = array(
0087:         round($x1 - (1 + $k) * $a), round($y1 + (1 - $k) * $a),
0088:         round($x1 - (1 - $k) * $a), round($y1 - (1 + $k) * $a),
0089:         round($x2 + (1 + $k) * $a), round($y2 - (1 - $k) * $a),
0090:         round($x2 + (1 - $k) * $a), round($y2 + (1 + $k) * $a),
0091:     );
0092:     imagefilledpolygon($image$points, 4, $this->PenColor);
0093: 
0094:     return imagepolygon($image$points, 4, $this->PenColor);
0095: }

結晶の中心に行くほど太さがある直線になるよう、ユーザー関数 imagelinethick を用意した。

解説:各種パラメータ

0290: /**
0291:  * $_GET または $_POST から正規化した数値を取り出す
0292:  * @param string $type int:整数 float:浮動小数
0293:  * @param string $key キー
0294:  * @param mixed $min, $max 最小値、最大値
0295:  * @param string $errmsg エラーメッセージを格納する
0296:  * @return mixed 取得値/NULL:エラー
0297: */
0298: function getParameters(&$items) {
0299:     static $tbl_val = array(
0300:         //描画領域(正方形)の1辺の長さ(ピクセル)
0301:         'width'=>array('type'=>'float', 'min'=>100, 'max' => 1000, 'def'=>500),
0302:         //再帰回数
0303:         'recur'=>array('type'=>'int', 'min'=>1, 'max'=>8, 'def'=>6),
0304:         //結晶の角の数(何角形か)
0305:         'corner'=>array('type'=>'int', 'min'=>3, 'max'=>12, 'def'=>6),
0306:         //枝の発生位置(比率)
0307:         'fac'=>array('type'=>'float', 'min'=>0.2, 'max'=>0.8, 'def'=>0.55)
0308:     );
0309:     static $tbl_str = array(
0310:         //背景色
0311:         'bgcolor'=>array('pat'=>'/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i', 'def'=>'000000'),
0312:         //描画色
0313:         'color'=>array('pat'=>'/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i', 'def'=>'CCCCFF')
0314:     );
0315:     foreach ($tbl_val as $key=>$arr) {
0316:         $items[$key] = getValidNumber($key$arr['type'], $arr['min'], $arr['max'], $arr['def']);
0317:     }
0318:     foreach ($tbl_str as $key=>$arr) {
0319:         $items[$key] = '#' . getValidString($key$arr['pat'], $arr['def']);
0320:     }
0321: }

コメントに記したように、描画領域の大きさ、再帰回数、結晶の角の数など、パラメータとして指定できるようにしてある。

参考サイト

(この項おわり)
header