IFSを使ってフラクタルを書く

独楽回しeddyと申します。
今回Processing Advent Calendar 2018の16日目を担当させていただきます。
以前からこういう事はやってみたかったのですが、実際何を書いたら良いのかは結構悩みました。
もう既に周知の事で今更書く事ではないかもなんて考えもしましたが、過去に理解するのに時間がかかった事なので、書く事にしました。
テーマはフラクタル図形です。これをIFSを使って書いてみます。

#Processing
https://processing.org
Processingとは、Ben Fry氏とCasey Reas氏らによって作られたグラフィック面に特化した言語。自分個人としては、簡単に書ける点や出力が目に見える形で表れる点、数学など様々な知識を組み合わせると面白いものが手軽に出来てしまう点から、初めてプログラミングを習う方に最適なんじゃないかなと思ってます。

#IFS
IFSはIteration Functional Systemの略です。これを使う事によって、フラクタル図形を手軽に描く事が出来ます！

例えばシダの葉状のフラクタル図形をIFSで書こうとすると次のようになります。
以下の２式を用います。

```math
x_{n+1} = ax_n + by_n + e \\
y_{n+1} = cx_n + dy_n + f
```

```math
x_{n+1}・・・次のx座標 \\
y_{n+1}・・・次のy座標 \\
x_{n}・・・今のx座標 \\
y_{n}・・・今のy座標 \\
a,b,c,d,e,f ・・・係数 \\
```

今の次の座標を今の座標から求めて、求めた座標に点などを描画します。そして描画した座標を今の座標として、また次の座標を求めて描画...これを繰り返しています。

係数(a,b,c,d,e,f)については次のように決まります。

|Set|a|b|c|d|e|f|確率|
|------|------|--------|-------|------|--------|-------|-------|
| 1 |0.0|0.0|0.0|0.16|0.0|0.0|1%|
| 2 |0.2|-0.26|0.23|0.22|0.0|1.6|7%|
| 3 |-0.15|0.28|0.26|0.24|0.0|0.44|7%|
| 4 |0.85|0.04|-0.04|0.85|0.0|1.5|85%|

係数はa~fまで、このように4つのSetとして決められています。(何故この数値なのかは、これを発見した凄い方に聞いて下さいm(_ _)m)
どのSetを使うかは確率が決められている場合があります。ここでは、Set1は1％の確率、Set2,3は7％の確率、Set4は85％の確率となっていて、ほぼほぼSet4を使うようになっています。

-https://ja.wikipedia.org/wiki/反復関数系

#Processingで実装
実際にProcessingで実装してみたときのソースコードはこちらとなっています。

```
float xn1,yn1; //今の座標の情報
float xn2,yn2; //次の座標の情報

float a,b,c,d,e,f;  //次の座標を計算するために使う係数

float p;  //どの係数を使うかを判定するための変数

void setup(){
  size(600,600);  //画面の大きさ(600×600)
  background(0);  //背景は黒
  stroke(255);  //線の色は白
  fill(255);  //塗り潰しの色は白
  xn1 = 0;  //最初のx座標
  yn1 = 0;  //最初のy座標
}

void draw(){
  p = random(1);  //0~1の乱数を生成
  if(p < 0.01){  //0.01以下ならSet1(1%)
    a = 0;
    b = 0;
    c = 0;
    d = 0.16;
    e = 0;
    f = 0;
  }else if(p >= 0.01 && p < 0.08){  //0.01以上0.08未満ならSet2(7%)
    a = 0.2;
    b = -0.26;
    c = 0.23;
    d = 0.22;
    e = 0;
    f = 1.6;
  }else if(p >= 0.08 && p < 0.15){  //0.08以上0.15未満ならSet3(7%)
    a = -0.15;
    b = 0.28;
    c = 0.26;
    d = 0.24;
    e = 0;
    f = 0.44;
  }else{  //0.15以上ならSet4(85%)
    a = 0.85;
    b = 0.04;
    c = -0.04;
    d = 0.85;
    e = 0;
    f = 1.6;
  }
  translate(width/2,height/2+height/4);  //通常は左上が(0,0)なので、中心を合わせる。(X : width/2、Y : height/2+height/4にすると個人的にいい感じだったので。)

/*次の座標の計算部分*/    
  xn2 = a * xn1 + b * yn1 + e;  //次のX座標の計算
  yn2 = c * xn1 + d * yn1 + f;  //次のY座標の計算
  

  ellipse(-xn2 * 40,-yn2 * 40,3,3);  //座標の描画(40はスケーリング)(-が付いているのは、Processingでは画面の右と下が+方向であり、それを調整するため)
  
  xn1 = xn2;  //求めた次のX座標を今のX座標とする
  yn1 = yn2;  //求めた次のY座標を今のY座標とする
}
```

なるべくコメントを書いたつもりですが、もし見辛かったらすみません。Processingで円や点を描く事自体はとても簡単なので、このような事をするには大変向いています。コメントにも書きましたが、Processingでは左上隅が(0,0)で画面右がXの+方向、画面下がYの+方向です。そのため、見た目を合わせるために符号を変えたりtranslate()で原点を変えたりして調整しています。また描画部分ellipse()の中で座標に40を掛けていますが、これも全体の大きさを調整するための値です。何も掛けずに描画すると値自体は大きくないので結果的に1点に集まっているように見えてしまうのでこのようにしています。人それぞれ見易さとかあると思うので、それは各々で調整していただければと思います。色も今回は黒と白でシンプルにしました。
最終的な結果は以下のようになります。プログラムを実行すると、徐々にこれに近づくように点が描画されて行きます。
<img width="602" alt="スクリーンショット 2018-12-15 14.13.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/187772/abd61cb8-330c-a138-8d12-a0dd90b595cb.png">
全体の形と一つ一つの葉の形が大きさ以外同じなのが分かります！式自体はそれほど難しい訳ではないのに、このような形が描画されるのは本当不思議だなと思います！

今回はシダの葉状のフラクタルを描画してみましたが、他にも色々なIFSはあります！しかし、係数や確率などの違いはあれど、「確率で係数のSetを選び、式に当てはめて今の座標に使って次の座標を計算する」という根幹は変わらないと思われるので、色々調べて試してみてはいかがでしょうか？

ここでは12月にちなんで、雪の結晶とクリスマスツリーをIFSで描いた物を載せます！
<img width="601" alt="スクリーンショット 2018-12-15 14.58.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/187772/a9894cb4-f392-88ee-28da-42fc02f1bda3.png">
<img width="602" alt="スクリーンショット 2018-12-15 14.32.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/187772/807c7736-76cc-33a8-3129-210941e6621e.png">

これは以下のリンクに載ってます。
他にも様々なIFSが紹介されているので、もし興味があればどうぞ！
元ネタ : http://paulbourke.net/fractals/ifs/

#まとめ
今回Processing上でIFSを使ってフラクタルの描画を行ってみました。植物の葉のような形が想像以上に単純な式から作られるって知った時、最初は本当に驚きました！しかし、それがどのように描画されるのかを見てみたくなったっという意味もあって簡単に試せるProcessingを使いました！
Processingはプログラミング言語の中では簡単な部類ですし、手軽に様々な事を試せますし、面白い事も沢山出来ます！これを機に少しでもProcessing自体はもちろん、その良さが伝われば嬉しいです！
ここまで読んで下さり、ありがとうございました！