xxxxxxxxxx
253
let TRIES = 25 //30 // 20;
let PICKED_MAX = 3;
let MAX_DEPTH = 75;
let VEL_RANGE = .01;
let VEL_RANGE_FACTOR_MAX = 0.5;
let DIR_RAND_MAX = 0.125;
let INITIAL_R = 0.01;
let MIN_R = 0.0005;
let SHRINK_R_MIN = .5;
let SHRINK_R_MAX = 3;
let COS_COLORS = [0, 0.1, 0.66];
let BG_COLOR = "black";
// let BG_COLOR = "white";
let SIZE;
let tex;
function setup() {
SIZE = 1080 * 8; //min(windowWidth, windowHeight);
createCanvas(SIZE, SIZE);
initialize();
}
let nodes, open_nodes;
function initialize() {
const size = floor(1 / (INITIAL_R * 2));
nodes = new Array(size).fill(null).map(() =>
new Array(size).fill(null).map(() => []));
const initial_node = createNode(0.5, 0.1, INITIAL_R, .25, 0, null);
open_nodes = [initial_node];
done = false;
colorMode(RGB, 1);
background(BG_COLOR);
noFill();
// TRIES = random(50);
// PICKED_MAX = random(5);
// MAX_DEPTH = random(50, 200);
// VEL_RANGE = random(.1);
// VEL_RANGE_FACTOR_MAX = random(1);
// DIR_RAND_MAX = random(.25);
// INITIAL_R = random(0.05);
// MIN_R = random(0.005);
// SHRINK_R_MIN = random(1);
// SHRINK_R_MAX = random(5);
// COS_COLORS = [random(), random(), random()];
// console.log("TRIES", TRIES);
// console.log("PICKED_MAX", PICKED_MAX);
// console.log("MAX_DEPTH", MAX_DEPTH);
// console.log("VEL_RANGE", VEL_RANGE);
// console.log("VEL_RANGE_FACTOR_MAX", VEL_RANGE_FACTOR_MAX);
// console.log("DIR_RAND_MAX", DIR_RAND_MAX);
// console.log("INITIAL_R", INITIAL_R);
// console.log("MIN_R", MIN_R);
// console.log("SHRINK_R_MIN", SHRINK_R_MIN);
// console.log("SHRINK_R_MAX", SHRINK_R_MAX);
// console.log("COS_COLORS", COS_COLORS);
console.log();
}
const pad_y = 0.1;
const pad_x = 0.3;
function createNode(x, y, r, dir, vel, parent) {
if (x < pad_x || x >= 1 - pad_x || y < pad_y /*|| y >= 1 - pad_y*/)
return null;
let picked = 0;
const b_r = (1 - pad_x * 2) / 2;
const b_y = 1 - pad_y;
const b_c_y = b_y - b_r;
if (/*x < pad_x || x >= 1 - pad_x || y < pad_y ||*/ y >= 1 - pad_y
|| y > b_c_y && sqrt(pow(x - 0.5, 2) + pow(y - b_c_y, 2)) > b_r
) {
if (r == INITIAL_R) {
x = 0.5;
y = b_y;
picked = PICKED_MAX;
}else
return null;
}
const size = nodes.length;
const x_i = floor(x * size);
const y_i = floor(y * size);
for (let c_x=max(0, x_i - 1); c_x <= min(x_i + 1, size - 1); c_x++)
for (let c_y=max(0, y_i - 1); c_y <= min(y_i + 1, size - 1); c_y++)
if (nodes[c_x][c_y].some(n => n != parent && sqrt(pow(n.x - x, 2) + pow(n.y - y, 2)) < r + n.r))
return null;
const node = {
x, y, r,
dir, vel,
parent,
depth: parent ? parent.depth + 1 : 0,
picked,
}
nodes[x_i][y_i].push(node);
return node;
}
function grow() {
if (open_nodes.length) {
const node = open_nodes.shift();
// open_nodes = open_nodes.filter(n => n != node);
// if (node.depth > MAX_DEPTH)
// return;
// if (node.r == MIN_R)
// return;
let new_node;
let its = 0;
let new_vel = node.picked == 0
? node.vel
// : node.vel * 0.25
// : random([0, node.vel * random()])
// : node.vel * random()
: 0
const new_r = max(MIN_R, node.r - node.picked * MIN_R * random(SHRINK_R_MIN, SHRINK_R_MAX))
let vel_range = VEL_RANGE * (1 - map(new_r, MIN_R, INITIAL_R, 0, VEL_RANGE_FACTOR_MAX));
// let vel_range = VEL_RANGE * (1 - map(node.depth, 0, MAX_DEPTH, 0, VEL_RANGE_FACTOR_MAX));
do {
const dir_rand = random(0, DIR_RAND_MAX);
const dir = node.dir
+ (node.picked == 0
? 0
: random([
-dir_rand,
dir_rand,
// 0.5 - dir_rand,
// 0.5 + dir_rand,
]));
new_vel += random(-vel_range, vel_range);
let new_dir = dir + new_vel;
if (new_r == INITIAL_R && node.picked == 0) {
const b_y = 1 - pad_y;
new_dir = lerp(
new_dir,
atan2(b_y - node.y, 0.5 - node.x) / TAU,
pow(map(node.y, pad_y, b_y, 0, 1), 2)
);
}
const new_x = node.x + cos(new_dir * TAU) * (node.r + new_r);
const new_y = node.y + sin(new_dir * TAU) * (node.r + new_r);
new_node = createNode(new_x, new_y, new_r, new_dir, new_vel, node);
its++
}while(new_node == null && its < TRIES);
// if (new_node == null) {
// if (node.parent) open_nodes.push(node.parent);
// } else {
// for (let i=0; i<2; i++)
node.picked++;
if (new_node) {
open_nodes.push(new_node);
if (node.picked < PICKED_MAX && !open_nodes.includes(node)) open_nodes.push(node);
}
else if (node.parent && !open_nodes.includes(node.parent)) open_nodes.push(node.parent);
return new_node;
}
}
function drawNode(node) {
// circle(
// node.x * width,
// node.y * height,
// node.r * 2 * width,
// );
if (node.parent === null)
return;
const x1 = node.parent.x;
const y1 = node.parent.y;
const cx1 = node.parent.x + cos(node.parent.dir * TAU) * node.parent.r * 0.5;
const cy1 = node.parent.y + sin(node.parent.dir * TAU) * node.parent.r * 0.5;
const cx2 = node.x - cos(node.dir * TAU) * node.r * 0.5;
const cy2 = node.y - sin(node.dir * TAU) * node.r * 0.5;
const x2 = node.x;
const y2 = node.y;
strokeWeight(node.r * SIZE * 1);
const v = min(1, node.depth / MAX_DEPTH)
stroke(
cosn(v + COS_COLORS[0]),
cosn(v + COS_COLORS[1]),
cosn(v + COS_COLORS[2])
);
bezier(
x1 * SIZE, y1 * SIZE,
cx1 * SIZE, cy1 * SIZE,
cx2 * SIZE, cy2 * SIZE,
x2 * SIZE, y2 * SIZE,
);
}
function draw() {
for (let i=0; i<500; i++) {
const node = grow();
if (node) drawNode(node);
}
// console.log(open_nodes.length);
if (open_nodes.length == 0) {
save();
initialize();
}
}
function cosn(v) {
return 0.5 + 0.5 * cos(v * TAU);
}