フラクタル図形を描く(道具編)


フラクタル図形とは

フラクタル図形は「自己相似」という構造をもった図形です。自己相似な図形は全体と部分が似た構造を持つ、不思議な絵になります。このような構造は、自然界にも多くあらわれるので、逆に、フラクタル構造をもつ図形を自分のプログラムで生成できるようになれば、なんとなく「自然界にある~っぽい図形」を描く事ができます。
以下の絵は非常に単純な再帰的なプログラムから描かれますが、どことなく、自然界にある「木」の構造に似ているところがあると思いませんか?

道具=タートルグラフィクス

よく知られているフラクタル図形が他にもいくつかありますが、それらをを描くプログラムをそれぞれ作るよりも、いったんタートルグラフィックスのライブラリを用意してそれを利用して作るのが楽ではないか、と思いますので、ここ超略式のタートルグラフィクスライブラリを準備し、フラクタル図形を描く道具とします。

ところで、タートルグラフィクスとは

タートルグラフィックスは、描画スクリーン上に生息する「ペンを持った亀(タートル)」を使った描画の方法、と考える事ができます。タートルは与えられた命令に従って動きます。タートルが受け付ける基本命令は以下の6つです。

命令 略称 意味
forward len fd 前にlen進む
back len bk 後ろにlen下がる
right th rt 右にth度方向を変える
left th lt 左にth度方向を変える
penup pu ペンを上げる
pendown pd ペンを上げる

タートルは、penを上げている状態で前に進んでも移動するだけ、penを下げている状態では、進んだときに軌跡が残ります。タートルグラフィクスでは、この軌跡をもって描きたい図形とみなします。

なお、この考え方はLogoというプログラミング言語のインタラクティブな描画環境として提供されているものです。

例えば、一辺の長さが10の正方形を描くタートルへの命令列は以下になります。

pd; 
fd 10; rt 90;
fd 10; rt 90; 
fd 10; rt 90; 
fd 10; rt 90; 

タートルグラフィックスライブラリの実装

6つの命令は以下のように実装できます(c++)。

// turtle.cxx Simple Turtle Graphics Library
#include <iostream>
#include <math.h>
using namespace std;

float x = 0.0;
float y = 0.0;
float angle = 0.0;
bool pendown = false;

void pd() { pendown = true; }
void pu() { pendown = false; }
void rt(float th) { angle += th; }
void lt(float th) { angle -= th; }
void fd(float len) {
  float tx = x + len * sin(M_PI*angle/180.0);
  float ty = y + len * cos(M_PI*angle/180.0);
  if(pendown) {
     cout << x  << " " << y  << endl;    // gnuplot's line
     cout << tx << " " << ty << endl << endl;
  }
  x = tx;
  y = ty;
}
void bk(float len) {fd(-len);}


注意点としては、このままだとangleのオーバフロー可能性があるので、更新タイミングで360とのmodを取っておいたほうが安全かもしれません。

なお、タートルは明らかにオブジェクトとして定義できるので、Turtleクラスを定義したいところですが、短さ+見やすさを追求した結果、ここではこれに留めておきます(ほぼ、コード全体をclass Turtle { ... } で囲むだけ、ですが)。

fd命令の説明

他は問題ないと思いますが、fd(forward)命令のところの式だけは簡単に説明しておきます。

sin, cosの引数で M_PI*angle/180.0という計算をしているところは、sin, cosの引数はラジアン単位なので、度(degree)から以下の関係式を使った変換となっています。

180(degree) = \pi (rad)

再帰Tree

最後にTurtleグラフィクスでフラクタル図形を1つ描いてみます。すでに示したタートルグラフィクスのコードと一緒にビルドしてみてください。

// treemain.cxx

void pd();
void pu();
void rt(float th);
void lt(float th);
void fd(float len);
void bk(float len);

void tree(float len, float th, float r, int n) {
  if(n > 0) {
    fd(len);
    lt(th);
    tree(len*r, th, r, n-1);
    rt(2.0*th);
    tree(len*r, th, r, n-1);
    lt(th);
    bk(len);
  }
}
int main()
{
   pd();
   tree(10.0, 30, 0.7, 12);
}

ビルド、実行

以下で。

$ g++ treemain.cxx turtle.cxx -o treemain
$ ./treemain > tt.dat

描画

gnuplotを利用します。gnuplotのコマンドは以下で。

gnuplot> set size ratio -1
gnuplot> plot "tt.dat" w l

gnuplotコマンドの一行目でx,y軸の比を同じにします。
また、描画結果は本記事冒頭のものです。

まとめ

今回は、フラクタル図形を描くための道具立てとしてのタートルグラフィックスの実装方法を紹介しました。また、最後に再帰的に描かれるTreeの描画を行いました(あまり説明していませんが)。

以上、です。