xxxxxxxxxx
const angle = 20;
const n = 7;
let length;
let symbols;
let prop = {};
function setup() {
createCanvas(windowWidth, windowHeight);
length = width / 80;
angleMode(DEGREES);
frameRate(1);
symbols = lsystem('X', {
'X': 'F[+X][-X]',
'F': 'FF'
}, n);
for(let i = 0; i < symbols.length - 1; i++) {
let symbol = symbols[i];
if(prop[symbol] === undefined) {
prop[symbol] = [];
}
prop[symbol].push(symbols[i + 1]);
}
strokeWeight(10);
}
function draw() {
background(0, 0, 150);
let generated = '';
let current = 'F';
for(let i = 0; i < symbols.length * 3; i++) {
let nx = random(prop[current]);
generated += nx;
current = nx;
}
let lines = lsystemTurtle(generated, 'X');
translate(width / 2, height);
rotate(-90);
for(let i = 0; i < lines.length; i++) {
stroke(random(255), i / lines.length * 255, i / lines.length * 255);
const {from, to} = lines[i];
line(from.x, from.y, to.x, to.y);
}
}
function lsystemTurtle(generated, forwardSymbols = '') {
let symbols = Array.from(generated);
if(forwardSymbols.length > 0) {
symbols = symbols.map(symbol => forwardSymbols.includes(symbol) ? 'F' : symbol);
}
const t = new Turtle();
const lines = [];
for(let i = 0; i < symbols.length; i++) {
switch(symbols[i]) {
case 'F':
lines.push(t.forward(length)); break;
case 'f':
t.forward(length); break;
case '+':
t.turn(-angle); break;
case '-':
t.turn(angle); break;
case '|':
t.reverse(); break;
case '[':
t.push(); break;
case ']':
if(t.state.length > 0) {
t.pop();
}
break;
}
}
return lines;
}
function lsystem(axiom, rules, n) {
function produceOne(variable, rules) {
if(rules[variable]) {
return Array.from(rules[variable]);
}
return [variable];
}
function produceAll(axiom, rules, n) {
let symbols = Array.from(axiom);
for(let i = 0; i < n; i++) {
symbols = symbols.flatMap(symbol => produceOne(symbol, rules));
}
return symbols;
}
return produceAll(axiom, rules, n).join('');
}
class Turtle {
constructor(x = 0, y = 0, angle = 0) {
this.coordinateVector = createVector(x, y);
this.headingVector = createVector(1, 0).rotate(angle);
this.state = [];
}
coordinate() {
return {
x: this.coordinateVector.x,
y: this.coordinateVector.y
};
}
forward(length) {
const from = this.coordinate();
const v = p5.Vector.mult(this.headingVector, length);
this.coordinateVector.add(v);
const to = this.coordinate();
return {from, to};
}
turn(angle) {
this.headingVector.rotate(angle);
}
push() {
this.state.push(new Turtle(
this.coordinateVector.x,
this.coordinateVector.y,
this.headingVector.heading()
));
}
pop() {
const t = this.state.pop();
this.coordinateVector = t.coordinateVector;
this.headingVector = t.headingVector;
}
reverse() {
this.headingVector.mult(-1);
}
}