Let’s hear it for Logo (3)

Logo is of course known for its turtle graphics, and such is the appeal that there are now turtle graphics libraries for lots of other systems, such as Python, Java, Racket, Ruby, lots of others. If your favorite language supports graphics, then somebody will have written a turtle graphics interpreter for it.

One of the more powerful uses of turtle graphics is for investigating Lindenmayer Systems, named for Aristid Lindenmayer, who developed them for modelling plant growth. (As an aside, note his first name: Aristid. At least once I’ve seen it misspelled “Astrid”.)

To start, we can draw a simple Y-shaped tree, with a trunk, and two branches at 45 degrees from the vertical, with these commands:

fd 100
rt 45
fd 100 bk 100
lt 90
fd 100 bk 100
rt 45
bk 100

which produces something like this:

Of course we would want to be able to change the size of the tree, so we could write the procedure

to tree :size
fd :size
rt 45
fd :size bk :size
lt 90
fd :size bk :size
rt 45
bk :size
end

And now with the command tree we can draw Y-shaped trees of any size. We have carefully designed our tree so that the turtle ends up back where we started. This means we can replace branches of the tree with smaller versions of itself:

to tree2 :size
fd :size
rt 45
tree :size/2
lt 90
tree :size/2
rt 45
bk :size
end

Then “cs tree2 100” produces this:

To replace all branches with smaller copies of the tree we can perform a recursion, stopping only when the branch size reaches a certain lower limit. Like this:

to tree3 :size
if :size < 2 [stop]
fd :size
rt 45
tree3 :size/2
lt 90
tree3 :size/2
rt 45
bk :size
end

If we now enter

cs
bk 150 tree3 200

(with the "bk 150" simply to give the tree room to grow in our graphics window), we obtain:

Now this looks like no tree found in nature. But we can easily manipulate it. All we require is for our basic, fundamental, tree, to be so designed that the turtle ends up at the start. Then we can recursively plot the branches with smaller copies of itself.

For example, here is a new basic tree:

to tree :size
fd :size
rt 30
fd :size/1.5 bk :size/1.5
lt 45
fd :size bk :size
rt 15
bk :size
end

so that "tree 100" produces this:

and a recursive version (which I'll now call "ltree"):

to ltree :size
if :size < 2 [stop]
fd :size
rt 30
ltree :size/2
lt 45
ltree :size/1.5
rt 15
bk :size
end

so that "cs bk 150 ltree 150" produces:

Already we are getting some vague semblance of a "natural" plant. Here's an example I pinched from the Ruby pages linked to above, rewritten in Logo, and with colors and widths taken out:

to ltree2 :size
if :size < 5 [stop] 
fd :size/3
lt 30 ltree2 :size*2/3 rt 30
fd :size/6
rt 25 ltree2 :size/2 lt 25
fd :size/3
rt 25 ltree2 :size/2 lt 25
bk :size*5/6
end

And here's the result of "cs bk 150 ltree2 250":

(I had to do this in the online Logo interpreter at http://www.calormen.com/jslogo/, as for some reason my ucblogo kept crashing with core dumps.) But it's remarkable that with a very simple procedure we can construct a picture which already looks more like a real plant than ever.

In fact, our plants aren't Lindenmayer systems themselves, but the output of such systems. Formally, a Lindenmayer System is a grammar, or set of rules, for creating recursively defined structures. Our initial plant, the highly unlife-like one, can be expressed in the L-systems language as

angle = 45
1 -> [1  1]
0 -> [1 [0] 0]

where 1 and 0 may be interpreted as drawing a line segment, and a line segment ending in a leaf, respectively. The brackets [ and ] may be interpreted as turning left and right (by 45 degrees) respectively.

This might seem a little obtuse, and an equivalent method is given by Chris Jennings who defines this tree as

angle = 45
axiom = FX
X ->  S[-FX]+FX

Here F and X mean drawing the trunk and branches respectively, and S means "draw everything smaller from now on". And the term "axiom" simply means the starting value. Here it's the + and - which refer to the turns, and the brackets indicate pushing and popping objects off a stack which ensure that we maintain the current position. This means that the last line here, which is this system's "rule" can be read as:

  • Make everything shorter, and
    1. draw a tree to the left
    2. draw a tree to the right

Using these symbols, another plant can be described (this is example 7 from https://en.wikipedia.org/wiki/L-system) as:

angle = 25
axiom = X
X -> F[−X][X]F[−X]+FX
F -> FF

In this example, the shortening is assumed. This can be turned into a Logo procedure as follows:

to ltree7 :size
if :size < 5 [stop]
fd :size
lt 25 ltree7 :size/2 rt 25
ltree7 :size/2
fd :size/2
lt 25 ltree7 :size/2 rt 25
rt 25
fd :size/2
ltree7 :size/2
bk :size/2
lt 25
bk :size/2
bk :size
end

and when invoked with

cs pu bk 250 ht pd ltree7 200 st

produces this noble plant:

Remarkable that such simple instruction sets can yield results of such beauty! It's quite possible to add colors and thicknesses to these plants to make them even more lifelike. But you get the idea.

Leave a Reply

Your email address will not be published. Required fields are marked *