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 |
Share your questions and comments below |
Find other OPENRNDR & Processing posts