Sunday, May 20, 2012

Playing with L-Systems in Kojo

You can use the idea of L-Systems to make some great drawings in Kojo.

So what are L-Systems?

The Wikipedia article on the subject has a good explanation. For the purpose of this post, let me define the important elements of an L-System; these are:
  • The alphabet of the system. Some of the letters of the alphabet have a turtle graphics interpretation.
  • The axiom of the system (a string made out of the letters of the alphabet). This is the starting point for the evolution of the L-System.
  • The production rules of the system. These specify how the system evolves.
  • The turning angle for the system - associated with the letter of the alphabet that is interpreted as a turn command.
  • The base length of the lines that are drawn.
  • the scaling factor that determines the size of some of the lines drawn in a particular generation.
Here's how an L-System can be converted into a drawing - you  start with the axiom string, and apply the production rules for a given number of generations. You then interpret the resulting string as a turtle graphics program.

In this post (and the accompanying code), the following alphabet letters have a  turtle graphics interpretation:

 F  Go forward by the base length
 f  Same as F (sometimes you need two different drawing letters)
 G  Go forward by the base length - with the pen up
 |  Go forward by the base length scaled down for the current generation
 [  Save position and heading
 ]  Restore position and heading
 +  Turn right
 -  Turn left

The following is a translation of these ideas into Kojo (Scala) code:

case class LSystem(axiom: String, angle: Double, len: Int = 100, sf: Double = 0.6)(rules: PartialFunction[Char, String]) {
    var currVal = axiom
    var currGen = 0
    def evolve() {
        currGen += 1
        currVal = currVal.map { c =>
            if (rules.isDefinedAt(c)) rules(c) else c
        }.mkString.replaceAll("""\|""" , currGen.toString)
    }
    
    def draw() {
        def isDigit(c: Char) = Character.isDigit(c)
        val genNum = new StringBuilder
        def maybeDrawBar() {
            if (genNum.size != 0) {
                val n = genNum.toString.toInt
                genNum.clear()
                forward(len * math.pow(sf, n))
            }
        }
        currVal.foreach { c => 
            if (!isDigit(c)) {
                maybeDrawBar()
            }
            
            c match {
                case 'F' => forward(len)
                case 'f' => forward(len)
                case 'G' => penUp(); forward(len); penDown()
                case '[' => savePosHe()
                case ']' => restorePosHe()
                case '+' => right(angle)
                case '-' => left(angle)
                case n if isDigit(n) => genNum.append(n)
                case _ => 
            }
        }
        maybeDrawBar()
    }
}

Here, we have a class called LSystem. To create an instance, you give the constructor function an axiom, an angle (for turning left/right), a base length (for moving forward), a scaling factor (for generation specific forward movements), and some production rules. You then evolve the L-System for as many generations as we want using the evolve command. Finally, you draw the L-System using the draw command.

This code has some restrictions:
  • You can't use numbers as the letters of an L-System alphabet.
  • The production rules need to be context free and deterministic.
  • You can't use the | letter as the left hand side of a production rule.

Let's try the code out. I'll begin with some of the samples on the Wikipedia L-Systems page.

Sierpinski triangle 

This is Example 6 on the Wikipedia page.

Kojo Code:

val sierp_wp6 = LSystem("F", 60, 2) {
    case 'F' => "f+F+f"
    case 'f' => "F-f-F"
} 

And the corresponding drawing:


Dragon Curve

This is Example 7 on the Wikipedia page.

Kojo Code:

val dragon_wp7 = LSystem("FX", 90, 10) {
    case 'X' => "X+YF"
    case 'Y' => "FX-Y"
}  


And the corresponding drawing:



Fractal Plant

This is Example 8 on the Wikipedia page.

Kojo Code:

val fplant_wp8 = LSystem("X", 25, 4) {
    case 'X'=> "F-[[X]+X]+F[+FX]-X"
    case 'F' => "FF"
}


And the corresponding drawing:




The next few examples are from the book - The Computational Beauty of Nature.

Tree-2

Kojo Code:

val tree2 = LSystem("G", 8, 100, 0.35) {
    case 'G' => "|[+++++G][-------G]-|[++++G][------G]-|[+++G][-----G]-|G"
}


And the corresponding drawing:



 

Carpet

Kojo Code:

val carpet = LSystem("F-F-F-F", 90, 1) {
    case 'F'=> "F[F]-F+F[--F]+F-F"
}


And the corresponding drawing:



Runnable code for this post is here: https://gist.github.com/2757241. To play with the code, copy it into Kojo and hit the Run button. Then tweak the code and re-run as desired.

Enjoy!

Related Links
The Wikipedia L-Systems page
The Computational Beauty of Nature
Neat Graphics with Scala Processing

Tuesday, May 15, 2012

Recursive Drawing with Kojo

A few days ago, I discovered (via Hacker News) a site called recursivedrawing.com. This site contains a very interesting tool for making drawings based on the idea of recursion. And even though the site focuses on a visual exploration of this idea, I was immediately struck by the conceptual similarity of this tool to Pictures within Kojo. So, without further ado, here are some of the drawings from the demo video on the site - done in Kojo.

And btw, doing art of this nature works very well with the recently introduced Interactive Program Moulding feature within Kojo.


Recursive Circles

 

Here's a Kojo based rendition of the drawing:




And here's the corresponding Kojo (Scala) code:

def C = penColor(noColor) * fillColor(Color(0, 136, 204)) -> Picture {
    circle(50)
}

clear()
setBackground(Color(255, 170, 29))
invisible()
def drawing(n: Int): Picture = {
    if (n == 1) 
        C
    else 
        GPics(
            C,
            brit(0.05) * trans(124, 0) * rot(-35) * scale(0.9) -> drawing(n-1)
        )
}

val pic = rot(60) -> drawing(50)
draw(pic)

 

Binary Tree

 

Here's a Kojo version of the drawing:




And here's the corresponding code:

val size = 100
def S = Picture {
    repeat (4) {
        forward(100)
        right()
    }
}

def stem = scale(0.13, 1) * penColor(noColor) * fillColor(black) -> S

clear()
setBackground(Color(255, 170, 29))
invisible()

def drawing(n: Int): Picture = {
    if (n == 1) 
        stem
    else 
        GPics(stem,
              trans(0, size-5) * brit(0.05) -> GPics(
                rot(25) * scale(0.72) -> drawing(n-1),
                rot(-50) * scale(0.55) -> drawing(n-1)
            )
        )
}

val pic = trans(0, -100) -> drawing(10)
draw(pic)

 

Fib Tree

 

Here's a Kojo version of the drawing:




And here's the corresponding code:

val size = 100
def S = Picture {
    repeat (4) {
        forward(100)
        right()
    }
}

def stem = scale(0.13, 1) * penColor(noColor) * fillColor(black) -> S

clear()
setBackground(Color(255, 170, 29))
invisible()

def drawing(n: Int): Picture = {
    if (n == 1) 
        stem
    else 
        GPics(stem,
              trans(2, size-5) * brit(0.05) -> GPics(
                rot(25) * scale(0.72) -> drawing(n-1),
                rot(25) * trans(0, size * 0.72) * rot(-75) * scale(0.55) -> drawing(n-1)
            )
        )
}

val pic = trans(0, -100) -> drawing(10)
draw(pic)

Happy recursing!

Monday, January 9, 2012

A Kojo Update

There have been some interesting new developments on the Kojo front recently.

Feedback welcome...

Enjoy!