Elm – fun with L-System (Part 2)

Series:

  1. Algae
  2. Pythago­ras Tree (this)
  3. Can­tor Dust
  4. Koch Curve
  5. Sier­pin­s­ki Tri­an­gle
  6. Drag­on Curve
  7. Frac­tal Plant

 

Last time out we imple­ment­ed the Algae exam­ple from the L-Sys­tem wikipedia page.

Frankly, it wasn’t very excit­ing at all, but still we need­ed to lay the ground work for stuff we’ll be look­ing at today. In this post (and the sub­se­quent posts in the series) we’ll make use of the Core mod­ule that we had estab­lished in Part 1.

 

Example 2 : Pythagoras Tree

Start­ing from this exam­ple, things get inter­est­ing as we need to draw things on the screen, yay!

First, we need to define our L-Sys­tem:

image

and a cou­ple of type alias­es:

image

Notice that we’re going to use a linked-list as the LIFO stack to record the posi­tion and angle. Because that’s how this par­tic­u­lar L-Sys­tem work:

image

Next, let’s add 2 helper func­tions for work­ing with the stack:

image

 

Now, before we get into the draw­ing part, let’s take a quick refresh­er on how the coor­di­nate sys­tem works in Elm (when you’re work­ing with a col­lage at least).

image

Here, (0, 0) is at the cen­tre of the col­lage. For every object, its posi­tion is also deter­mined by its cen­tre point.

This coor­di­nate sys­tem works great in some cas­es, but hav­ing been used to most oth­er coor­di­nate sys­tems (that places (0, 0) at the top-left cor­ner) this can take a while to get used to.

 

Next, let’s add anoth­er helper func­tion that takes the cur­rent posi­tion of the path, and work out the next posi­tion based on the rota­tion angle (in radi­ans) and the length of the new seg­ment.

image

image

Next, let’s add a cre­ate­Seg­ments func­tion that takes in:

  • the start­ing posi­tion (at the base of the tree);
  • the length of a line seg­ment not end­ing in a leaf, with the assump­tion that line seg­ments end­ing in a leaf is half as long;
  • the cur­rent state of the tree

and returns a list of line seg­ments.

image

The above code is a pret­ty lit­er­al trans­la­tion of the instruc­tions:

image

How­ev­er, for those of you com­ing from F#, you might notice that I used newRo­ta­tion’ when pop­ping from the stack, but then used newRo­ta­tion on the next line:

image

This is because shad­ow­ing is not allowed in Elm.

 

All that is left to do now, is to col­lect the line seg­ments and put them inside a col­lage that cov­ers the entire win­dow.

image

As I exper­i­ment­ed with a num­ber of length set­tings it became clear that the length real­ly needs to change along with the gen­er­a­tions.

I thought of two approach­es:

  1. use a sim­ple for­mu­la to cal­cu­late the length based on a base­line val­ue and the cur­rent gen­er­a­tion num­ber;
  2. use the same length through­out, then scale the whole tree back to fit into col­lage

In the end, I opt­ed for the first approach for sim­plic­i­ty and for this exam­ple it works suf­fi­cient­ly well.

 

Final­ly, to tie every­thing togeth­er:

image

 

Live Demo (here)

Use LEFT and RIGHT arrow keys to evolve/devolve the L-Sys­tem.

 

Source Code (here)

 

Next : Can­tor Dust

 

Links