上のアプレットはフラクタルを利用して描いた木です.リロードする度に形がかわります. フラクタルには難しそうな定義があるのですが,直感的に自己相似性のあるものが フラクタルです.例えば海岸の波打ち際などは,上空から見たときの形と間近で見たときの 形はよく似ています.つまりどんなスケールで観測しても同じ特徴が続きます. これは自然の物によく見られる特徴で,上のアプレットもそれを利用しているのですが, 木も幹から枝が分かれ,そこからまた枝が分かれています.最終的には葉があるわけですが, 葉もよく見ると葉脈などがそのようになっています.
同じ特徴が続くというのはプログラムを作る側からすると大変ありがたい事で, 再帰を使う事でたったの数行で記述する事ができます. 上に表示されている木もよく見ると同じ点から分かれた2つの枝は同じ形をしているのが分かります. それではソースコードを見てみます.
public void fractal(Graphics g,int x,int y, int degree,int loopnum,int length){ int nextX, nextY; nextX = x + (int)(Math.cos(Math.toRadians((double)degree))*length); nextY = y - (int)(Math.sin(Math.toRadians((double)degree))*length); g.drawLine(x, y, nextX, nextY); if(loopnum!=0){ fractal(g, nextX, nextY, degree - right, loopnum - 1, (int)(length * 0.8)); fractal(g, nextX, nextY, degree + left, loopnum - 1, (int)(length * 0.8)); } }
エンジン部分はこれだけです.xとyはこれから描画する線の始点となる座標で, degreeは角度です.数学でよく見る普通のx-y座標系を考えてください.ただし, y軸は上下逆さまになっていることに注意する必要があります.真上に線を引くときは 90度を指定すれば良いです.lengthは描画する線の長さです. loopnumは再帰の深さを指定することになります.これが無いと永遠に戻ってくることが できず,スタックがオーバーフローします.終了条件を決めるのは再帰の基本です.
終了条件を満たさない間はひたすら再帰を繰り返します. rightはこれから描く右側の枝と今描いた枝とのなす角で,右側の枝は座標系において 角度が小さくなるので引き算をし,左側は角度が大きくなるので足し算を行います. 最後にlengthに0.8を掛けているのは,同じ大きさだと先が葉に見えないからで, 好きに変更して構いません.
最後にもう一つフラクタルの木を紹介します.
特に説明はしませんが,やってることは上の木と同じです. ソースコードは下に載せておきます.