I saw segaldigital implementation (reddit.com/r/plotter…_dots_some_hexagons/) of Leon Rische's blogpost leonrische.me/pages/generative_art_with_cfgs.html and I thought... nice!
Hexogonal Tree ⬡ (variation)
Hexogonal Tree ⬡ (variation)
Log in to post a comment.
const length = 15; // min=1 max=100 step=1
const lengthRatio = .5; // min=0 max=1 step=.1
const thickness = 5; // min=1 max=10 step=1
const thicknessRatio = .6 // min=0 max=1 step=.1
const generationLimit = 4 // min=1 max=20 step=1
const iterationLimit = 30 // min=1 max=30 step=1
const invForkProbPerGen = .70 // min=.50 max=1 step=.001
const invForkProbPerIter = .87 // min=.50 max=1 step=.01
const circleProb = .1 //min=0 max=.5 step=.01
// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(.8);
const forkProbPerGen = 1 - invForkProbPerGen;
const forkProbPerIter = 1 - invForkProbPerIter;
// Global code will be evaluated once.
class Fork {
constructor(branches, state, iteration, generation) {
this.state = state;
this.iteration = iteration | 0;
this.generation = generation | 0;
this.branches = branches;
}
generate(t) {
this.state.restore(t);
if(this.generation < generationLimit) {
let gts = new TurtleState(t);
gts.thickness *= thicknessRatio;
(new Fork(3, gts, 0, this.generation + 1)).generate(t);
}
let bLength = length * Math.pow(lengthRatio, this.generation);
this.state.restore(t);
if(Math.random() < circleProb) {
t.seth(270);
let circleDivisions = 3;
t.jump(t.x() - ((bLength * .25) / circleDivisions), t.y());
for(let d = 1; d < 4; d++) {
let show = Math.random() < .5;
let start = ((bLength * .25) / circleDivisions) * d;
let max = ((bLength * .25) / circleDivisions) * (d + 1);
for(let r = start; r < max; r += .25) {
t.jump(t.x() -.25, t.y());
if(show) {
t.circle(r);
}
}
}
this.state.restore(t);
}
this.state.restore(t);
t.left(60);
let ts = new TurtleState(t);
let forks = [];
for(let i = 0; i < this.branches; i++) {
if(this.iteration < iterationLimit && Math.random() > (forkProbPerGen * this.generation) + (forkProbPerIter * this.iteration)) {
t.forward(bLength);
forks.push(new Fork(2, new TurtleState(t), this.iteration + 1, this.generation));
}
ts.restore(t);
t.right(120);
ts.store(t);
}
forks.forEach(function(f) {
if(f.iteration < 7) {
f.generate(t);
}
});
}
}
class TurtleState {
constructor(...args) {
this.store(...args);
}
store(turtle, x, y, isdown, thickness) {
this.h = turtle;
this.x = x;
this.y = y;
this.isdown = isdown;
this.thickness = thickness
if(x === undefined) {
this.h = turtle.h();
this.x = turtle.x();
this.y = turtle.y();
this.isdown = turtle.isdown();
this.thickness = turtle.thickness;
}
}
restore(turtle) {
turtle.seth(this.h);
turtle.jump(this.x, this.y);
this.isdown? turtle.down(): turtle.up();
turtle.thickness = this.thickness;
}
clone() {
return new TurtleState(this.h, [this.x, this.y], this.isdown, this.thickness);
}
}
// The walk function will be called until it returns false.
function walk(i) {
const turtle = new Slowbro(); turtle.thickness = thickness;
const s = new TurtleState(turtle);
let f = new Fork(3, s);
f.generate(turtle);
return false;
turtle.forward(100);
s.restore(turtle);
turtle.right(144);
s.save(turtle);
return i < 4;
}
////////////////////////////////////////////////////////////////
// Slowbro utility code. Created by Lionel Lemarie 2021
// Based on Slowpoke, which removes most duplicate lines
// Slowbro adds optional thickness to the lines
////////////////////////////////////////////////////////////////
function Slowbro(x, y) {
const linesDrawn = {};
class Slowbro extends Turtle {
constructor(x, y) {
super(x, y);
this.thickness = 1; this.offset = 0.2;
this.slowpoke_skip = this.slowpoke_draw = 0;
}
goto(x, y) {
if (Array.isArray(x)) { y = x[1]; x = x[0]; }
const ox = this.x(), oy = this.y();
if (this.isdown()) {
const p = [x, y], o = [ox, oy];
const h1 = o[0].toFixed(2) + '_' + p[0].toFixed(2) + o[1].toFixed(2) + '_' + p[1].toFixed(2);
const h2 = p[0].toFixed(2) + '_' + o[0].toFixed(2) + p[1].toFixed(2) + '_' + o[1].toFixed(2);
if (linesDrawn[h1] || linesDrawn[h2]) {
super.up(); super.goto(p); super.down();
this.slowpoke_skip++;
return;
}
linesDrawn[h1] = linesDrawn[h2] = true;
this.slowpoke_draw++;
for (var dx = this.thickness-1; dx >=0 ; dx--) {
for (var dy = this.thickness-1; dy >= 0; dy--) {
if (!dx && !dy) continue;
super.goto( x + dx * this.offset, y + dy * this.offset);
super.goto(ox + dx * this.offset, oy + dy * this.offset);
}
}
}
super.goto(x, y);
}
}
return new Slowbro(x, y);
}