www.johngrindall.com

.

Maths/ L systems


L systems are a formal grammar (whatever one of those is) invented by Lindenmayer to study the structure of plant growth. Loosely speaking an L system is specified by a re-writing rule, which gives a string of letters to replace a given letter by. Starting with a single letter F (meaning one step forwards) and replacing it by the string gives a new longer string of letters, which encodes the shape of Plant 1 (1st generation). Feeding this string back and doing the replacement on that gives a more complicated longer string, encoding the information for Plant 2.

Repeating this procedure can give a realistic looking fractal plant structure, although my flash program cannot cope with more than 3 iterations except for simple replacement strings.

Information about what the letters stand for still needs to be done.


Enter your replacement string in the box provided, choose the number of iterations and the angle of bend of the branches. Then click 'draw'and rotate the plant with the mouse.

Or just check out the presets.








Explanation and code

The plant is drawn using a list of points in 3D. The list is generated by the string you enter in the box, iterated as described above, using this code:


1. function getstring():Void { 2. var i:Number; 3. for (i=1; i<=iter; i++) { 4. s = replaces(s, "F", replace); 5. } 6. } 7. function replaces(orig:String, a:String, b:String):String { 8. return (orig.split(a).join(b)); 9. }



The output of this code will be a great big long string, for example:

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]]]


Given the final string we need to translate it into the list of points used to draw the plant.

The position of the drawer at each time is specified by x, y and z coordinates and the direction in which it is facing. The direction is encoded in three vectors called 'h', 'l' and 'u'. These three vectors correspond to the 'heading' of the drawer, the direction called 'left' and the direction called 'up'. These form an orthogonal basis of unit vectors at all time.

It is best to imagine that the plant is drawn by a little turtle, in which these three vectors are as shown:



The 'F' symbol means go forward in the direction of 'h', the heading.

The other vectors are used to change the direction of the turtle, and since the best way to store three vectors is in a matrix, we use matrices to adjust these directions.


'+' and '-' rotate the turtle about the 'u' vector by your chosen angle (ie. the turtle turns left or right)

Now the clever bit - rotating the turtle left (anticlockwise looking down 'u') by an angle 'a' degrees is the same as rotating the vectors 'h' and 'l' the other way (clockwise). That is, rather than rotating the turtle itself, we move the vectors 'h' and 'l' the other way to simulate the turtle moving.

The easiest way to store vectors in Flash is as rows, not columns in a matrix, so we store 'h', 'l' and 'u' like this:


hxhyhz
lxlylz
uxuyuz

Now, using row vectors, the matrix for rotating the standard basis vectors by angle 'a' about the z-axis is:


   
( vxvyvz )
   
   
( vxvyvz )
   
cos(a)sin(a)0
-sin(a)cos(a)0
001



So the matrix for rotating 'h' and 'l' by angle '-a' (that's 'a' backwards as explained) about axis 'u' is obtained by first transforming h, l, u into the standard basis, then rotating about the z-axis, and finally transforming back:


   
( vxvyvz )
   
   
( vxvyvz )
   
hxhyhz -1
lxlylz 
uxuyuz 
cos(a)-sin(a)0
sin(a)cos(a)0
001
hxhyhz
lxlylz
uxuyuz


So the new h, l, u matrix is given by the rows of the matrix:



hxhyhz
lxlylz
uxuyuz
hxhyhz
lxlylz
uxuyuz
hxhyhz -1
lxlylz
uxuyuz
cos(a)-sin(a)0
sin(a)cos(a)0
001
hxhyhz
lxlylz
uxuyuz

=
cos(a)-sin(a)0
sin(a)cos(a)0
001
hxhyhz
lxlylz
uxuyuz


It's important to see that this matrix acts on h, l, u rather than the x,y,z position of the turtle. Throughout, we act on these vectors with negative rotations which simulate changing the direction of the turtle.



& and ^ rotate the turtle about the 'l' vector by your chosen angle (ie. the turtle pitches up and down like an aircraft would when changing altitude).

The matrix for this is:


hxhyhz
lxlylz
uxuyuz
cos(a)0-sin(a)
010
sin(a)0cos(a)
hxhyhz
lxlylz
uxuyuz


< and > roll the turtle around on an axis through its body - about the 'h' vector (ie. like an aircraft doing a barrel roll or a canoe turning over in the water).

The matrix for this is:


hxhyhz
lxlylz
uxuyuz
100
0cos(a)-sin(a)
0sin(a)cos(a)
hxhyhz
lxlylz
uxuyuz




Finally, '|' means turn around - the turtle faces backwards without turning upside down. This is the same as rotating around the vector h by 180 degrees.



So, given the string of symbols we keep track of the position of the turtle and the h, l, u vectors.

Going through the string one by one we update the position of the turtle and h, l, u. When we reach an 'F' symbol we move the turtle forward along vector 'h'. When we reach a '[' symbol we put the current position and directions in a stack, like a calculator memory. If we reach a ']' symbol we extract the most recent data from the memory (called 'popping') and start from there again. The memory is what allows us to make plants that branch - we can draw one branch and then pop and then draw another branch from the same point.

Along with each point I associate a depth - lower down in the plant I draw thicker brown lines and higher up thin green lines. When the memory is accessed the depth is re-loaded too.




Copyright John Grindall