Monday, February 28, 2011

SVG Fractal with Scala 2 : The Sierpinski gasket

Result

Source Code - first part

import java.io.FileWriter
import java.io.BufferedWriter

abstract class Fractal(width: Double, height: Double) {

 val head = """<?xml version="1.0" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">"""

 def body: xml.Elem 

 def root = body match {
  case <pack>{inner @ _*}</pack> =>
  <svg width={width.toString} height={height.toString}
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink">
   {inner}
  </svg>
 }

 def draw(filename: String): Unit = {
  val fw = new BufferedWriter(new FileWriter(filename))
  fw.write(head)
  fw.newLine()
  fw.write(root.toString)
  fw.close()
 }
}

This is an abstract class which provides draw() function to its descendants.  body() should generate <pack> figure </pack> form of XML code and root() changes it to <svn> figure </svn>.  And, then, draw() write it to a file.

Things I am so sure
  • Is this the best way to writing to the file?  Doesn't Scala really have its own write functions?
  • Maybe I should use Traits, whatever it is, rather than abstract class.  That might be more Scala way?
  • I defined head as a String because defining it as a xml.Elem gave me an error at <!DOCTYPE.  Compiler said it did not expected ! after <.  But, is this really?  Isn't <! kind a common in XML?  
  • I use following to substitute <body> with <scala>.  Is this, again, a best practice?
    def root = body match {
        case <pack>{inner @ _*}</pack> =>
        <svg>{inner} </svg>
        }
Source Code - second part

class Triangle(width: Double, level:Int) extends 
      Fractal(width,(width*1.732/2+1).toInt) {
 
    val scale = width/2 - 20
    val base = <pack><path id="level_0" fill="blue" 
                          d="M0,0 2,0 1,1.732 z"/></pack>
 
    def recursive(current:xml.Elem, currlevel:Int): xml.Elem = {
  if(currlevel == level)
  {
   current match {
    case <pack>{in @ _*}</pack> =>
    <pack>
    <g transform={"translate(20,20) scale("+scale+")"}>
     {in}
    </g>
    </pack>
   }
  } else {
   val next = current match {
    case <pack>{in @ _*}</pack> =>
    <pack>
    <g transform="translate(0,0) scale(0.5)">
     {in}
    </g>
    <g transform="translate(1,0) scale(0.5)">
     {in}
    </g>
    <g transform="translate(0.5,0.866) scale(0.5)">
     {in}
    </g>
    </pack>
   }
   recursive(next, currlevel+1)
  }
 }

 override def body = recursive(base, 0)
}

This is the real generator class of the Sierpinski gasket.  Take figure width and recursive level as parameters and draw() output a SVG file.  Basic idea is that at every recursive process, current level of figure is copied 3 times, shrink 50%, and then located to the position so that 3 of them combined form a big triangle.

Observations

  • My Macbook Pro runs this script up to level 11.  Level 12 gives me a stack over flow (Scala 2.8.1.final Interpreter).
  • I first wrote a code which generates SVG code just like this web page .  But, obviously, these style requires more processing power when drawing.  My Chrome gave up at level 8 and showed this.

Sunday, February 27, 2011

SVG Fractals with Scara

This is my first blogging ever.  I started learning a programming language called Scala a couple of weeks ago.  I thought it was a good timing for me to start blogging to keep track of my progress on learning and give some motivations at the same time.   But, gee, I even do not know how to put my source code here, not to mention about SVG.  Well, basically, I am learning two things at once, please be patient.

References
Following great URLs helped me a lot.

  • The Beauty of SVG
  • Free tutorials for graphics  Great tutorials for Postscript and SVG (in Japanese)
  • NikkeiBP article on Scala Great introduction to Scala (in Japanese)
    • Although my native tang is Japanese, I usually find tutorials in English better to understand.   I went through Haskell and Schema before, and they have very good English tutorials.  Somehow, however, it worked differently for me with Scala...
Goal
Write a scala program, or script?, which outputs a SVG file of a fractal diagam such as Koch snowflake, or this.
I wrote this triangle as SVG and converted it into PNG with Incscape.  I fond this post and tried, but did not work with my file.  I am pretty sure that that is my SVG file that is not following the convention strictly enough that his program works.  But, since Chrome and Firefox can show the picture, at least in my environment, I am satisfied with my SVG, at least for now...

Well, that it for today.  I wil post my source code next time (tomorrow, or next weekend, or might be tonight).