有限拡散集合 (DLA)

2021年12月15日

はじめに

有限拡散集合あるいは拡散律速凝集 (DLA: diffusion-limited aggregation) の描画を Processing で行う。

DLA

DLA は、植物の模様、固体のき裂、稲妻の模様のような、そういう絵を簡単な規則から与える。

DLA の描き方は単純である。格子状の世界を考えて、その上を点が四方にランダムに動くものとする。最初に種となる点を置いておく。空間に点を投入し、ランダムに動かす。点が静止している点の隣に来たら、その点を静止させる。そして新しい点を投入し、静止した点の隣に来るまでランダムに動かす。これを繰り返す。

Processing で描画すると、以下のようになる。

dla.pde

final int width = 300;
final int height = 300;
Boolean[][] points = new Boolean[width+1][height+1];

void setup() {
  size(300, 300);
  background(255);
  frameRate(30);
  
  color red = color(255, 0, 0);
  stroke(red);
  
  for (int i = 0; i <= width; i++) {
    for (int j = 0; j <= height; j++) {
      points[i][j] = false;
    }
  }
  
  randomSeed(0);
  //randomSeed(100);
  
  int i = width/2;
  int j = height/2; // center
  //int j = height - 1; // bottom
  
  point(i, j);
  points[i][j] = true;
}

void draw() {
  int i = 0;
  int j = 0;
  
  int side = int(random(4));
  //side = 2; // top
  
  switch (side) {
    case 0: // left
      i = 1;
      j = int(random(1, height - 1));
      break;
    case 1: // right
      i = width - 1;
      j = int(random(1, height - 1));
      break;
    case 2: // top
      i = int(random(1, width - 1));
      j = 1;
      break;
    case 3: // bottom
      i = int(random(1, width - 1));
      j = height - 1;
      break;
  }
  
  while (true) {
    int direction = int(random(4));
    switch (direction) {
      case 0: // left
        i--;
        break;
      case 1: // right
        i++;
        break;
      case 2: // up
        j--;
        break;
      case 3: // down
        j++;
        break;
    }
    
    if (i == 0) i = 1;
    else if (i == width) i = width - 1;
    if (j == 0) j = 1;
    else if (j == height) j = height - 1;
    
    if (points[i-1][j] || points[i+1][j] ||
        points[i][j-1] || points[i][j+1]) {
      println(i, j);
      point(i, j);
      points[i][j] = true;
      break;
    }
  }
}

void keyPressed() {
  final int k = keyCode;
  if (k == 32) { // space
    if (looping) noLoop();
    else loop();
  } else if (k == 'P') {
    println("save");
    save("fig.png");
  }
}

配列 points に点のありなしを記録する。setup() では、初期化を行っている。最初の点を中心あるいは底に設定する。draw() では、まず点を投入する位置を決めて、そこから点を動かしていく。隣接点が存在したら、そこに点を打って次に行く。

描画例

描画例を示す。種の位置と、点投入の位置、乱数 seed を変えている。植物ような模様が得られている。

左: 種中心、seed = 0/右: 種中心、seed = 100

左: 種底面、seed = 0/右: 種底面、seed = 100

種底面、点投入上面、seed = 100

参考文献

  • ニーナ・ホール編: カオスの素顔, 講談社, 1994