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> }
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.