生成 Penrose P3 平铺的 L 系统是什么?

问题描述 投票:0回答:1

我正在尝试编写一个 L-System 来生成 Penrose P3 平铺(具有薄菱形和厚菱形,我将它们称为 Rhombus-A 和 Rhombus-B。

对于渲染,我计划使用以下字符。

  • '+'表示逆时针旋转 TWO_PI/20
  • '-'表示顺时针旋转TWO_PI/20
  • 'A'表示画菱形-A
  • 'B'表示画菱形-B
  • '['推变换矩阵
  • ']' 弹出变换矩阵

我的问题是 L 系统会生成 Penrose P3 平铺吗?任何参考将不胜感激。

我已经走到这一步了:

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>

您还可以将代码复制/粘贴到此处以快速测试和操作代码:

https://editor.p5js.org/

algorithm p5.js tiling l-systems
1个回答
0
投票

经过几个小时的反复试验,我放弃了原来的方法,深入研究了数学史,发现了这个绘制菱形边缘而不是菱形形状的解决方案。由于它满足了上面所述的问题,我将其发布在这里。然而,我仍然没有找到通过绘制薄菱形和厚菱形来生成彭罗斯 P3 平铺的 L 系统的答案。

let ds;

function setup() {
  createCanvas(1200, 1200);
  ds = new PenroseLSystem();
  //please, play around with the following line
  ds.simulate(6);
}

function draw() {
  background(100,200, 255);
  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 = windowWidth;
    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();
      }
    }
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.