サンプル・プログラム:実行例
サンプル・プログラム
MandelbrotSet.php | サンプル・プログラム本体 |
マンデルブロ集合とは
で定義される複素数列 zn が n→∞ のときに発散しないという条件を満たす複素数cの集合である。
ここで複素数cを と表し、cをXY平面上の点(a, b)とプロットしてゆくと、冒頭のようなフラクタル図形が得られる。
さて、高校数学で登場する複素数だが、実生活では使用しない「数」と誤解していないだろうか。
19世紀に複素数を使う複素力学系が登場する。そして、光や電波、音波などの「波」を物理学的に記述するのに複素数が利用されるようになった。スマホのノイズキャンセリングや送受信電波制御にも複素数が使われているのである。
話をフラクタル図形に戻そう。
1975年(昭和50年)、フランスの数学者ブノワ・マンデルブロは、図形の部分と全体が自己相似(再帰)になっているフラクタルという概念を提唱する。「PHPで樹木曲線を描く」「PHPで雪の結晶を描く」で紹介したのもフラクタル図形だ。
1979年(昭和54年)、マンデルブロはコンピュータを使って充填ジュリア集合を2次元に描くことに成功した。これが冒頭のフラクタル図形である。このことから、マンデルブロ集合と呼ばれるようになった。
マンデルブロ集合を拡大すると、似たような図形が繰り返し現れるのだが、けっして同じ図形ではないとされている。樹木曲線や雪の結晶に比べて魅惑的な図形となっている。
2011年(平成23年)1月からフジテレビ系で放映されたアニメ『フラクタル』のオープニングで、美しいマンデルブロ集合のアニメーションが流れたことを記憶している方もいると思う。
準備:初期値
0034: //表示サイズ(縦横ピクセル)
0035: define('SIZE', 600);
0036:
0037: //パラメータ・テーブル
0038: // kl = 最大繰返し回数
0039: // 複素平面の範囲
0040: // 開始:rs=実部, is=虚部
0041: // 終了:re=実部,ie=虚部
0042: static $Table = array(
0043: array('kl'=>100, 'rs'=>-2.10, 're'=>+0.50, 'is'=>-1.35, 'ie'=>+1.35),
0044: array('kl'=>150, 'rs'=>-0.50, 're'=>+0.50, 'is'=>+0.25, 'ie'=>+1.35),
0045: array('kl'=>250, 'rs'=>-0.20, 're'=>+0.30, 'is'=>+0.55, 'ie'=>+1.10),
0046: array('kl'=>300, 'rs'=>-0.05, 're'=>+0.05, 'is'=>+0.70, 'ie'=>+0.80),
0047: array('kl'=>350, 'rs'=>-0.03, 're'=>+0.04, 'is'=>+0.71, 'ie'=>+0.79)
0048: );
マンデルブロ集合を描く複素平面の範囲は、配列 $Table に定義している。最初の配列は、マンデルブロ集合の全景を描くパラメータである。このパラメータを適当に変更することで、描画したい範囲を変更できる。配列の数も自由に増減できる。
解説:マンデブロ集合を描画
0203: /**
0204: * マンデブロ集合を描画
0205: * @param resource $imgイメージストリーム
0206: * @param int $ks 複素平面の縦横の分割数
0207: * @param array $paramパラメータ($Tableに準ずる)
0208: * @return なし
0209: */
0210: function drawMandelbrot($img, $ks, $param) {
0211: $rs = $param['rs'];
0212: $re = $param['re'];
0213: $is = $param['is'];
0214: $ie = $param['ie'];
0215: $kl = $param['kl'];
0216:
0217: $dr = ($re - $rs) / $ks;
0218: $di = ($ie - $is) / $ks;
0219: for ($cr = $rs; $cr <= $re; $cr += $dr) {
0220: for ($ci = $is; $ci <= $ie; $ci += $di) {
0221: $zr = $zi = 0.0;
0222: $k = 0;
0223: $flag = TRUE;
0224: //複素関数f(z)
0225: while (1) {
0226: $k++;
0227: if ($k > $kl) {
0228: $flag = FALSE;
0229: break;
0230: }
0231: $r = $zr * $zr - $zi * $zi + $cr; //f(z)=Z*Z+A の実部
0232: $i = 2 * $zr * $zi + $ci; //f(z)=Z*Z+A の虚部
0233: if (($r * $r + $i * $i) > 4) { //Znが発散した場合は描画
0234: $flag = TRUE;
0235: break;
0236: }
0237: $zr = $r;
0238: $zi = $i;
0239: }
0240: //描画
0241: if ($flag) {
0242: list($r, $g, $b) = hsv2rgb($k / $kl, 1.0, 1.0);
0243: $color = imagecolorallocate($img, (int)($r * 255), (int)($g * 255), (int)($b * 255));
0244: $x = (SIZE / ($re - $rs)) * ($cr - $rs);
0245: $y = (SIZE / ($ie - $is)) * ($ci - $is);
0246: imagesetpixel($img, (int)$x, (int)$y, $color);
0247: }
0248: }
0249: }
0250: }
解説:HSV→RGB変換
0160: /**
0161: * HSV→RGB変換
0162: * @param resource $imgイメージストリーム
0163: * @param double ($x1, $y1) - ($x1, $y2) 線分の座標
0164: * @return -
0165: */
0166: function hsv2rgb($h, $s, $v) {
0167: $r = $g = $b = $v;
0168: if ($s > 0.0) {
0169: $h *= (float)6.0;
0170: $i = (int)$h;
0171: $f = $h - (float)$i;
0172: switch ($i) {
0173: default:
0174: case 0:
0175: $g *= 1 - $s * (1 - $f);
0176: $b *= 1 - $s;
0177: break;
0178: case 1:
0179: $r *= 1 - $s * $f;
0180: $b *= 1 - $s;
0181: break;
0182: case 2:
0183: $r *= 1 - $s;
0184: $b *= 1 - $s * (1 - $f);
0185: break;
0186: case 3:
0187: $r *= 1 - $s;
0188: $g *= 1 - $s * $f;
0189: break;
0190: case 4:
0191: $r *= 1 - $s * (1 - $f);
0192: $g *= 1 - $s;
0193: break;
0194: case 5:
0195: $g *= 1 - $s;
0196: $b *= 1 - $s * $f;
0197: break;
0198: }
0199: }
0200: return array($r, $g, $b);
0201: }
参考サイト
- マンデブロー集合 -2次元関数の複素力学入門-:川平友規
- マンデルブロ集合の不思議な世界:
- アニメ『フラクタル』
(2022年4月29日)PHP8対応,リファラ・チェック改良