/*https://editor.p5js.org/p5/sketches/Simulate:_penrose_tiles
* @name Penrose Tiles
* @frame 710,400
* @description This is a port by David Blitz of the "Penrose Tile" example from processing.org/examples
*/
let ds;
function setup() {
createCanvas(710, 400);
ds = new PenroseLSystem();
//please, play around with the following line
ds.simulate(5);
}
function draw() {
background(0);
ds.render();
}
function PenroseLSystem() {
this.steps = 0;
//these are axiom and rules for the penrose rhombus l-system
//a reference would be cool, but I couldn't find a good one
this.axiom = "[X]++[X]++[X]++[X]++[X]";
this.ruleW = "YF++ZF----XF[-YF----WF]++";
this.ruleX = "+YF--ZF[---WF--XF]+";
this.ruleY = "-WF++XF[+++YF++ZF]-";
this.ruleZ = "--YF++++WF[+ZF++++XF]--XF";
//please play around with the following two lines
this.startLength = 460.0;
this.theta = TWO_PI / 10.0; //36 degrees, try TWO_PI / 6.0, ...
this.reset();
}
PenroseLSystem.prototype.simulate = function (gen) {
while (this.getAge() < gen) {
this.iterate(this.production);
}
}
PenroseLSystem.prototype.reset = function () {
this.production = this.axiom;
this.drawLength = this.startLength;
this.generations = 0;
}
PenroseLSystem.prototype.getAge = function () {
return this.generations;
}
//apply substitution rules to create new iteration of production string
PenroseLSystem.prototype.iterate = function() {
let newProduction = "";
for(let i=0; i < this.production.length; ++i) {
let step = this.production.charAt(i);
//if current character is 'W', replace current character
//by corresponding rule
if (step == 'W') {
newProduction = newProduction + this.ruleW;
}
else if (step == 'X') {
newProduction = newProduction + this.ruleX;
}
else if (step == 'Y') {
newProduction = newProduction + this.ruleY;
}
else if (step == 'Z') {
newProduction = newProduction + this.ruleZ;
}
else {
//drop all 'F' characters, don't touch other
//characters (i.e. '+', '-', '[', ']'
if (step != 'F') {
newProduction = newProduction + step;
}
}
}
this.drawLength = this.drawLength * 0.5;
this.generations++;
this.production = newProduction;
}
//convert production string to a turtle graphic
PenroseLSystem.prototype.render = function () {
translate(width / 2, height / 2);
this.steps += 20;
if(this.steps > this.production.length) {
this.steps = this.production.length;
}
for(let i=0; i<this.steps; ++i) {
let step = this.production.charAt(i);
//'W', 'X', 'Y', 'Z' symbols don't actually correspond to a turtle action
if( step == 'F') {
stroke(255, 60);
for(let j=0; j < this.repeats; j++) {
line(0, 0, 0, -this.drawLength);
noFill();
translate(0, -this.drawLength);
}
this.repeats = 1;
}
else if (step == '+') {
rotate(this.theta);
}
else if (step == '-') {
rotate(-this.theta);
}
else if (step == '[') {
push();
}
else if (step == ']') {
pop();
}
}
}