import java.lang.Math.{hypot, atan, cos, sin, pow}
abstract class Tree[+T] {
def forEach (f :(T,Int) => Unit):Unit = forEach (f, 0)
def forEach (f :(T,Int) => Unit, level:Int):Unit = {}
}
case class TreeNode[+T] (value:T, left:Tree[T], right:Tree[T]) extends Tree[T] {
override def forEach (f : (T,Int) => Unit, level:Int) = {
f(value, level)
left.forEach(f, level+1)
right.forEach(f, level+1)
}
}
case object EmptyTree extends Tree[Nothing]
case class Point (x:Double, y:Double)
case class Square (topLeft:Point, topRight:Point, bottomLeft:Point, bottomRight:Point, angle:Double)
val base = Square(Point(0,0), Point(100,0), Point(0,100), Point(100,100), 0)
val skew = 1
val halfPi = java.lang.Math.PI / 2
val quarterPi = java.lang.Math.PI / 4
val sqrt2 = java.lang.Math.pow(2, 0.5)
def makeTree (base:Square, goFor:Int):Tree[Square] = {
if (goFor > 0) {
val sideLength = hypot (base.topLeft.x - base.topRight.x, base.topLeft.y - base.topRight.y)
val newSideLength = (sideLength / sqrt2) * skew
val otherSideLength = pow(pow(sideLength,2) - pow(newSideLength,2), 0.5)
val angle = base.angle + atan(otherSideLength/newSideLength)
val otherAngle = angle - halfPi
val midPointX = base.topLeft.x + newSideLength * cos(angle)
val midPointY = base.topLeft.y - newSideLength * sin(angle)
val midPoint = Point(midPointX, midPointY)
TreeNode(base, makeSubTree(newSideLength, base.topLeft, midPoint, angle, goFor),
makeSubTree(otherSideLength, midPoint, base.topRight, otherAngle, goFor))
} else {
EmptyTree
}
}
def makeSubTree (length:Double, start:Point, end:Point, angle:Double, goFor:Int):Tree[Square] = {
val newSquare = Square (
Point(start.x - length*sin(angle), start.y - length * cos(angle)),
Point(end.x - length*sin(angle), end.y - length * cos(angle)),
start, end, angle)
makeTree(newSquare, goFor-1)
}
val maxLevel = 10
val newRoot = makeTree(base, maxLevel)
var count = 0
def showLine(start:Point, end:Point,color:String) = {
println("""<line id="%d" style="stroke:rgb(%s);stroke-width:1;fill:none;" x1="%f" y1="%f" x2="%f" y2="%f" />""".format
(count, color, start.x+300, start.y+300, end.x+300, end.y+300))
count += 1
}
println("""<svg x="0" y="0" width="800" height="600">""")
newRoot forEach {(square,level) =>
val color =
if (level == maxLevel - 1) "255,0,255"
else "0,0,128"
showLine(square.topLeft, square.topRight, color)
showLine(square.topLeft, square.bottomLeft, color)
showLine(square.bottomRight, square.topRight, color)
showLine(square.bottomLeft, square.bottomRight, color)
}
println("</svg>")