Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

L-System Explorer: another experiment with procedural plants and gsub

edited October 2017 in Code Sharing Posts: 489

(Updated) The inspiration for the code below is the book identified below and the Wikipedia articles on simulated growth of plants and L-systems that cite it as a source. An example of its output is below:
image

--
-- L-System Explorer
--
-- With acknowledgements to "The Algorithmic Beauty of Plants" by
-- Przemyslaw Prusinkiewicz and Aristid Lindenmayer
-- http://algorithmicbotany.org/papers/

supportedOrientations(LANDSCAPE_ANY)
function setup()
    -- Set up L-System
    l = L("X", {X = "F-[[X]+X]+F[+FX]-X", F = "FF"}, 5, 22.5)
    -- Other L-Systems:
    -- l = L("F", {F = "FF-[-F+F+F]+[+F-F-F]"}, 5, 22.5)
    -- l = L("X", {X = "F-[[X]+X]+F[+FX]-X", F = "FF"}, 5, 22.5)
    -- l = L("X", {X = "F[+X][-X]FX", F = "FF"}, 5, 25.7)
    -- l = L("X", {X = "F[+X]F[-X]+X", F = "FF"}, 5, 20)
    l.color = color(50, 140, 28)

    sTime = ElapsedTime
    step = 1
    count = 1
    maxCount = 7

    bm = mesh()
    bm.vertices = {vec2(1, 1), vec2(WIDTH, 1), vec2(1, HEIGHT),
    vec2(1, HEIGHT), vec2(WIDTH, 1), vec2(WIDTH, HEIGHT)}
    local c1 = color(199, 200, 159)
    local c2 = color(203, 214, 89)
    bm.colors = {c2, c2, c1, c1, c2, c1}
    textMode(CORNER)
    font("Inconsolata")
end

function draw()
    if ElapsedTime - sTime > step and count < maxCount then
        l:grow()
        sTime = ElapsedTime
        count = count + 1
    end
    background(0)
    bm:draw()
    fill(0)
    local h = HEIGHT - 30
    for k, v in pairs(l.rules) do
        local r = k.." -> "..v
        text(r, 10, h)
        h = h - 30
    end

    translate(WIDTH/2, 0)
    l:draw()
end

L = class()

function L:init(root, rules, length, angle)
    self.state = root
    self.rules = rules
    self.length = length
    self.angle = angle
    self.color = color(255)
    local pattern = "(["
    for k, v in pairs(rules) do
        pattern = pattern..k
    end
    self.pattern = pattern.."])"
end

function L:draw()
    local stack = {}
    pushMatrix()
    pushStyle()
    stroke(self.color)
    strokeWidth(1)
    noSmooth()
    local tx, ty, ta = 0, 0, 90
    local l = self.length
    local a = self.angle
    for i = 1, #self.state do
        local ntx, nty, nta
        local c =self.state:sub(i, i)
        if c == "F" then
            nta = ta
            local nar = math.rad(nta)
            ntx = tx + l * math.cos(nar)
            nty = ty + l * math.sin(nar)
            line(tx, ty, ntx, nty)
        elseif c == "-" then
            nta = (ta - a) % 360
            ntx, nty = tx, ty
        elseif c == "+" then
            nta = (ta + a) % 360
            ntx, nty = tx, ty
        elseif c == "[" then
            stack[#stack + 1] = {tx, ty, ta}
            ntx, nty, nta = tx, ty, ta
        elseif c == "]" then
            ntx, nty, nta = unpack(stack[#stack])
            table.remove(stack)
        else
            ntx, nty, nta = tx, ty, ta
        end            
        tx, ty, ta = ntx, nty, nta
    end
    popStyle()
    popMatrix()
end

function L:grow()
    local function f(...)
        return self.rules[arg[1]]
    end
    self.state = self.state:gsub(self.pattern, f)
end

Elsewhere on the Codea Forum, @Herwig and @Bri_G have also posted L-system based code, here and here. This code is shorter, because it makes use of Lua's powerful string.gsub() library function.

The rules of the L-system are represented by a Lua table (referred to in the Codea class L by the by the field rules). For example, the two rules:

X -> F-[[X]+X]+F[+FX]-X
F -> FF

are represented by the table constructed as:

{
    X = "F-[[X]+X]+F[+FX]-X",
    F = "FF"
}
Tagged:

Comments

  • Posts: 563

    You are a code generating machine!

  • edited October 2012 Posts: 489

    Thank you @Reefwing - I'll take that as a compliment. I have updated my original post to include further references and explanations.

    If anybody should follow the experiments that I post to this forum, they will see that they are only snippets. My current interest is to explore what short but, hopefully, intelligible code can produce.

  • Posts: 666

    So, I'd like to take this code and have it generate a mesh object...should be simple to do that...it's leaves that I don't know (yet) how to generate. I think the Bloom project will help with that...

  • Posts: 563

    It was a compliment @mpilgrem - I'm amazed at how much code you are able to produce on a variety of subjects.

  • Posts: 2,161

    @mpilgrem I'm getting curious as to your background. There's quite a lot of mathematics behind some of these things you're doing.

Sign In or Register to comment.