(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:
--
-- 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"
}