For a fledgling project idea, I’ve recently needed to work out how to draw plants procedurally, and of course Python is my language of choice for some rapid prototyping. Whilst some richly-featured professional applications exist for generating flora in a procedural fashion for high-end rendering, there are precious few systems available for the kind of bulk task that I require.
At first the task of generating plants might seem like a massive endeavour. The various permutations of stem widths, lengths, branch frequency, colour variation, leaf size, shape, frequency and mind-boggling. And that’s not even considering the problem space represented by flowers.
Fortunately, the problem of representing self-similar biological development is one that attracted Aristid Lindenmayer, who in 1968 introduced L-Systems:
… as a theoretical framework for studying the development of simple multicellular organisms, and subsequently applied to investigate higher plants and plant organs. After the incorporation of geometric features, plant models expressed using L-systems became detailed enough to allow the use of computer graphics for realistic visualization of plant structures and developmental processes.
(Lindenmayer’s book The Algorithmic Beauty of Plants is no longer in print, but is available for free in PDF.)
L-Systems are remarkably powerful, simple systems that express the development of a formal grammar through a parallel rewriting process. In effect, you start with a string that represents certain graphical operations, and a set of rules for rewriting the string. You iterate over the string a certain number of times, and are left with a final product.
For example in a 2D system, the symbol F represents drawing a straight line in a forward direction, the symbol + represents rotating left, and – represents rotating right. If you start with the string “F”, and a rule that says “(F → F+F−F−F+F)”, then you’d see the following iterations:
- F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F+ F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F- F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F- F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F+ F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F
If you then plot those rules using a unit vector length and an angle of 90 degrees, you end up with the following iterations:
There are several more symbols that can be applied to the graphical operations, including pushing the current position and orientation onto a stack and popping it off again, rotations in 3D, and operations to define closed polygons and moving through colour and size lookup tables.
The most basic type of L-System is the deterministic context-less system, D0L, where each operation is independent and will always produce the same output. The Koch Square above is one of the most simplistic examples, but with a couple of variations much more complex patterns arise:
- Start: “X”
- Rule 1: “(X → F-[[X]+X]+F[+FX]-X)”
- Rule 2: “(F → FF)”
- Angle: 25 degrees
- Iterations: 5
In Part 2 we’ll look at a first approach to implementing L-Systems in Python, and a rudimentary renderer for 2D systems using PyCairo.