Moving circles around until they stop overlapping.
Log in to post a comment.
// LL 2021
const particle_count = 250; // min=1 max=1000 step=1
const iterations = 100; // min=0 max=1000 step=1
const collision_loop = 101 // min=1 max=1000 step=10
const min_radius = 0.06 // min=0.001 max=0.1 step=0.001
const max_radius = 0.7 // min=0.01 max=1.0 step=0.01
const min_bias = 6 // min=1 max=50 step=1
const fill_step = 0.75; // min=0.05 max=1 step=0.05
const seed = 0; // min=0 max=100 step=1
const scale = 100; // min=10 max=1000 step=10
Canvas.setpenopacity(1);
const turtle = new Turtle();
class Particle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
update() {
const factor = 0.99;
this.x *= factor;
this.y *= factor;
}
}
function resolve_collisions() {
for (var r=0; r<collision_loop; r++) {
for (var i=0; i<particle_count; i++) {
for (var j=i+1; j<particle_count; j++) {
var dx = particles[i].x - particles[j].x;
var dy = particles[i].y - particles[j].y;
var dist = Math.sqrt(dx*dx + dy*dy);
const min_dist = particles[i].r + particles[j].r;
while (dist < min_dist) {
const factor = 0.001;
particles[i].x += dx * factor;
particles[i].y += dy * factor;
particles[j].x -= dx * factor;
particles[j].y -= dy * factor;
dx = particles[i].x - particles[j].x;
dy = particles[i].y - particles[j].y;
dist = Math.sqrt(dx*dx + dy*dy);
}
}
}
}
}
function random_particle() {
const x = rng.nextFloat() * 2 - 1;
const y = rng.nextFloat() * 2 - 1;
const r = Math.pow(rng.nextFloat(), min_bias) * (max_radius - min_radius) + min_radius;
return new Particle(x, y, r);
}
var particles = null;
function update_particles(loop_count) {
resolve_collisions();
for (var i=0; i<loop_count; i++) {
for (var p=0; p<particle_count; p++) {
particles[p].update();
}
resolve_collisions();
}
}
function walk(i, t) {
if (particles == null) {
particles = Array.from({length: particle_count}, (_, id) => (random_particle()));
update_particles(t * iterations);
}
turtle.jump(particles[i].x * scale, particles[i].y * scale - particles[i].r * scale);
turtle.circle(particles[i].r * scale);
for (var r = particles[i].r * scale - fill_step; r > 0 && fill_step < 1; r -= fill_step) {
turtle.jump(particles[i].x * scale, particles[i].y * scale - r);
turtle.circle(r)
}
return (i+1) < particle_count;
}
///////
//// Random with seed
function RNG(_seed) {
// LCG using GCC's constants
this.m = 0x80000000; // 2**31;
this.a = 1103515245;
this.c = 12345;
this.state = _seed ? _seed : Math.floor(Math.random() * (this.m - 1));
}
RNG.prototype.nextFloat = function() {
// returns in range [0,1]
this.state = (this.a * this.state + this.c) % this.m;
return this.state / (this.m - 1);
}
var rng = new RNG(seed);