フラクタル(英: fractal)は、フランスの数学者ブノワ・マンデルブロが導入した幾何学の概念です。 図形の部分と全体が自己相似になっているものなどをいいます。
フラクタルの作成方法は反復計算などを使います。シンプルな計算式で綺麗なフラクタルを作成できます。
まず、コッホ曲線の例でフラクタルの作成方法を勉強します。
コッホ曲線を作成するめに、上記の作業の中の繰り返している部分を考えます。
繰り返している作業:
与えられる線分を以下の配列で表示します。
$$ \left[ \begin{array}{cc}x1 & y1 \\ x2 & y2 \end{array} \right] $$
3等分後の節点は4になりますが、これを以下のように表示します。
$$ \left[ \begin{array}{cc}x1 & y1 \\ x3 & y3 \\ x4 & y4 \\ x2 & y2 \end{array} \right] $$
新しい節点の座標は次のように計算できます。
$$x3=\frac{2}{3} x_1 + \frac{1}{3} x_2, \quad y3=\frac{2}{3} y_1 + \frac{1}{3} y_2 $$ $$x4=\frac{1}{3} x_1 + \frac{2}{3} x_2, \quad y4=\frac{1}{3} y_1 + \frac{2}{3} y_2 $$
以下のOctaveのコードを参考してください。
x1=0;y1=0;
x2=1;y2=0;
node_list = [x1,y1;x2,y2]
x3 = 2/3*x1+1/3*x2;
y3 = 2/3*y1+1/3*y2;
x4 = 1/3*x1+2/3*x2;
y4 = 1/3*y1+2/3*y2;
new_node_list = [ x1,y1; x3,y3; x4,y4; x2,y2]
上記のコードに作られているnode_listを描画するために、以下の関数を作ります。
function draw_node_list(node_list,plot_option)
x_list = node_list(:,1);
y_list = node_list(:,2);
plot(x_list, y_list, plot_option)
end
draw_node_list(node_list, 'r')
hold on
draw_node_list(new_node_list, 'bo')
p_list_1 = [0,0;1,2];
x1=p_list_1(1,1);y1=p_list_1(1,2);
x2=p_list_1(2,1);y2=p_list_1(2,2);
x3 = 2/3*x1+1/3*x2;
y3 = 2/3*y1+1/3*y2;
x4 = 1/3*x1+2/3*x2;
y4 = 1/3*y1+2/3*y2;
new_node_list = [ x1,y1; x3,y3; x4,y4; x2,y2];
%---------------- Simple method to calculate new points. -------------
p1=p_list_1(1,:); p2=p_list_1(2,:);
p3 = 2/3*p1+1/3*p2;
p4 = 1/3*p1+2/3*p2;
new_node_list = [ p1; p3; p4; p2];
%-------------------- END ---------------------------------------------
hold on
draw_node_list(p_list_1, 'r-')
hold on
draw_node_list(new_node_list, 'bo')
与えられる線分を1辺とする正三角形を考えます。 線分のデータは以下の形を持っています。
$$ \left[ \begin{array}{cc}x1 & y1 \\ x2 & y2 \end{array} \right] $$
指定される正三角形の(x1,y1),(x2,y2)の以外の頂点(x3,y3)を以下のように算出できます。
即ち、
$$ \left( \begin{array}{c} x3\\ y3 \end{array} \right) =\left( \begin{array}{cc} \cos \theta & - \sin \theta \\ \sin \theta & \cos \theta \end{array} \right) \left( \begin{array}{c} x2-x1\\ y2-y1 \end{array} \right) + \left( \begin{array}{c} x1\\ y1 \end{array} \right) $$
x1=0;y1=0;
x2=1;y2=0;
node_list = [x1,y1;x2,y2];
theta=pi/3;
A=[cos(theta), -sin(theta); sin(theta), cos(theta)];
new_point = A*[x2-x1; y2-y1] + [x1;y1];
x3=new_point(1);
y3=new_point(2);
new_node_list = [x1,y1; x3,y3; x2,y2];
hold on;
draw_node_list(node_list,'b');
draw_node_list(new_node_list,'r');
上記の作業をまとめて、関数create_triangleを定義します。
function new_node_list = create_triangle(line)
x1 = line(1,1); y1 = line(1,2);
x2 = line(2,1); y2 = line(2,2);
theta=pi/3;
A=[cos(theta), -sin(theta); sin(theta), cos(theta)];
new_point = A*[x2-x1; y2-y1] + [x1;y1];
x3=new_point(1);
y3=new_point(2);
new_node_list = [x1,y1; x3,y3; x2,y2];
end
関数 create_triangleを使って、三角形の2辺を作成します。
x1=0;y1=0;
x2=1;y2=0;
line = [x1,y1;x2,y2];
new_node_list = create_triangle(line);
draw_node_list(line,'b');
draw_node_list(new_node_list,'r');
与えられる線分(node_listで表す)について、三等分と三角形作成の作業を update_line にまとめます。
function new_node_list = update_line (node_list)
x1 = node_list(1,1); y1 = node_list(1,2);
x2 = node_list(2,1); y2 = node_list(2,2);
x3 = 2/3*x1+1/3*x2;
y3 = 2/3*y1+1/3*y2;
x4 = 1/3*x1+2/3*x2;
y4 = 1/3*y1+2/3*y2;
triangle_edges = create_triangle([x3,y3; x4,y4]);
new_node_list = [ x1,y1; triangle_edges; x2,y2 ];
end
%ここにコードを書いてください。
node_listに格納される各点と次ぎの点がなす線分をupdate_lineで処理します。各線分から得られる新しい4つの線分をnew_node_listに入れて、新しい点のリストが作られます。
function new_node_list = update_node_list(node_list)
new_node_list = [];
for k = 1 : (size(node_list,1)-1)
line = node_list(k:k+1,:);
new_line = update_line(line);
new_node_list = [new_node_list ; new_line];
end
end
以下の線分処理の回数(N)を順番に1,2,3,4,5にしてから結果を確認してください。
node_list = [0,0; 1,0];
N=1;
for k=1:N
node_list = update_node_list(node_list);
end
draw_node_list(node_list, 'r-')
axis("equal")
function new_node_list = create_triangle(line)
x1 = line(1,1); y1 = line(1,2);
x2 = line(2,1); y2 = line(2,2);
theta=pi/3;
A=[cos(theta), -sin(theta); sin(theta), cos(theta)];
new_point = A*[x2-x1; y2-y1] + [x1;y1];
x3=new_point(1);
y3=new_point(2);
new_node_list = [x1,y1; x3,y3; x2,y2];
end
function new_node_list = update_line (node_list)
x1 = node_list(1,1); y1 = node_list(1,2);
x2 = node_list(2,1); y2 = node_list(2,2);
x3 = 2/3*x1+1/3*x2;
y3 = 2/3*y1+1/3*y2;
x4 = 1/3*x1+2/3*x2;
y4 = 1/3*y1+2/3*y2;
triangle_edges = create_triangle([x3,y3; x4,y4]);
new_node_list = [ x1,y1; triangle_edges; x2,y2 ];
end
function new_node_list = update_node_list(node_list)
new_node_list = [];
for k = 1 : (size(node_list,1)-1)
line = node_list(k:k+1,:);
new_line = update_line(line);
new_node_list = [new_node_list ; new_line];
end
end
%------------------ 以上は反復計算を定義します。 ------------------
node_list = [0,0;1,0];
N=2;
for k=1:N
node_list = update_node_list(node_list);
end
draw_node_list(node_list, 'r-')
axis("equal")
初期の点のリストを正三角形の頂点について、上記のupdate_node_listで処理してみてください。
正三角形の頂点の座標:
$$ (0,0), (1/2,\sqrt{3}/2), (1,0) $$
node_list = [ 0,0; 0.5,sqrt(3)/2; 1,0; 0,0];
??
axis("equal")
axis off
Minkowski Sausageのフラクタルは以下のような反復計算を使っています。 コッホ曲線の計算コードを参考して、Minkowski Sausageのフラクタルを作ってください。
以下は正方形から作ったMinkowski Sausageの図です。
p1=[0,0];
p2=[1,0];
p3 = p1 + 1/sqrt(5)*(p2-p1)/norm(p2-p1)
$p_1$を中心にしてベクトル$p_1p_3$を時計回り$\theta$角度で回転します。ただし、$\theta$は以下ように算出されます。 $$ \theta = \sin^{-1}(\frac{1}{\sqrt{5}}) $$
theta=-asin(1/sqrt(5));
A=[cos(theta), -sin(theta); sin(theta), cos(theta)];
vec = (p3-p1)';
new_point = A*vec + p1';
node_list = [p1; new_point']
hold on
draw_node_list([p1;p2], 'b-o')
draw_node_list(node_list, 'r-o')
axis("equal")
線分$p_1p_2$の上の点$p_4$を描く。