見出し画像

再帰図形(2)

 フラクタルCGコレクション(渕上季代絵著:サイエンス社) (以下,「この本)では,「再帰図形2」として,任意の図形による再帰図形を考えています。任意といっても,ここで扱うのは折れ線です。まず示されているのは次の例です。

画像3

左の図を「ジェネレータ」と呼びます。このジェネレータの各辺(5つの辺)を,ジェネレータ自身を縮小して置き換えます。置き換える向きも決まっています。左の点から右の点まで進んでいくものとして,正方形の突起は常に進行方向左手にあるようにします。すると,中央の図になります。さらに置き換えていくと右の図になります。
 これは,L-system のタートルグラフィクスでも出てきたものです。回転角は90°で一定,1歩の長さも一定です。
 しかし,この本での「再帰図形2」は,ジェネレータの作り方が違います。回転角は一定でなくてもよく,進む長さにも単位はありません。次のようなジェネレータによる図形もできるのです。似たようなものがこの本に載っています。

画像4

ただし,この本では,始点が(0,0)で,終点が(1,0) という制限を設けています。それにより,次のようにして置き換えが簡単になるようにしています。
該当ページ(22ページ)をスキャンしたものです。

画像1

 ここでは「行列」は用語としては登場しませんが,回転行列を使っていることになります。(1)の式がそれですが,行列を使わずに表現しています。この式でのポイントは,回転角THをどう求めるか,なのですが,始点を(0,0),終点を(1,0) という制限を設けることによって,THを求めなくても(2)の式で置き換えができるというわけです。
そこで,次のプログラムが示されています。N88BASIC です。

画像2

再帰図形1 のコードと構造としては同じでしょう。GOTO 文で行き来するので,追っていくのが大変です。

 これを,CindyScriptで書いていきますが,複素数を使います。というのは,複素数平面では,回転と拡大縮小が,複素数の積で表されたので,それを使えば,やはり回転角を求める必要がないからです。
原理を次の図で説明しましょう。

画像5

左の図が基本です。赤の線分に緑の線分を縮小して重ねます。$${z_1}$$ にある複素数 $${z}$$ をかけると$${z_2}$$ になるとします。$${z_2=z_1 z}$$ ですから,回転のための複素数$${z}$$ は$${z=\dfrac{z_2}{z_1}}$$ として求められます。
中央の図は,青の線分の端点が原点ではない場合です。青の線分を,端点が原点に来るように平行移動すると,$${z_3}$$ は$${z_3-z_2}$$ に移動します。緑の線分を縮小して赤の線分に重ねたら,$${z_1}$$まで平行移動すれば青の線に重なります。したがって,$${z=\dfrac{z_3-z_2}{z_1}}$$ として回転のための複素数$${z}$$ を求め,$${z_1 z+z_2}$$ とすれば,$${z_1}$$ は$${z_3}$$に重なります。緑の線分上の点はすべて同じ計算で青の線分上に行くわけですが,これが線分でなく折れ線であっても同じ回転・縮小で青の線分上に乗ることになります。 したがって,ジェネレータを,かならず原点から始まるように作っておけば,もう一方の端点が (1,0) でなくても構わないことになります。

次の図でやってみましょう。

画像7

左の図。青い線がジェネレータ。6つの点を結んでいます。これを、赤い線分GHの上に乗せます。プログラムは次の通り。実行した結果が右の図です。

Plist=[A,B,C,D,E,F];
Generator=apply(Plist,complex(#));
z1=complex(F);
z2=complex(G);
z3=complex(H);
z=(z3-z2)/z1;
pl=apply(Generator,z*#+z2);
connect(apply(pl,gauss(#)));

・A〜Fをリストにして,複素数に変換するとジェネレータを表すリストができる・・・ Plist と Generator
・回転・縮小をする複素数 z を求め,Generator の各要素を z*#+z2 で回転・縮小する。#はリストの要素を表す。
・得られたリスト pl の各要素を xy 座標に変換して折れ線を描く(connect)

これを基本として,Generator の各辺上にGenerator 自身を回転・縮小して乗せます。

Plist=[A,B,C,D,E,F];
Generator=apply(Plist,complex(#));
z1=Generator_(-1);
work=[];
repeat(length(Generator)-1,s,
  z2=Generator_s;
  z3=Generator_(s+1);
  z=(z3-z2)/z1;
  work=work++apply(Generator,z*#+z2);
);
pl=work;
connect(apply(pl,gauss(#)));

画像8

pl ができた点のリストです。この pl に対して同じことを行えば2回目の拡大縮小ができます。そこで,はじめに pl を Generator にしておいて,繰り返せばいいわけです。次のコードがプログラム全体です。

Plist=[A,B,C,D,E,F];
Generator=apply(Plist,complex(#));
z1=Generator_(-1);
Loop=4;
pl=Generator;
repeat(Loop,
  work=[];
  repeat(length(pl)-1,s,
    z2=pl_s;
    z3=pl_(s+1);
    z=(z3-z2)/z1;
    work=work++apply(Generator,z*#+z2);
  );
  pl=work;
);
connect(apply(pl,gauss(#)));

Loop の値で繰り返し回数が決まります。次の図は Loop=4 の場合です。

画像9

点B〜Fの位置を変えれば図が変わります。また,コッホ曲線ならば,ジェネレータの点の数が5個ですので,はじめの Plist=[A,B,C,D,E,F]; を Plist=[A,B,C,D,E]; にします。

以上のプログラムに,スライダで繰り返し回数や点の数をインタラクティブに変えられるようにしたのが次のものです。

はじめはコッホ曲線風の図です。(風というのは,線分の長さが同一ではないので)

画像10

右方に3つ,点があります。したがって,全部で8つの点を使ったジェネレータを作ることができます。指定した点の数だけ線分でつなげられるので,点をドラッグしてジェネレータを作り,回数を指定します。
方眼が表示されていますが,スナップモードになっているので,格子点の近くに行くとぴったり格子点にくっつきます。もちろん格子点以外に置くこともできます。

画像11
画像12


ところで,コッホ曲線には,雪片曲線というのがあります。雪の結晶のような図です。雪片曲線では L-system でやったように,はじめの図形:イニシエータを用意します。これを次の節でやってみましょう。


次節:再帰図形(3)

複素数平面とフラクタル:目次 に戻る