ミャクミャクジュリア集合
どうも、108Hassiumです。
以前、Twitterにこんな画像を投稿しました。

これは$${z^2+0.35+0.1i}$$のジュリア集合を、大阪万博のマスコットキャラクター「ミャクミャク」っぽく彩色したものです。
この記事では、この画像の描画方法を解説します。
解説
コードは以下の通りです。(言語はProcessing)
void setup(){
size(2000,2000);
background(0,0,255);
noStroke();
double x,y,px,py,cx,cy,dx,dy,r,rr,rw,rb;
boolean o;
int m;
m=1000;
rr=2e-8;
rw=2e-9;
rb=5e-10;
x=0;
y=0;
cx=0.35;
cy=0.1;
for(int a=0;a<m;a++){
px=x;
py=y;
x=px*px-py*py+cx;
y=2.0*px*py+cy;
}
dx=x;
dy=y;
for(int a=0;a<2000;a++){
for(int b=0;b<2000;b++){
x=(double)a/1000.0-1.0;
y=(double)b/1000.0-1.0;
o=true;
for(int c=0;c<50000&&o;c++){
px=x;
py=y;
x=px*px-py*py+cx;
y=2.0*px*py+cy;
r=(x-dx)*(x-dx)+(y-dy)*(y-dy);
if(r<rr){
o=false;
if(rw<r){
fill(255,0,0);
rect(a,b,1,1);
}else if(rb<r){
fill(255);
rect(a,b,1,1);
}
}
if(100<x*x+y*y){
o=false;
fill(cr(c),cr(c*2),cr(c*3));
rect(a,b,1,1);
}
}
}
}
}
float cr(float c){
return int((c%256)*(256-(c%256))/65);
}大まかな内容は普通のジュリア集合の描画方法と変わらないので、重要な部分だけ掻い摘んで説明します。
...
background(0,0,255);
...背景を青色に設定しています。
ジュリア集合の中の青い部分(ミャクミャクの水の部分と目の中央部分)は実は背景の色です。
...
m=1000;
rr=2e-8;
rw=2e-9;
rb=5e-10;
...描画に必要なパラメータを設定する部分です。
...
x=0;
y=0;
cx=0.35;
cy=0.1;
for(int a=0;a<m;a++){
px=x;
py=y;
x=px*px-py*py+cx;
y=2.0*px*py+cy;
}
dx=x;
dy=y;
...$${z_0=0,z_{n+1}=z_n^2+0.35+0.1i}$$という数列を計算し、$${z_m}$$($${=z_{1000}}$$)の値を保存しています。(以下、ここで計算した値を$${d}$$とします)
数列$${z_n}$$は本来なら吸引的固定点へ収束していくのですが、収束が非常に遅いので1000回の計算では計算結果は固定点から少しずれた値になります。
...
r=(x-dx)*(x-dx)+(y-dy)*(y-dy);
if(r<rr){
o=false;
if(rw<r){
fill(255,0,0);
rect(a,b,1,1);
}else if(rb<r){
fill(255);
rect(a,b,1,1);
}
}
...赤と白の部分の描画をしている部分です。
まず、通常のジュリア集合の描画と同じように計算した数列の値に対して、$${d}$$との距離の2乗をrに保存します。
そしてrの値が$${2×10^{-8}}$$(=rr)より小さかったら数列の計算を打ち切り、さらに
rが$${2×10^{-9}}$$(=rw)より大きかったら赤で彩色する
rが$${5×10^{-10}}$$(=rb)より大きく$${2×10^{-9}}$$以下だったら白で彩色する
・・・という処理をします。
要するにこれは$${d}$$をトラップにしたorbit trapのようなもので、$${z_n}$$が$${d}$$に近づいたら$${d}$$との距離に応じて色を決めることで細胞と目玉を描画しています。
※☟orbit trapの解説
なお、最初の方で設定したm、rr、rw、rbという4つの値は試行錯誤で見つけたものです。
$${z^2+0.35+0.1i}$$以外の関数のジュリア集合に応用する場合、これらの値は個別に調整する必要があります。
応用
応用です。












