JavaScript code for producing Lindenmayer systems

From JSXGraph Wiki
Revision as of 09:30, 31 January 2013 by Michael (talk | contribs)

Here is an explanation of the JavaScript code that produces the pictures in L-systems. It uses the Turtle Graphics implementation of JSXGraph.

For example, the Sierpinski curve in L-systems is defined by the following Lindenmayer system:

var level = 6;
var axiom = 'A';
var rules = {
    'A':'B-A-B',
    'B':'A+B+A',
    '+' : '+',
    '-' : '-'
};
var symbols = { 'A':'F', 
                'B':'F', 
                '+':'+', 
                '-':'-', 
                '[':'[', 
                ']':']'  
              }; 
var angle = 60; 
var len = 500/Math.pow(2,level); 
t.setPos(-250*Math.pow(-1,level),-250); 
t.rt(90*Math.pow(-1,level));

JSXGraph for the various boards and the turtle graphics are initialized by the following code:

var t;
var turtle = [];
var brd = [];
brd[0] = JXG.JSXGraph.initBoard('box0', {boundingbox: [-300, 300, 300, -300]});
turtle[0] = brd[0].createElement('turtle');
var shrink = 1.0;

Here is the recursive code to expand an axiom of a Lindenmayer system into a string:

function expander(level,axiom,rules) {
    this.axiom = axiom;
    this.rules = rules;
    this.source = (level>1) ? new expander(level-1,axiom,rules) : (new function() {
        // Axiom:
        this.code = axiom;
        this.pos = 0;
        this.next = function() {
            if (this.pos>=this.code.length) return null;
            return this.code.charAt(this.pos++);
        }
    });
    
    this.code = '';
    this.pos = 0;
    this.next = function() {
        while (this.pos>=this.code.length) { // produce new symbols from source
            this.pos = 0;
            var pattern = this.source.next();
            if (!pattern) return null // Finished
            this.code = this.rules[pattern];
        }
        return this.code.charAt(this.pos++);
    }
}

The string of an Lindenmayer system can be plotted by the JSXGraph-powered turtle:

function plotter(generator,symbols,len,angle,t,shrink) {
    for (var c; c=generator.next(); c) {
        switch(symbols[c]) {
            case 'F':
                t.fd(len);
                break;
            case 'f':
                t.penUp();
                t.fd(len);
                t.penDown();
                break;
            case '+':
                t.lt(angle);
                break;
            case '-':
                t.rt(angle);
                break;
            case '[':
                t.pushTurtle();
                len *= shrink;
                break;
            case ']':
                t.popTurtle();
                len /= shrink;
                break;
            default:
                ;
        }
    }
    return null;
  }

After clicking on a run-button in L-systems the following code is started:

function run(nr) {
  brd[nr].suspendUpdate();
  var code = $('inputtext'+nr).value;
  if (code=='') { return; }
  t = turtle[nr];
  t.cs();
  t.hideTurtle();
  eval(code);
  var generator = new expander(level,axiom,rules);
  plotter(generator,symbols,len,angle,t,shrink);
  brd[nr].unsuspendUpdate();
}

function clearturtle(nr) {
  turtle[nr].cs();
}

References

The code for expander and plotter is an adaption of the code from http://www.intertwingly.net/blog/2006/07/06/Penrose-Tiling from Sam Ruby.