# L-System Tutorial

Starting with version **14.04.14**, **Lazy Nezumi Pro** allows you to draw complex shapes and fractals using the **Scripting** engine's **L-System** functions.

This tutorial will teach you how to use these functions step by step.

Reference tables of all functions and instruction symbols can be found at the bottom of this page.

## Definition

An **L-System** is defined by:

- A set of
**symbols**called the**alphabet**. - A string of these symbols called
**axiom**that defines the initial state of the system. - A set of
**rules**that describe how these symbols should be transformed each time the system is iterated.

The system will be iterated a number of times, with symbols being changed according to the rules. This will produce a final string of symbols, which will be read as instructions to move the pen in order to draw a shape.

## Example 1 - Koch Curve

Let's start by looking at a famous **L-System**: The Koch Curve.

**Alphabet**: F, +, -**Axiom**: F**Rules**: F = F-F+F+F-F

If we start with the **Axiom** and use the given rule to replace **F**, the system evolves like so:

**After 1 iteration**:

F-F+F+F-F**After 2 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**After 3 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

How is this used to draw something? We read the final string from left to right. Each time we encounter the **F** symbol, we draw a straight line. If we encounter a **-** or **+** symbol, we turn left or right 90 degrees. The following image shows the results.

## L-System Scripting Programs

So how do we use this in **Lazy Nezumi Pro**? Start off by making a new preset. In its details, enable **Scripting**. Select the **custom** mode, and paste this code into the text box:

lsysRules("F=F-F+F+F-F");

lsysDrawSymbols("F");

lsysAngle(90);

lsysLength(length);

lsysIterations(iterations);

lsysAdvance();

Then go ahead and click **Compile**. Since this program has two user variables, two parameter sliders should appear: **length** and **iterations**. Click on their "..." buttons to set their range to something more useful than [0-1].

**Length** (set with the **lsysLength** function) is the distance the pen travels each time the system encounters a **Draw Symbol** (in this case **F**, as set with the **lsysDrawSymbols** function). A value around 10 should be a good start.

**Iterations** (set with the **lsysIterations** function) is the number of iterations that should be performed on the system after compiling the program. Be careful with this one: if you have highly recursive rules, setting a high number of iterations will take a long time to compute the final system string (and the application might become unresponsive for a little while). Usually you won't need to go above 10 iterations, so set a range between 0 and 10.

All of the **L-System** functions except **lsysAdvance** are only used when the program is being compiled. When you are drawing, **lsysAdvance** steps through the final **L-System** string until it finds a **Draw Symbol**, at which point it moves the current pen position and returns. This position is stored in the **ox** and **oy** variables.

If you open the **Scripting Graph** window, you can see a preview of the resulting **L-System** as you change the parameters. Drawing an **L-System** in your art app may take some time, so it's a good idea to look at the preview first to get a general idea of what you will get.

## Example 2 - Trees

**L-Systems** are really good at modeling trees and other plants. Let's start with this example:

lsysRules("B=A[-B][+B]");

lsysDrawSymbols("AB");

lsysAngle(20);

lsysLength(length);

lsysDir(0, -1);

lsysIterations(iterations);

lsysAdvance();

Here we introduce two new symbols: [ and ]. When an open bracket is encountered, the state of the system is saved (or pushed) onto a stack. When a closing bracket is encountered, the state is restored by popping the top element from the stack. The system state is composed of the following:

**Pen Position****Direction****Line Length****Line Thickness****Rotation Angle**

This allows us to easily create branches. In this example, we start off with a branch, which sprouts two new branches after each iteration. Here's what this system looks like after 4 iterations:

But real tree branches usually get smaller and smaller. How can we simulate this with our **L-System**? Here's one way:

Adding the **A=AA** rule will cause each branch to double in size for each iteration of the system. Here's what this looks like after 4 iterations:

But what if we want the branches to grow at a slower rate than doubling at each iteration? You have two more options: the **%** symbol which will divide the length by the **Length Scale Factor** (which is set to 1.3 by default), and the **&** symbol, which will decrease the length by the **Length Increase Factor** (which is set to 0.1 by default). You can change these values by calling the **lsysLengthScale** and **lsysLengthInc** functions.

Here's an example rule that applies the scale factor to the left branches, and the increase factor to the right branches, so you can see the difference it makes:

Now let's make this tree look a bit more natural, by adding a central branch and decreasing the thickness as we branch out. For this we use the **!** symbol:

Here's what it looks like after 6 iterations. This is starting to look a lot better! For this to work correctly, don't forget to bind the pen's pressure to line thickness in your art app's brush settings.

If you draw this, you'll notice it takes longer, since there are now 3 branches splitting off of every branch. We can make the tree look more natural and reduce some of this drawing time by randomly skipping some branches. We do this with the **?** symbol. When this symbol is encountered, the instruction (or branch) after it is skipped with a certain probability. A random number between 0 and 10 is drawn, and if it is higher than the current **Skip Number**, then we skip the instruction. We set the **Skip Number** by simply writing a number somewhere in our rule string, before the **?** symbol. Here's an example:

What we are doing here is giving the left branch 7 chances in 10 to be drawn, and the right branch 8 chances in 10. Now that we've introduced some randomness in our **L-System**, every tree we draw will be slightly different! Here's an example of what we can get with this rule after 6 iterations:

Removing perfect symmetry makes things look a lot more natural. Let's add even more randomness! We can have the system add some random values to the angle and length when rotating and drawing by using the following functions:

lsysLengthRandom(lengthRandom);

This will make two new sliders appear. Set the range for angleRandom to [0-45] (since it is an angle), and you can leave the range of lengthRandom to [0-1] (since it's a percentage of the current length). Small values will go a long way to make realistic looking trees. If you set these too high though, you will get some pretty crazy results which might not look like trees at all anymore.

Here are some examples of what you can get after 6 iterations, with angleRandom set to around 5, and lengthRandom to 0.15. I've also set the **Length Scale Factor** to 1.6, to simulate leaves at the end of branches.

## Further Exploration

I hope this tutorial has sparked your interest and that you will start exploring **L-Systems** on your own! If you look under the **L-System** category in the **Scripting Mode**, you will find some examples to get you started. Feel free to copy/paste the code into your own **Custom** mode programs to tweak them and create new patterns!

You will also find a wealth of information and examples on the internet by simply doing a Google search. There is no standard way of defining **L-System** instruction symbols, so you may have to do some minor translations to get them working correctly in **Lazy Nezumi Pro**.

## Scripting Functions

Here is a table of all the available **L-System** related functions that you can use in a **Scripting** program.

Function |
Description |

lsysAxiom(string) |
Set the Axiom (starting state) of the system. |

lsysRules(string) |
Set the Rules of the system, in the following format: [symbol]=[symbols],[symbol]=[symbols],... |

lsysIterations(number) |
Set the number of times the system should be iterated before producing the final instruction string. |

lsysDrawSymbols(string) |
Set the symbols (one after the other, without spaces or commas) that will cause the pen to move when encountered in the final instruction string. Other symbols will only be used to control the evolution of the system as it is iterated. |

lsysDir(x, y) |
Set the pen's starting Direction vector. Default is (1, 0). |

lsysAngle(angle) |
Set the starting Angle (in degrees) that will be used when processing a rotate (+ or -) instruction. Default is 90. |

lsysAngleRandom(angle) |
Set the maximum angle (in degrees) that can be randomly added to the current Angle when processing a rotate instruction. Default is 0. |

lsysAngleScale(factor) |
Set the Angle Scale Factor. Default is 1.2. |

lsysAngleInc(inc) |
Set the Angle Increase Factor. Default is 5. |

lsysThickness(thick) |
Set the starting line Thickness, between 0.0 and 1.0. Default is 1.0. |

lsysThicknessRandom(factor) |
Set the percentage of current Thickness that can be randomly added when moving the pen position. Default is 0. |

lsysThicknessScale(factor) |
Set the Thickness Scale Factor. Default is 2.0. |

lsysThicknessInc(inc) |
Set the Thickness Increase Factor. Default is 0.1. |

lsysLength(len) |
Set the starting line Length. Default is 1.0. |

lsysLengthRandom(factor) |
Set the percentage of current Length that can be randomly added when moving the pen position. Default is 0. |

lsysLengthScale(factor) |
Set the Length Scale Factor. Default is 1.3. |

lsysLengthInc(inc) |
Set the Length Increase Factor. Default is 0.1. |

lsysLoop(loop) |
If loop is 1, then lsysAdvance will wrap around to the start of the system's instruction string upon reaching the end. Otherwise, the pen position will no longer be updated. Default is 0. |

lsysAdvance() |
Step through the system's instruction string until finding a Draw Symbol, at which point the pen's position is moved by the current Length in the current Direction. The new position is stored in the ox, oy variables, and the current thickness is stored in the op variable. |

## Symbol Instructions

The following table describes the function of each **Symbol** you can use when defining your **L-System Axiom and Rules**.

Symbol |
Instruction |

Any Draw Symbol |
Move the pen position by Length amount in the current Direction. |

0-9 |
Sets the current Skip Number (used with the ? symbol). |

? |
Random Skip: Draw a random number between 0 and 10. If it is higher than the current Skip Number, then skip the next instruction. |

: |
Skip the next instruction. You can use this to write statements like 5?A:B, where either A or B will be executed. |

( ) |
Open and close an Instruction Group. This lets you skip an entire group of instructions by writing something like 5?(AB):(CD). |

+ |
Rotate the current Direction left by the set Angle amount, plus a random amount of which the maximum is set by lsysAngleRandom. |

- |
Rotate the current Direction right by the set Angle amount, plus a random amount of which the maximum is set by lsysAngleRandom. |

| |
Reverse direction (rotate 180 degrees). |

. |
Exchange meaning of + and -. |

! |
Divide Thickness by Thickness Scale Factor. |

@ |
Multiply Thickness by Thickness Scale Factor. |

# |
Decrease Thickness by Thickness Increase Factor. |

$ |
Increase Thickness by Thickness Increase Factor. |

% |
Divide Length by Length Scale Factor. |

^ |
Multiply Length by Length Scale Factor. |

& |
Decrease Length by Length Increase Factor times Start Length. |

* |
Increase Length by Length Increase Factor times Start Length. |

{ |
Divide Angle by Angle Scale Factor. |

} |
Multiply Angle by Angle Scale Factor. |

< |
Decrease Angle by Angle Increase Factor. |

> |
Increase Angle by Angle Increase Factor. |

[ |
Save the state and start a new Branch. |

] |
End the current Branch and restore the state. |