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

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

(2026年3月1日)PHP8.5対応:imagedestroyを使わない, pahooInputData.php導入

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

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

目次

サンプル・プログラム

圧縮ファイルの内容
MandelbrotSet.phpサンプル・プログラム本体
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
MandelbrotSet.php 更新履歴
バージョン 更新日 内容
1.2.0 2026/03/01 PHP8.5対応:imagedestroyを使わない, pahooInputData.php導入
1.1 2022/04/29 PHP8対応,リファラ・チェック改良
1.0 2020/03/01 初版
pahooInputData.php 関数/メソッド一覧
関数/メソッド 機能 詳細
pahooLoadEnv .env ファイルからデータを読み込む .env ファイルは include_path が通っているディレクトリに配置すること
execFunc 指定した関数を実行し,その戻り値を返す. phpversion関数が実装されていなければ強制終了する.
exitIfLessVersion PHP処理系が指定したバージョン未満ならメッセージを表示して強制終了する.
exitIfExceedVersion PHP処理系が指定したバージョンを超えたらメッセージを表示して強制終了する.
isCommandLine コマンドラインから起動されたかどうかを求める.
isButton HTML FORMで指定したボタンが押されたかどうかを求める. filter_input()関数および $argv を参照する.
getParam HTML FORMで指定したINPUTの内容を取り出す. filter_input()関数および $argv を参照する.
validNumber 数値バリデーションを行う. 数値が整数か小数かを指定し,最小値と最大値を指定する.
getValidNumber HTML FORMで指定したINPUTの内容を数値として取り出す(バリデーション付き) filter_input()関数および $argv を参照する.
validString 文字列バリデーションを行う. filter_input()関数および $argv を参照する. 文字列の最小長,最大長,排除または受容するパターンを指定する.
validURL URLバリデーションを行う. RFC 1738 Uniform Resource Locators にマッチするかどうかを照合する。
validEmail メールアドレス・URLバリデーションを行う. RFC 2282 Internet Message Format にマッチするかどうかを照合する。
getValidString HTML FORMで指定したINPUTの内容を文字列として取り出す(バリデーション付き) filter_input()関数および $argv を参照する.
validRegexPattern 正規表現のバリデーションを行う.
getPasswordHash パスワード・ハッシュをつくる.
verifyPassword パスワードがハッシュに合致するかどうかを求める.
roundFloat 小数を指定した桁数で丸めて文字列として返す。 与えた小数の有効桁数より指定桁数が多いときには,末尾に0をサプレスする.

マンデルブロ集合とは

マンデルブロ集合とは、 $$ \begin{cases} z_{n+1}\ =\ {z_n}^2\ +\ c\\z_0\ =\ 0 \end{cases} $$
で定義される複素数列 $ z_n $ が $ n \ \text{→} \ \infty $ のときに発散しないという条件を満たす複素数cの集合である。
ここで複素数 $ c $ を $ c\ =\ a +\ ib $ と表し、$ c $ をXY平面上の点 $ (a, b) $ とプロットしてゆくと、冒頭のようなフラクタル図形が得られる。

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

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

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

準備:初期値

MandelbrotSet.php

  49: // 各種定数(START) ===========================================================
  50: 
  51: // 表示サイズ(縦横ピクセル)
  52: define('SIZE', 600);
  53: 
  54: // パラメータ・テーブル
  55: // kl = 最大繰返し回数
  56: // 複素平面の範囲
  57: //   開始:rs=実部, is=虚部
  58: //   終了:re=実部,ie=虚部
  59: static $Table = array(
  60: array('kl'=>100, 'rs'=>-2.10, 're'=>+0.50, 'is'=>-1.35, 'ie'=>+1.35),
  61: array('kl'=>150, 'rs'=>-0.50, 're'=>+0.50, 'is'=>+0.25, 'ie'=>+1.35),
  62: array('kl'=>250, 'rs'=>-0.20, 're'=>+0.30, 'is'=>+0.55, 'ie'=>+1.10),
  63: array('kl'=>300, 'rs'=>-0.05, 're'=>+0.05, 'is'=>+0.70, 'ie'=>+0.80),
  64: array('kl'=>350, 'rs'=>-0.03, 're'=>+0.04, 'is'=>+0.71, 'ie'=>+0.79)
  65: );
  66: 
  67: // 各種定数(END) ===============================================================

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

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

MandelbrotSet.php

 180: /**
 181:  * マンデブロ集合を描画
 182:  * @param   resource $img イメージストリーム
 183:  * @param   int $ks 複素平面の縦横の分割数
 184:  * @param   array $param パラメータ($Tableに準ずる)
 185:  * @return  なし
 186: */
 187: function drawMandelbrot($img, $ks, $param) {
 188:     $rs = $param['rs'];
 189:     $re = $param['re'];
 190:     $is = $param['is'];
 191:     $ie = $param['ie'];
 192:     $kl = $param['kl'];
 193: 
 194:     $dr = ($re - $rs) / $ks;
 195:     $di = ($ie - $is) / $ks;
 196:     for ($cr = $rs$cr <$re$cr +$dr) {
 197:         for ($ci = $is$ci <$ie$ci +$di) {
 198:             $zr = $zi = 0.0;
 199:             $k = 0;
 200:             $flag = TRUE;
 201:             // 複素関数 f(z)
 202:             while (1) {
 203:                 $k++;
 204:                 if ($k > $kl) {
 205:                     $flag = FALSE;
 206:                     break;
 207:                 }
 208:                 $r = $zr * $zr - $zi * $zi + $cr;   // f(z)=Z*Z+A の実部
 209:                 $i = 2 * $zr * $zi + $ci;           // f(z)=Z*Z+A の虚部
 210:                 if (($r * $r + $i * $i> 4) {      // Znが発散した場合は描画
 211:                     $flag = TRUE;
 212:                     break;
 213:                 }
 214:                 $zr = $r;
 215:                 $zi = $i;
 216:             }
 217:             // 描画
 218:             if ($flag) {
 219:                 list($r, $g, $b) = hsv2rgb($k / $kl, 1.0, 1.0);
 220:                 $color = imagecolorallocate($img, (int)($r * 255), (int)($g * 255), (int)($b * 255));
 221:                 $x = (SIZE / ($re - $rs)) * ($cr - $rs);
 222:                 $y = (SIZE / ($ie - $is)) * ($ci - $is);
 223:                 imagesetpixel($img, (int)$x, (int)$y, $color);
 224:             }
 225:         }
 226:     }
 227: }

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

解説:HSV→RGB変換

MandelbrotSet.php

 137: /**
 138:  * HSV→RGB変換
 139:  * @param   resource $img イメージストリーム
 140:  * @param   double ($x1, $y1) - ($x1, $y2)  線分の座標
 141:  * @return  -
 142: */
 143: function hsv2rgb($h, $s, $v) {
 144:     $r = $g = $b = $v;
 145:     if ($s > 0.0) {
 146:         $h *= (float)6.0;
 147:         $i = (int)$h;
 148:         $f = $h - (float)$i;
 149:         switch ($i) {
 150:             default:
 151:             case 0:
 152:                 $g *1 - $s * (1 - $f);
 153:                 $b *1 - $s;
 154:                 break;
 155:             case 1:
 156:                 $r *1 - $s * $f;
 157:                 $b *1 - $s;
 158:                 break;
 159:             case 2:
 160:                 $r *1 - $s;
 161:                 $b *1 - $s * (1 - $f);
 162:                 break;
 163:             case 3:
 164:                 $r *1 - $s;
 165:                 $g *1 - $s * $f;
 166:                 break;
 167:             case 4:
 168:                 $r *1 - $s * (1 - $f);
 169:                 $g *1 - $s;
 170:                 break;
 171:             case 5:
 172:                 $g *1 - $s;
 173:                 $b *1 - $s * $f;
 174:                 break;
 175:         }
 176:     }
 177:     return array($r, $g, $b);
 178: }

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

参考サイト

(この項おわり)
header