Lindenmayer-System (L-System)

seen from Netherlands
seen from Netherlands
seen from Norway

seen from Italy

seen from Australia
seen from China
seen from China
seen from Singapore

seen from United Kingdom
seen from Yemen

seen from United States
seen from Russia

seen from United States
seen from Thailand

seen from Germany
seen from United Kingdom
seen from China

seen from Russia
seen from United States

seen from United States
Lindenmayer-System (L-System)
Heya, I showed those color filling gifs to my dad and he was wondering what your algorithm for which color goes next was? (How does it decide to go pink instead of going purple etc.)
The original algorithm was really janky and consisted of incrementing different modes, where each mode was hardcoded to either increase or decrease the RGB values by one until the RGB value matched the target colour. Once the target was reached the next mode would be set.
The algorithm I'm currently using randomly chooses from a list of colours and then only increments one RGB value per iteration for a more gradual colour transition.
The tool I'm using is gifski, which works on the idea that gifs can reuse colours from previous frames (so long as they don't change position) to achieve any number of colours per frame.
Code snippets and gifs under the cut!
L-Systems (part 1)
In this series of blog posts I will describe the theory and implementation (in Clojure, C# and Scala) of Lindenmayer systems. I will start out by explaining the basics about L-Systems.
What are L-Systems?
A Lindenmayer system (or L-System) is a formal system that was invented by the Hungarian biologist Aristid Lindenmayer. He used it to formally describe the growth of plants. Nowadays, it is used for drawing pretty fractals (like the Koch snowflake, the Dragon curve and others) and generating trees and plants for computer graphics. The ultimate resource on L-Systems and their many different versions is the book The Algorithmic Beauty of Plants by Lindenmayer and Prusinkiewicz. It's a very good book, however it might be a little daunting to jump into as a newcomer.
An L-Sytem builds up a string of characters by a set of rules, starting with an axiom. Those characters will later be drawn to the screen by iterating over them and executing some action for each character in the string, such as drawing 5 pixels forward or rotating by 90 degrees. Formally, an L-System consists of a set of rules, an axiom (a string to start out with) and an alphabet of characters.
Application of rules
Rules can look something like this:
X → X+YF+ Y → -FX-Y
That means, if we encounter an X in our current state string, we replace it by the right hand side of the matching rule (X+YF+). For example, starting out with the axiom FX and the rules described above:
FX ↑
We look through the rules but find no matching character on the left hand sides of all the rules. That means it is left as it is.
Current state: F
FX ↑
Excellent, there is a matching rule! That means we replace the X in our current state by the right hand side of the matching rule. With that, our state string becomes:
FX+YF+
This completes one iteration of applying the rules to the state. One more iteration:
FX+YF+ ↑
Current state: F
FX+YF+ ↑
Current state: FX+YF+
FX+YF+ ↑
Current state: FX+YF++
FX+YF+ ↑
Current state: FX+YF++-FX-Y
FX+YF+ ↑
Current state: FX+YF++-FX-YF
FX+YF+ ↑
Current state: FX+YF++-FX-YF+
So, what we've been doing was the following, in imperative pseudo-code:
# State is a string, rules is a map from characters to strings # Does one iteration of the rules on the state string. function stepOnce(state, rules): newState = "" for c in state: if rules.contains(c): newState += rules[c] else: newState += c return newState # Given an axiom, a map of rules # and a number of desired iterations, # produces a state string. function stepN(axiom, rules, numIterations): state = axiom for i in (0 until numIterations): state = stepOnce(state, rules) return state
I realize this might be a little (very) dry, but those character strings have a meaning as well. In fact, the character string we just generated, will later on be used to draw a Dragon curve, which looks like this:
How to draw the L-System
Now that we have our state string, we need to get to drawing the turtle on screen. For this, we need Turtle graphics. A turtle is basically a cursor that can move around in the 2D plane and draw lines on that plane. Our version of turtle graphics has three attributes: A location (a pair of integers), an orientation or angle (a floating point number) and a stack, which saves the state of the turtle, so you can restore it later. The operations that a turtle can perform (that we need) are drawing forward a given amount of pixels, rotating by a given angle, saving its current state to a stack and restoring the state from the stack.
We can now look at the alphabet for the Dragon curve that we examined earlier and assign a turtle action to each symbol in the alphabet:
F: Draw forward +: Increase the turtle's angle by 90° -: Decrease the turtle's angle by 90° X, Y: Do nothing
Now, once we have our full state string, we can step through the string character by character and execute a turtle action based on each character. In pseudocode, it would look something like this:
function draw(state, turtle, distance, angle): for c in state: c match: # An F in the state string moves the turtle forward # while drawing a line. case 'F' => turtle.forward(distance) # A + sign increases the turtle's angle by an amount # that is specified in the L-System. case '+' => turtle.rotate(angle) case '-' => turtle.rotate(-angle) # Ignore all other characters. case _ => ()
The angle for the dragon curve is 90°, the distance can be chosen based on the size of the image and the number of iterations. For a L-System that also uses the stack operations, we can expand our pseudocode like the following:
function draw(state, turtle, distance, angle): for c in state: c match: case 'F' => turtle.forward(distance) case '+' => turtle.rotate(angle) case '-' => turtle.rotate(-angle) # An open square bracket signifies that we want # to save the current state of the turtle to the stack. case '[' => turtle.push() # A closed suqare bracket restores the turtle's state # from the stack. case ']' => turtle.pop() case _ => ()
In the next part, we will look at implementations of the turtle's functions and its state.
"Lost Within" 01/04/14
Attaining a balance one animation a day.
evooxy.com/everydays Facebook Twitter Instagram
3-D rendering of plants drawn based on the Lindenmayer System.
They are delicate, capricious and real.
Fun with space filling curves and the Lindenmayer system.
For my homework I have to write a program that draws a Hilbert curve and another space filling curve. I wrote the program such that it accepts a Lindenmayer system like grammar to make all sorts of different curves.
I played a bit around and this marvelous beauty came out.
L-system: axiom = F+F+F+F F --> FF+F++F+F angle = 90