Penrose
5 years ago in HTML
<html lang="en">
<head>
<script type='text/javascript' src='https://p5js.org/assets/js/p5.min.js'></script>
<script type='text/javascript' src='https://p5js.org/assets/js/p5.dom.min.js'></script>
<script type='text/javascript' src='https://p5js.org/assets/js/p5.sound.min.js'></script>
<style>
html, body {
overflow: hidden;
margin: 0;
padding: 0;
background: white;
}
</style>
<title>PenroseLSystem</title>
</head>
<body>
<script>
let penroseLSystem;
function setup() {
createCanvas(window.innerWidth, window.innerHeight);
penroseLSystem = new PenroseLSystem();
penroseLSystem.simulate(5);
}
function draw() {
background(0);
penroseLSystem.render();
}
class PenroseLSystem {
static AXIOM = "[X]++[X]++[X]++[X]++[X]";
static RULES = {
W: "YF++ZF----XF[-YF----WF]++",
X: "+YF--ZF[---WF--XF]+",
Y: "-WF++XF[+++YF++ZF]-",
Z: "--YF++++WF[+ZF++++XF]--XF",
};
static TURTLE_ACTIONS = {
F: ({drawLength}) => {
stroke(255, 60);
line(0, 0, 0, -drawLength);
noFill();
translate(0, -drawLength);
},
'+': ({theta}) => rotate(theta),
'-': ({theta}) => rotate(-theta),
'[': () => push(),
']': () => pop(),
};
constructor() {
this.steps = 0;
this.startLength = 460.0;
this.theta = TWO_PI / 10.0; //36 degrees, try TWO_PI / 6.0, ...
this.reset();
}
simulate(gen) {
while (this.getAge() < gen) {
this.iterate();
}
}
reset() {
this.production = PenroseLSystem.AXIOM;
this.drawLength = this.startLength;
this.generations = 0;
}
getAge = () => this.generations;
getCurrentProductionSteps = () => [...this.production];
iterate() {
const newProduction = this.getCurrentProductionSteps()
.map(step => {
if (PenroseLSystem.RULES.hasOwnProperty(step)) {
return PenroseLSystem.RULES[step];
}
//drop all 'F' characters
if (step === 'F') {
return "";
}
//don't touch characters ('+', '-', '[', ']'
return step;
})
.join("");
this.drawLength = this.drawLength * 0.5;
this.generations++;
this.production = newProduction;
}
render() {
translate(width / 2, height / 2);
this.steps = Math.min(this.steps + 20, this.production.length);
this.getCurrentProductionSteps()
.slice(0, this.steps)
.filter(step => PenroseLSystem.TURTLE_ACTIONS.hasOwnProperty(step))
.forEach(step => PenroseLSystem.TURTLE_ACTIONS[step](this));
}
}
</script>
</body>
</html>