OPENRNDR & Processing - Coral growth

Diffusion Limited Aggregation

A program that keeps a collection of circles. Initially there is only one located at the center of the screen. Circles of decreasing size are shot from the outskirts towards the center of the screen. When they touch any circle they freeze and become part of the collection. Read more about this algorithm at http://paulbourke.net/fractals/dla/.

Processing / Java

ArrayList<PVector> circles = new ArrayList<PVector>();
void setup() {
  fullScreen();
  noStroke();
  fill(40);
  background(220);
  circles.add(new PVector(0, 0, 120));
}
void draw() {
  background(255);
  translate(width/2, height/2);
  for (PVector p : circles) { 
    ellipse(p.x, p.y, p.z, p.z);
  }
  PVector newPos = PVector.fromAngle(millis() * 0.05).mult(width);
  float newDiam = circles.get(circles.size()-1).z * 0.98;
  boolean search = true;
  while (search) {
    newPos.sub(newPos.copy().normalize());
    for (int i=circles.size()-1; i>=0; i--) {
      PVector other = circles.get(i);
      float d = dist(other.x, other.y, newPos.x, newPos.y);
      float minDist = other.z * 0.5 + newDiam * 0.5 + 5;
      if (d < minDist) {
        newPos.z = newDiam;
        circles.add(newPos);
        search = false;
        break;
      }
    }
  }
}

OPENRNDR / Kotlin

fun main() = application {
    configure {
        fullscreen = Fullscreen.CURRENT_DISPLAY_MODE
    }
    program {
        val circles = mutableListOf(Circle(0.0, 0.0, 60.0))

        extend {
            drawer.stroke = null
            drawer.fill = rgb(0.2)
            drawer.background(rgb(0.9))
            drawer.translate(drawer.bounds.center)
            drawer.circles(circles)

            var newPos = Polar(seconds * 5091, width * 1.0).cartesian
            var newRadius = circles.last().radius * 0.98
            var search = true
            while (search) {
                newPos -= newPos.normalized
                circles.lastOrNull { other ->
                    val d = (other.center - newPos).length
                    val minDist = other.radius + newRadius + 5
                    d < minDist
                }?.run {
                    circles.add(Circle(newPos, newRadius))
                    search = false
                }
            }
        }
    }
}

Differences to note:

Topic Processing OPENRNDR
define and initialize a collection ArrayList<PVector> circles = new ArrayList<PVector>();
circles.add(new PVector(0, 0, 120));
val circles = mutableListOf(Circle(0.0, 0.0, 60.0))
drawing circles expects width and height: initial size is 120.0 then multiplies diameters by 0.5 expects radius: initial size is 60.0
colors defined using byte values (0 ~ 255) defined using normalized values (0.0 ~ 1.0)
vector data type PVector Vector2, Vector3 and Vector4, but in this case we use Circle for two reasons: one, we can use it with the method drawer.circles() to efficiently draw collections of circles and two, the code becomes more readable by using .center and .radius instead of .x, .y and .z
polar coordinates PVector.fromAngle(radians) then call .mult(radius) to set the length Polar(degrees, radius).cartesian
finding last circle colliding with the current moving circle classic for loop with break when found lastOrNull searches for the last colliding item. if found ?.run a block of code to add a circle
center of the screen (width/2, height/2) drawer.bounds.center or
(width/2.0, height/2.0)
declaring variables specify type: float, boolean, ArrayList<PVector> use var (mutable) or val (inmutable)
time millis() seconds

:point_down: Share your questions and comments below | :mag_right: Find other OPENRNDR & Processing posts

4 Likes