I am trying to write an L-System to generate the Penrose P3 tiling (with thin and thick rhombi, I will call them Rhombus-A and Rhombus-B.
For render, I am planning to use the following chars.
- '+' means rotate counter-clockwise TWO_PI/20
- '-' means rotate clockwise TWO_PI/20
- 'A' means draw Rhombus-A
- 'B' means draw Rhombus-B
- '[' push transformation matrix
- ']' pop transformation matrix
And my question is what would the L-System be to generate an Penrose P3 tiling? Any references would be appreciated.
I got this far:
function penroseP3(){
this.a = 20; //side length
this.center = createVector(width/2, height/2)
this.theta = TWO_PI/20;
this.axiom = "[X]++++[X]++++[X]++++[X]++++[X]";
this.ruleX = "A-------[B[+++++A]+++++++++A[--[A[++++++A][------A]]][-----B][-------B[+A]][+B[+A]][+++B]++++++A]";
this.sentence = this.axiom;
this.substitute = function() {
//apply substitution rules to create new iteration of sentence string
let newSentence = "";
for (let i = 0; i < this.sentence.length; ++i) {
let step = this.sentence.charAt(i);
//if current character is 'W', replace current character
//by corresponding rule
if (step == 'W') {
newSentence = newSentence + this.ruleW; //not defined yet
} else if (step == 'X') {
newSentence = newSentence + this.ruleX;
} else if (step == 'Y') {
newSentence = newSentence + this.ruleY; //not defined yet
} else if (step == 'Z') {
newSentence = newSentence + this.ruleZ; //not defined yet
} else {
newSentence = newSentence + step; //Do nothing
}
}
this.generations++;
this.sentence = newSentence;
}
this.LSystem = function(generations) {
for (let i = 0; i < generations; i++) {
this.substitute();
}
}
this.drawRhombusA = function(){
push();
beginShape();
//bottom vertex
vertex(0, 0);
vertex(this.a * sin(2*this.theta), -this.a * cos(2*this.theta));
vertex(0, -2*this.a * cos(2*this.theta));
vertex(-this.a * sin(2*this.theta), -this.a * cos(2*this.theta));
endShape(CLOSE);
pop();
}
this.drawRhombusB = function(){
push();
beginShape();
//bottom vertex
vertex(0, 0);
vertex(this.a * sin(this.theta), -this.a * cos(this.theta));
vertex(0, -2*this.a * cos(this.theta));
vertex(-this.a * sin(this.theta), -this.a * cos(this.theta));
endShape(CLOSE);
pop();
}
this.draw = function() {
let steps = this.sentence;
// console.log(this.sentence);
translate(this.center);
for (let i = 0; i < steps.length; i++) {
let step = steps.charAt(i);
if (step == 'A') {
this.drawRhombusA();
translate(0, - 2*this.a*cos(2*this.theta));
} else if (step == 'B') {
this.drawRhombusB();
translate(this.a*sin(this.theta), -this.a*cos(this.theta));
} else if (step == '+') {
rotate(this.theta);
} else if (step == '-') {
rotate(-this.theta);
} else if (step == '[') {
push();
} else if (step == ']') {
pop();
}
}
}
}
let p3;
function setup() {
createCanvas(windowWidth, 300);
p3 = new penroseP3();
p3.LSystem(2)
}
function draw() {
background(100,200, 255);
p3.draw();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>
You can also copy/paste the code here to quickly test and manipulate the code:

After several hours of trial and error, I gave up on the original method and digged deeper in the annals of Mathematics, and found this solution that draws the edges of the rhombi rather than the rhobmi shapes. Since it satisfies the question as it is stated above I will post it here. However I still don't have an answer for an L-System that generates the Penrose P3 tiling by drawing the thin and thick Rhombi.