PHPでマンデブロ集合を描く

(1/1)
マンデブロ集合を 2 次元平面にプロットした魅惑的なフラクタル図形を PHP で描くプログラムを紹介する。

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

PHPでマンデブロ集合を描く

目次

サンプル・プログラム

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

マンデルブロ集合とは

マンデルブロ集合とは、
 mimetex 
で定義される複素数列 zn が n→∞ のときに発散しないという条件を満たす複素数 c の集合である。
ここで複素数 c を  mimetex  と表し、c を XY 平面上の点(a, b)とプロットしてゆくと、冒頭のようなフラクタル図形が得られる。

さて、高校数学で登場する複素数だが、実生活では使用しない「数」と誤解していないだろうか。
19 世紀に複素数を使う複素力学系が登場する。そして、光や電波、音波などの「」を物理学的に記述するのに複素数が利用されるようになった。スマホのノイズキャンセリングや送受信電波制御にも複素数が使われているのである。

話をフラクタル図形に戻そう。
1975 年(昭和 50 年)、フランスの数学者ブノワ・マンデルブロは、図形の部分と全体が自己相似(再帰)になっているフラクタルという概念を提唱する。「PHP で樹木曲線を描く」「PHP で雪の結晶を描く」で紹介したのもフラクタル図形だ。
1979 年(昭和 54 年)、マンデルブロはコンピュータを使って充填ジュリア集合を 2 次元に描くことに成功した。これが冒頭のフラクタル図形である。このことから、マンデルブロ集合と呼ばれるようになった。
マンデルブロ集合を拡大すると、似たような図形が繰り返し現れるのだが、けっして同じ図形ではないとされている。樹木曲線や雪の結晶に比べて魅惑的な図形となっている。

2011 年(平成 23 年)1 月からフジテレビ系で放映されたアニメ『フラクタル』のオープニングで、美しいマンデルブロ集合のアニメーションが流れたことを記憶している方もいると思う。

準備:初期値

0021: //リリース・フラグ(公開時にはTRUEにすること)
0022: define('FLAG_RELEASE', FALSE);
0023: 
0024: //リファラ・チェック(直リン防止用;空文字ならチェックしない)
0025: //define('REFER_ON', 'www.pahoo.org');
0026: define('REFER_ON', '');
0027: 
0028: //表示サイズ(縦横ピクセル)
0029: define('SIZE', 600);
0030: 
0031: //パラメータ・テーブル
0032: // kl = 最大繰返し回数
0033: // 複素平面の範囲
0034: //   開始:rs=実部, is=虚部
0035: //   終了:re=実部,ie=虚部
0036: static $Table = array(
0037: array('kl'=>100, 'rs'=>-2.10, 're'=>+0.50, 'is'=>-1.35, 'ie'=>+1.35),
0038: array('kl'=>150, 'rs'=>-0.50, 're'=>+0.50, 'is'=>+0.25, 'ie'=>+1.35),
0039: array('kl'=>250, 'rs'=>-0.20, 're'=>+0.30, 'is'=>+0.55, 'ie'=>+1.10),
0040: array('kl'=>300, 'rs'=>-0.05, 're'=>+0.05, 'is'=>+0.70, 'ie'=>+0.80),
0041: array('kl'=>350, 'rs'=>-0.03, 're'=>+0.04, 'is'=>+0.71, 'ie'=>+0.79)
0042: );

上記の初期値は任意に変更が可能である。
マンデルブロ集合を描く複素平面の範囲は、配列 $Table に定義している。最初の配列は、マンデルブロ集合の全景を描くパラメータである。このパラメータを適当に変更することで、描画したい範囲を変更できる。配列の数も自由に増減できる。

解説:マンデブロ集合を描画

0195: /**
0196:  * マンデブロ集合を描画
0197:  * @param resource $img イメージストリーム
0198:  * @param int $ks 複素平面の縦横の分割数
0199:  * @param array $param パラメータ($Tableに準ずる)
0200:  * @return なし
0201: */
0202: function drawMandelbrot($img$ks$param) {
0203:     $rs = $param['rs'];
0204:     $re = $param['re'];
0205:     $is = $param['is'];
0206:     $ie = $param['ie'];
0207:     $kl = $param['kl'];
0208: 
0209:     $dr = ($re - $rs) / $ks;
0210:     $di = ($ie - $is) / $ks;
0211:     for ($cr = $rs$cr <= $re$cr += $dr) {
0212:         for ($ci = $is$ci <= $ie$ci += $di) {
0213:             $zr = $zi = 0.0;
0214:             $k = 0;
0215:             $flag = TRUE;
0216:             //複素関数 f(z)
0217:             while (1) {
0218:                 $k++;
0219:                 if ($k > $kl) {
0220:                     $flag = FALSE;
0221:                     break;
0222:                 }
0223:                 $r = $zr * $zr - $zi * $zi + $cr;  //f(z)=Z*Z+A の実部
0224:                 $i = 2 * $zr * $zi + $ci;         //f(z)=Z*Z+A の虚部
0225:                 if (($r * $r + $i * $i) > 4) {        //Znが発散した場合は描画
0226:                     $flag = TRUE;
0227:                     break;
0228:                 }
0229:                 $zr = $r;
0230:                 $zi = $i;
0231:             }
0232:             //描画
0233:             if ($flag) {
0234:                 list($r$g$b) = hsv2rgb($k / $kl, 1.0, 1.0);
0235:                 $color = imagecolorallocate($img$r * 255, $g * 255, $b * 255);
0236:                 $x = (SIZE / ($re - $rs)) * ($cr - $rs);
0237:                 $y = (SIZE / ($ie - $is)) * ($ci - $is);
0238:                 imagesetpixel($img$x$y$color);
0239:             }
0240:         }
0241:     }
0242: }

ユーザー関数 drawMandelbrot は、冒頭の複素数列の定義にしたがってマンデルブロ集合を描くものである。

解説:HSV→RGB変換

0152: /**
0153:  * HSV→RGB変換
0154:  * @param resource $img イメージストリーム
0155:  * @param double ($x1, $y1) - ($x1, $y2)  線分の座標
0156:  * @return -
0157: */
0158: function hsv2rgb($h$s$v) {
0159:     $r = $g = $b = $v;
0160:     if ($s > 0.0) {
0161:         $h *= (float)6.0;
0162:         $i = (int)$h;
0163:         $f = $h - (float)$i;
0164:         switch ($i) {
0165:             default:
0166:             case 0:
0167:                 $g *= 1 - $s * (1 - $f);
0168:                 $b *= 1 - $s;
0169:                 break;
0170:             case 1:
0171:                 $r *= 1 - $s * $f;
0172:                 $b *= 1 - $s;
0173:                 break;
0174:             case 2:
0175:                 $r *= 1 - $s;
0176:                 $b *= 1 - $s * (1 - $f);
0177:                 break;
0178:             case 3:
0179:                 $r *= 1 - $s;
0180:                 $g *= 1 - $s * $f;
0181:                 break;
0182:             case 4:
0183:                 $r *= 1 - $s * (1 - $f);
0184:                 $g *= 1 - $s;
0185:                 break;
0186:             case 5:
0187:                 $g *= 1 - $s;
0188:                 $b *= 1 - $s * $f;
0189:                 break;
0190:         }
0191:     }
0192:     return array($r$g$b);
0193: }

マンデルブロ集合の着色はレインボーカラーを採用した。
レインボーカラーは、HSV色空間において色相(H)だけ変化するものである。そこで、ユーザー関数 hsv2rgb を用意し、HSV色空間から RGB へ変換することができるようにした。

参考サイト

(この項おわり)
header