Stochastic L-system Plant

Stochastic L-systems add probability distributions to the production rules in order to model the variations which would occur between individual specimens of a given plant.

This L-system is based on chapter 1.7 "Stochastic L-systems" of the book "The Algorithmic Beauty of Plants" by Przemyslaw Prusinkiewicz & Aristid Lindenmayer
algorithmicbotany.org/

This turtle is forked from "Fractal plant #1" by reinder
Fractal plant #1

#lsystem

Log in to post a comment.

// --------------------------------------------------
// CREDITS
// --------------------------------------------------
// Forked from "Fractal plant #1" by reinder
// https://turtletoy.net/turtle/b750bb0220
//
// Based on chapter 1.7 "Stochastic L-systems"
// of the book "The Algorithmic Beauty of Plants"
// by Przemyslaw Prusinkiewicz & Aristid Lindenmayer
//
// http://algorithmicbotany.org/
// --------------------------------------------------

// Setup
Canvas.setpenopacity(.5);

// Put the turtle in the bottom left corner pointed toward the top right corner
const turtle = new Turtle(-100,100);
turtle.left(45);

// The number of times to evaluate the production rules before drawing the result
const recursion = 5; // min=1, max=10, step=1

// The number of degrees in a left or right turn when drawing
const angle = 22; // min=0, max=90, step=1

// The distance to travel forward or back when drawing
const distance = 2; // min=1, max=10, step=0.25

// The starting string for the l-system
const axiom = "F";

// The rules and probabilities for transforming symbols in the L-system
// For a given production rule, all probability values should sum to 1.0
const productions = {
    "F": [
        {
            probability: 0.20,
            to: "F[+F]F[-F]F"
        },
        {
            probability: 0.40,
            to: "FF-[-F+F+O]+[+F-F-F]"
        },
        {
            probability: 0.40,
            to: "FF+[+F-F-F]-[-F+F+O]"
        }
    ]
}

// l-system
function createLSystem(numIters, axiom) {
    let s = axiom;
    for (let i=0; i<numIters; i++) {
        s = processString(s);
    }
    return s;
}

function processString(oldStr) {
    let newstr = "";
    for (let i=0; i<oldStr.length; i++) {
        newstr += applyRules(oldStr[i]);
    }
    return newstr;
}

function applyRules(ch) {
    let r = Math.random();
    let p = 0;
    let rules = productions[ch];
    
    // If there are no replacement productions, leave the character as-is.
    if (!rules) {
        return ch;
    }
    
    // Choose the production rule with the appropriate probability
    for (let i=0; i<rules.length; i++) {
        p += rules[i].probability;

        if (r < p) {
            return rules[i].to;
        }
    }
    
    // If something is amiss with the probabilities, fall back to the last rule listed
    return rules[rules.length - 1].to;
}

// Calculate the the final string to render.
const inst = createLSystem(recursion, axiom);
const states = [];

// The walk function will be called until it returns false.
function walk(i) {
    const cmd = inst[i];
    
    switch (cmd) {
        case "F":   turtle.forward(distance);
                    break;
        case "B":   turtle.backward(distance);
                    break;
        case "+":   turtle.right(angle);
                    break;
        case "-":   turtle.left(angle);
                    break;
        case "O":   turtle.circle(distance / 2);
                    break;
        case "[":   states.push({
                        x: turtle.xcor(),
                        y: turtle.ycor(),
                        h: turtle.heading()
                    });
                    break;
        case "]":   const state = states.pop();
                    turtle.penup();
                    turtle.goto(state.x, state.y);
                    turtle.setheading(state.h);
                    turtle.pendown();
                    break;
        default:
    }
      
    return i < inst.length - 1;
}