[Edu-sig] Re: Implementing an Lsystem (edu-sig Python project)

Kirby Urner pdx4d@teleport.com
Thu, 06 Jul 2000 17:06:24 -0700


Note:  This is part 2.  Part 1 is at:
http://www.python.org/pipermail/edu-sig/2000-July/000545.html
============

In the shoptalk of Lsystems, you start with axioms and rules of 
production.  An axiom is a string like:

 >>> axiom = 'F--F--F'

and your rules of production define substitions, such as:

 >>> rules = {}
 >>> rules['F'] = 'F+F--F+F'

To apply the rules to an axiom is to scan a string, and 
substitute wherever appropriate, e.g. every occurance of 'F' in 
the above axiom would be replaced by 'F+F--F+F'.[1]  

Since the '-' symbol is not associated with a substition rule, 
it would simply pass through as is:

 >>> def produce(axiom,rules):
	output = ""
	for i in axiom:
	    output = output + rules.get(i,i)
	return output

Notice that the dictionary.get() method takes 2 arguments, the 
2nd being what to return if the 1st is not a key.  For example, 
if i = 'F', then the rule for 'F' will be invoked, but if i = 
'-', then '-' will simply pass through to the growing output 
string.

 >>> produce(axiom,rules)
 'F+F--F+F--F+F--F+F--F+F--F+F'
 >>> newaxiom = produce(axiom,rules)
 >>> produce(newaxiom,rules)
 'F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--
  F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F'

Another example:

 >>> rules = {}
 >>> rules['A'] = 'B'
 >>> rules['B'] = 'AB'
 >>> axiom = 'A'

This sets up the example used at:
http://www.csu.edu.au/complex_systems/tutorial2.html

We'll define iterate as a recursive function:

 >>> def iterate(n,axiom,rules):
	print axiom
	if n>0:
	   axiom = produce(axiom,rules)
	   return iterate(n-1,axiom,rules)

	
 >>> iterate(7,axiom,rules)
 A
 B
 AB
 BAB
 ABBAB
 BABABBAB
 ABBABBABABBAB
 BABABBABABBABBABABBAB

Basically, our Lparser class needs to read in a file consisting 
of an axiom and some rules, plus other parameters such as how 
many times to recursively apply the rules, what the default 
angle of rotation is and so on.

Let's look at a real example of an .ls file, included with the
downloadable DOS version of Lparser at 

      http://www.xs4all.nl/~ljlapre/lparser.htm

#===================================================
#  Crystals.ls         (c) C.J. van der Mark      
#
#      Questions about Lparser files to:          
#        Internet  cvdmark@xs4all.nl              
#           Fido      2:283/203.11                
#           PCG       9:526/464.3                 
#===================================================
15
20
20
I
I=+(40)ffHccI
H=[+fffG]c[-fffG]c[^fffG]c[&fffG]G
G=[dS]e[d]e[d]e[d]e[d]e[d]e[d]e[d]
e=+(90)f-(90)>(-45)
d={[f+(90)f+(90)f+(90)f>(+38)-(105)ff-(151)ff][f&(38)+(15)ff+(151)ff]}
@

Rules are defined by equal signs.  The axiom is given by a 
letter alone, after some numbers, in this case I.  As per 
http://www.xs4all.nl/~cvdmark/tutor.html, the first 3 numbers 
represent:

15    # recursion depth 
20    # angle 
20    # thickness as % of length 

In Python:

 >>> rules = {}
 >>> rules['I']='+(40)ffHccI'
 >>> rules['H']='[+fffG]c[-fffG]c[^fffG]c[&fffG]G'
 >>> rules['G']='[dS]e[d]e[d]e[d]e[d]e[d]e[d]e[d]'
 >>> rules['e']='+(90)f-(90)>(-45)'
 >>>
rules['d']='{[f+(90)f+(90)f+(90)f>(+38)-(105)ff-(151)ff][f&(38)+(15)ff+(151)
ff]}'
 >>> axiom = 'I'
 >>> iterate(2,axiom,rules)
 I
 +(40)ffHccI
 +(40)ff[+fffG]c[-fffG]c[^fffG]c[&fffG]Gcc+(40)ffHccI

And that's only 2 iterations.  After 15, we'd have a very long 
string of commands to feed to our Lturtle.

Let's use the DOS lparser.exe to generate a Povray file 
corresponding to Crystals.ls:

lparser -vc -g Crystals

Running in a DOS box, I get the following output in response
to the above input:

L-System Parser/Mutator v4.0
---------------------------------------------------------
Copyright (C)  : RenderStar Technology BV. 1992-1995
Release date   : Dec 27 1995 (386+/DOS)
---------------------------------------------------------
Sizing memory
L-system file  : .\crystals.ls
Recursion depth: 15
Basic angle    : 20
Thickness      : 20
Axiom          : I
Rule           : I=+(40)ffHccI
Rule           : H=[+fffG]c[-fffG]c[^fffG]c[&fffG]G
Rule           : G=[dS]e[d]e[d]e[d]e[d]e[d]e[d]e[d]
Rule           : e=+(90)f-(90)>(-45)
Rule           :
d={[f+(90)f+(90)f+(90)f>(+38)-(105)ff-(151)ff][f&(38)+(15)ff+(1
51)ff]}
Size of string : 41480 chars
Pov file       : output.inc
Objects        : 5761
End

Then the instructions tell me:

  The file 'setup1.pov' can be used to connect to the output.inc file 
  created with lparser -vc. The first 8 colors in the pov rendering 
  will then match the ones in the viewer.

But I didn't get a very good rendering after all that.  Had to 
tweak it quite a bit (monkey around with lighting and camera
angle).  Here's the result:

   http://www.inetarena.com/~pdx4d/ocn/graphics/lsystems1.gif

Kirby


ERRATUM:

In my previous post I wrote:

> I was exploring in ActiveWorlds Education Universe today
> (http://edu.activeworlds.com/top.html), and went again to 
> Bonnie DeVarco's Virtual High School (VHS), a fave location 
> in TheU, one of 133 worlds in Education Universe.

The URL should have just been: http://edu.activeworlds.com/

Notes:

[1]  This example from Tim Wegner, 'Image Lab' (The Waite Group 
     Press, 1992), pg. 256