ここでは、書籍「アートで魅せる数学の世界」のp.187-197に掲載されている、反復関数を用いたドラゴン曲線を再現してみました。

反復関数を用いたドラゴン曲線

まず、反復関数を用いたドラゴン曲線です。

反復関数を用いたドラゴン曲線

ドラゴン曲線は別記事「Lシステム」でも紹介しています。

ドラゴン曲線に対する反復関数

下図のように横の長さが\(l\)となるキャンバス(グレーの領域)に対して\(x\)軸と\(y\)軸をとります。そのキャンバス上に点C\((\frac{l}{4},\frac{l}{4})\)をとり、点Cを左端とする長さ\(\frac{l}{2}\)の線分を取ります。この線分を最初の起点として、ドラゴン曲線を生成するための2つの反復関数は以下のようになります。\[ \begin{align} f_1 &: x \to \frac{1}{2} (x-\frac{l}{4})-\frac{1}{2} (y-\frac{l}{4}) + \frac{l}{4}, \ \ y \to \frac{1}{2} (x-\frac{l}{4})+\frac{1}{2} (y-\frac{l}{4}) + \frac{l}{4} \\ f_2 &: x \to -\frac{1}{2} (x-\frac{l}{4})-\frac{1}{2} (y-\frac{l}{4}) + \frac{3l}{4}, \ \ y \to \frac{1}{2} (x-\frac{l}{4})-\frac{1}{2} (y-\frac{l}{4}) + \frac{l}{4} \end{align} \]

ドラゴン曲線を生成するための2つの反復関数

プログラムコード

今回作成した反復関数を用いたドラゴン曲線のプログラムコードを示します。

int iteration_num = 13; // 反復回数 

void setup(){
  size(600,600);
  background(255,255,255);

  PVector center = new PVector(width/4.0, height/4.0); // 原点の座標
  float len = width/2.0; // 最初に与える線分の長さ

  // 直線を描画する
  line(center.x, center.y, center.x + len, center.y); 
  
  PImage img;
  int iter = 0;
  while(iter<iteration_num){
    // 描いた図形を一旦imgに保存する
    img = createImage(width, height, RGB);
    loadPixels();
    for(int j=0; j<img.height; j++){
      for(int i=0; i<img.width; i++){
        img.set(i, j, pixels[j*width + i]);
      }
    }
    background(255,255,255); // キャンバスを白色で塗りつぶす
    // imgの画素が黒色の場合、2つの反復変換を行ってドラゴン曲線を更新していく
    for(int j=0; j<img.height; j++){
      for(int i=0; i<img.width; i++){
        if(img.get(i,j) == color(0,0,0)){
          rect(center.x + 0.5*(i-center.x) - 0.5*(j-center.y), center.y + 0.5*(i-center.x) + 0.5*(j-center.y), 0.1, 0.1);
          rect(center.x - 0.5*(i-center.x) - 0.5*(j-center.y) + len, center.y + 0.5*(i-center.x) - 0.5*(j-center.y) , 0.1, 0.1);
        }
      }
    }
    iter++;
  }
}

反復関数を用いたゴールデン・ドラゴン曲線

次は、反復関数を用いたゴールデン・ドラゴン曲線です。

反復関数を用いたゴールデン・ドラゴン曲線

ゴールデン・ドラゴン曲線は書籍「アートで魅せる数学の世界」の裏表紙に掲載されている図形です。

ゴールデン・ドラゴン曲線に対する反復関数

下図のように横の長さが\(l\)となるキャンバス(グレーの領域)に対して\(x\)軸と\(y\)軸をとります。そのキャンバス上に点C\((\frac{l}{4},\frac{l}{4})\)をとり、点Cを左端とする長さ\(\frac{l}{2}\)の線分を取ります。この線分を最初の起点として、ドラゴン曲線を生成するための2つの反復関数は以下のようになります。\[ \begin{align} f_1 &: x \to a \cos \alpha (x-\frac{l}{4})-a \sin \alpha (y-\frac{l}{4}) + \frac{l}{4}, \ \ y \to a \sin \alpha (x-\frac{l}{4})+a \cos \alpha (y-\frac{l}{4}) + \frac{l}{4} \\ f_2 &: x \to -a \cos \beta (x-\frac{l}{4})-a \sin \beta (y-\frac{l}{4}) + \frac{3l}{4}, \ \ y \to a \sin \beta (x-\frac{l}{4})-a \cos \beta (y-\frac{l}{4}) + \frac{l}{4} \end{align} \]また、各パラメータは以下のようになります。\[ \phi = \frac{1+\sqrt{5}}{2}, \ \ a = \left( \frac{1}{\phi} \right)^{\frac{1}{\phi}}, \\ \cos \alpha = \frac{1+a^2-a^4}{2a}, \ \ \cos \beta = \frac{1-a^2+a^4}{2a^2} \]

ゴールデン・ドラゴン曲線を生成するための2つの反復関数

プログラムコード

今回作成した反復関数を用いたゴールデン・ドラゴン曲線のプログラムコードを示します。

int iteration_num = 13; // 反復回数 

void setup(){
  size(600,600);
  background(255,255,255);

  PVector center = new PVector(width/4.0, height/4.0); // 原点の座標
  float len = width/2.0; // 最初に与える線分の長さ

  // 直線を描画する
  line(center.x, center.y, center.x + len, center.y); 
  
  // 変換用のパラメータ
  float phi = (1.0+sqrt(5.0))/2.0;
  float a = pow(1.0/phi, 1.0/phi);
  float cosA = (1.0+pow(a,2.0)-pow(a,4.0))/2.0/a;
  float sinA = sqrt(1.0 - pow(cosA,2.0));
  float cosB = (1.0-pow(a,2.0)+pow(a,4.0))/2.0/pow(a,2.0);
  float sinB = sqrt(1.0 - pow(cosB,2.0));
  
  PImage img;
  int iter = 0;
  while(iter<iteration_num){
    // 描いた図形を一旦imgに保存する
    img = createImage(width, height, RGB);
    loadPixels();
    for(int j=0; j<img.height; j++){
      for(int i=0; i<img.width; i++){
        img.set(i, j, pixels[j*width + i]);
      }
    }
    background(255,255,255); // キャンバスを白色で塗りつぶす
    // imgの画素が黒色の場合、2つの反復変換を行ってゴールデン・ドラゴン曲線を更新していく
    for(int j=0; j<img.height; j++){
      for(int i=0; i<img.width; i++){
        if(img.get(i,j) == color(0,0,0)){
          rect(center.x + a*cosA*(i-center.x) - a*sinA*(j-center.y), center.y + a*sinA*(i-center.x) + a*cosA*(j-center.y), 0.1, 0.1);
          rect(center.x - a*a*cosB*(i-center.x) - a*a*sinB*(j-center.y) + len, center.y + a*a*sinB*(i-center.x) - a*a*cosB*(j-center.y) , 0.1, 0.1);
        }
      }
    }
    iter++;
  }
}