2015年10月2日金曜日

フラクタル図形を描いてみる[Processing]

 図書館に『初めてのフラクタル 数学とプログラミング』という本を見つけた。Processingなら描けるかなと思って借りてみました。とりあえず幾つか描いてみます。

※フラクタルの次元などの理論的な小難しい話は割愛します(そもそも理解していない)。

1.Hフラクタルのプログラム

百聞は一見にしかず。とりあえず見てみればわかると思う。

 Hという文字が沢山くっついているのがわかると思う。一部を拡大すればまたHが出てきて,さらにそれを拡大すれば……となっている。

 まぁプログラムはこちら。

/* stepを呼び出す関数 */
int N = 5;

void setup() {
  size(512,512);
}

void draw() {
  /* 背景を黒で塗りつぶす */
  background(0);
  /* 線の色を緑に指定 */
  stroke(0,255,0);
  
  /* 再帰関数を呼び出す */
  step(width/2,height/2,0);
}

/**
 * @fn
 * H-フラクタルを描くプログラム
 * @param (x) 'H'の文字の中心x座標
 * @param (y) 'H'の文字の中心y座標
 * @param (n) 呼び出された回数(深さ)
 */
void step(float x, float y, int n) {
  if ( n >= N )
    return;

  /* Hの各辺の長さの半分の長さ */
  float len = width / 4 * pow(0.5, n);

  /* 中心の横棒を描く */
  line(x-len, y, x+len, y);
  /* 左の縦棒を描く */
  line(x-len, y-len, x-len, y+len);
  /* 右の縦棒を描く */
  line(x+len, y-len, x+len, y+len);

  /* Hの右上・右下・左上・左下の点から新たに'H'を描く */
  step(x-len, y-len, n+1);
  step(x-len, y+len, n+1);
  step(x+len, y-len, n+1);
  step(x+len, y+len, n+1);
}

再帰関数の練習にはなったかな。

2.シェルピンスキーのふるいを描く

シェルピンスキーのギャスケットとも言うらしい。本の絵を見て作ったから間違ってるかもしれ無いけれど。
 図形はこんなの

 プログラムはこんな感じ。
/* stepを呼び出す回数 */
int N = 7;

void setup() {
  size(512, 512);
}

void draw() {
  /* 背景を黒で塗りつぶす */
  background(0);
  /* 線の色を緑に指定 */
  stroke(0, 255, 0);

  /* 原点を中心に持ってくる */
  translate(width/2, height/2);
  /* 画面を適当な角度だけ回転する */
  rotate(PI/6);

  /* 再帰関数を呼び出す */
  step(0, 0, 0);
}

/**
 * @fn
 * シェルピンスキーのふるいを描くプログラム
 * @param (x) 三角形の中心x座標
 * @param (y) 三角形の中心y座標
 * @param (n) 呼び出された回数(深さ)
 */
void step(float x, float y, int n) {
  if ( n >= N )
    return;

  float len = width / 3 * pow(0.5, n);
  /* 3分の2 * PI [rad]つまり120度 */
  float theta = 2.0/3.0*PI;
  float x0, x1, y0, y1;

  /* 三角形を描く */
  for (int i = 0; i < 3; i++ ) {
    x0 = x+len * cos( i * theta );
    y0 = y+len * sin( i * theta );
    x1 = x+len * cos( (i+1) * theta );
    y1 = y+len * sin( (i+1) * theta );

    line(x0, y0, x1, y1);
  }

  /* もう一つ小さい三角形の中心を指定し呼び出す */
  len = len / 2;
  for (int i = 0; i < 3; i++ ) {
    step(x+len*cos(i*theta), y+len*sin(i*theta), n+1);
  }
}

 まぁsin,cosの勉強にはなったかな。

3.なんかよくわからないもの

なんかいい感じのやつがあったのであげておきます。ただ詳細はよくわからないです。
L,Rの漸化式をランダムで計算するといい感じの図形が得られる。Lは原点中心の1/4回転を,Rは点(1,0)の拡大を行うとのこと。そうするといい感じのやつが描かれるという。
 百聞は一見にしかず,だ。プログラムと画像はこんな感じ。プログラムを実行したらマウスを動かすと上の式のaが変化して図形が変化します。


 
int N = 4096;

void setup() {
  size(512, 512);
}

void draw() {
  /* 背景を黒で塗りつぶす */
  background(0);
  /* 線の色を緑に指定 */
  stroke(0, 255, 0);


  /* 原点を中心に持ってくる */
  translate(width/2, height/2);
  /* 画面を適当な角度だけ回転する */
  rotate(PI);

  float x = 0.0;
  float y = 0.0;  
  float temp, tx, ty;
  /* 定数aを適当に決める */
  float a = 5.0*(mouseX * mouseY ) / ( width*height );

  for (int i = 0; i < N; i++ ) {
    /* x_n,y_nを保存しておく */
    tx = x;
    ty = y;

    /* 漸化式をランダムに変える */
    if ( random(2) < 1 ) {
      x = -ty;
      y = tx;
    } else {
      temp = (tx-1)*(tx-1)+ty*ty+1;
      x = 1 + a * ( x - 1 ) / temp;
      y = a * ty /temp;
    }
    
    /* 点の描画 */
    rect(x*width/2, y*height/2, 1, 1);
  }
}

 何なんだろこれ。でも面白いからいいか.

ツイッターのアイコンをProcessingで作ってみる

 ブログを始めたついでにツイッターを始めることにした。卵アイコンではなんだか物足りないので何かアイコンを作ろうと思う。

 とはいうものの,アイコンって結構悩みどころ。かっこいい画像がいいけれど,オリジナルにしたい。あと理系っぽい雰囲気をかもし出すためにはなんかグラフとかにしたい。

 散々迷った挙句,とりあえずバラ曲線を描いてみることにした。

1.バラ曲線を描く

まぁまずバラ曲線の式はこちら。極方程式であらわされる。
aとnは定数。θはもちろん変数。Processingで描く際にはθを適当な値から少しづつ変化させて,次の(x,y)について点を打つ。
まぁ実際には点ではなく線を引いている。とりあえずプログラムを見てもらえればわかると思う。

/* シータの値 */
float theta = 0.0;
/* この値を変えると形が変化する */
float n = 5.0/7.0; 

void setup() {
  /* 適当な大きさのウィンドウを表示する */
  size(512, 512);
  /* 背景を黒く塗りつぶす */
  background(0);
}

void draw() {

  float x0, x1, y0, y1;
  float r;

  /* Processingでは左上が原点になっているので中心に持ってくる */
  translate(width/2, height/2);
  /* Processingでは上下が逆なので180度(つまりPI[rad])回転する */
  rotate(PI);

  /* 線の色は緑にする */
  stroke(0, 255, 0);
  /* thetaが変化する前の座標 */
  r = width / 2 * sin(n*theta);
  x0 = r * cos(theta);
  y0 = r * sin(theta);

  /* thetaをちょっとだけ動かす */
  theta += 0.01;

  /* thetaが変化した後の座標 */
  r = width / 2 * sin(n*theta);
  x1 = r * cos(theta);
  y1 = r * sin(theta);

  /* (x0,y0)から(x1,y1)に線を引く */
  line(x0, y0, x1, y1);

  //saveFrame("a.png");
}

x0,y0は前回計算したx1,y1を流用すれば計算回数少なくて済むよ!という声が聞こえてきそうだがプログラム的には(たぶん)こっちのほうが見やすいかなと思ってこうした。

 徐々に描かれるのは仕様です。ほんとは範囲決めて一瞬で描きたかったけれど,nが小数の時にどうするかがわからなかった。整数なら0 <= θ < 2πでやれば描けるんだけれどもね。実行結果は以下の通り。


 十分きれいな形だな。でもこの図形は数学Ⅲでならうくらい有名なものです。これじゃつまらん。オリジナリティがないとか言われそう。なのでちょっとアレンジしてみる。

2.バラバラ曲線を描く

なんて名前付けたらいいのかわからないのでこう呼ぶことにした。上のバラ曲線のプログラムを書いてた時に偶然生まれたもの。ごにょごにょやっている間にえらい変な数式になってしまった。
 訳が分からないよ。一応a,c0~c4は定数。この(x0,y0)から(x1,y1)に引いた線分の集合をバラバラ曲線と呼ぶことにした。とりあえずソースコードみて(お察しください)。

/* 各係数を格納する配列 */
int[] c = { 1, 6, -6, 2, -2};
/* 係数の最小値 */
int C_MIN = -8;
/* 係数の最大値 */
int C_MAX = 8;

void setup() {
  /* 適当な大きさのウィンドウを表示する */
  size(512, 512);
  /* 1秒間に1回drawが呼ばれるようにする */
  frameRate(1);
}

void draw() {
  /* 背景を黒く塗りつぶす */
  background(0);

  float x0, x1, y0, y1;
  float r;

  /* Processingでは左上が原点になっているので中心に持ってくる */
  translate(width/2, height/2);
  /* Processingでは上下が逆なので180度(つまりPI[rad])回転する */
  rotate(PI);

  for (float theta = 0.0; theta < 2 * PI; theta += 0.01 ) {
    /* この辺はバラ曲線と似たイメージ */
    r = width / 2 * sin(c[0]*theta);
    x0 = r * cos(c[1]*theta);
    y0 = r * sin(c[2]*theta);
    x1 = r * cos(c[3]*theta);
    y1 = r * sin(c[4]*theta);

    /* 色をそれっぽい感じに変化させる */
    stroke(255*abs(sin(theta)));

    /* (x0,y0)から(x1,y1)に線を引く */
    line(x0, y0, x1, y1);
  }
  
  /* 係数をランダムに変える */
  for (int i = 0; i < c.length; i++ ) {
    c[i] = int(random(C_MIN, C_MAX));
  }
}

/* キーボードが押されたときに呼び出される関数 */
void keyPressed() { 
  /* 保存する */
  saveFrame("######.png");
}
 1秒に1回ランダムにパラメータを決めて表示している。何かしらキーボードを押せば保存される。実行結果の例としてはこんなのが出てきた。

 まぁまぁいいんじゃない?オリジナリティもあるし。まぁ変なのばかりだけれど。しばらくツイッターのアイコンはこれにしておこうと思います。