Last active
August 29, 2015 13:57
-
-
Save kamiyaowl/9501818 to your computer and use it in GitHub Desktop.
Scalaで自己相似図形を描画
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
java.lang.OutOfMemoryError: Java heap space | |
at java.util.Arrays.copyOf(Arrays.java:2882) | |
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) | |
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390) | |
at java.lang.StringBuilder.append(StringBuilder.java:119) | |
at scala.collection.mutable.StringBuilder.append(StringBuilder.scala:197) | |
at scala.collection.TraversableOnce$$anonfun$addString$1.apply(TraversableOnce.scala:327) | |
at scala.collection.Iterator$class.foreach(Iterator.scala:727) | |
at scala.collection.AbstractIterator.foreach(Iterator.scala:1157) | |
at scala.collection.IterableLike$class.foreach(IterableLike.scala:72) | |
at scala.collection.AbstractIterable.foreach(Iterable.scala:54) | |
at scala.collection.TraversableOnce$class.addString(TraversableOnce.scala:320) | |
at scala.collection.AbstractTraversable.addString(Traversable.scala:105) | |
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:286) | |
at scala.collection.AbstractTraversable.mkString(Traversable.scala:105) | |
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:288) | |
at scala.collection.AbstractTraversable.mkString(Traversable.scala:105) | |
at scala.collection.TraversableOnce$class.mkString(TraversableOnce.scala:290) | |
at scala.collection.AbstractTraversable.mkString(Traversable.scala:105) | |
at Main$ReplaceSystem.$div(LSystem.scala:49) | |
at Main$ReplaceSystem.$greater$greater(LSystem.scala:52) | |
at Main$ReplaceSystem.$greater$greater(LSystem.scala:52) | |
at Main$ReplaceSystem.$greater$greater(LSystem.scala:52) | |
at Main$ReplaceSystem.$greater$greater(LSystem.scala:52) | |
at Main$ReplaceSystem.$greater$greater(LSystem.scala:52) | |
at Main$$anonfun$main$1.apply$mcVI$sp(LSystem.scala:77) | |
at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:141) | |
at Main$.main(LSystem.scala:66) | |
at Main.main(LSystem.scala) | |
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) | |
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) | |
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) | |
at java.lang.reflect.Method.invoke(Method.java:597) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.language.postfixOps | |
import scala.language.implicitConversions | |
import javax.imageio.ImageIO | |
import java.awt.{Graphics, Color} | |
import java.awt.image.BufferedImage | |
import java.io.File | |
object LSystem { | |
implicit class PointWriter(val self:List[(Double,Double)]) { | |
implicit def doubleToInt(x:Double) = x.toInt | |
def createImage(s:(Double,Double) = (0.0, 0.0)) = { | |
val size = if(s == (0.0,0.0)) imageSize else s | |
new BufferedImage(size._1,size._2,BufferedImage.TYPE_INT_BGR) | |
} | |
def >>(g:Graphics)(implicit color:Color = Color.red) = { | |
g.setColor(color) | |
self zip self.tail foreach(x => g.drawLine(x._1._1,x._1._2, x._2._1, x._2._2)) | |
} | |
def imageSize = { | |
((self.map(_._1).max - self.map(_._1).min) * 2, (self.map(_._2).max - self.map(_._2).min) * 2) | |
} | |
def shiftCenter(size:(Double,Double)) = { | |
self map(x => {(x._1 + size._1, x._2 + size._2)}) | |
} | |
} | |
implicit class AngleExtension[T <% Double](self:T) { | |
def toRad() = (self / 180.0 * math.Pi) | |
def toDeg() = (self / math.Pi * 180) | |
} | |
class LSystemDrawing(var stroke:Double, var diffDeg:Double) { | |
def calc(from:(Double,Double), deg:Double) = { | |
val dx = stroke * math.cos(deg.toRad) | |
val dy = stroke * math.sin(deg.toRad) | |
(from._1 + dx, from._2 + dy) | |
} | |
def next(c:List[Char])(from:(Double,Double), fromDeg:Double) : Stream[(Double,Double)] = { | |
def turn(nextDeg:Double) = next(c.tail)(from,nextDeg) | |
def ahead() = { | |
val current = calc(from,fromDeg) | |
Stream.cons(current,next(c.tail)(current,fromDeg)) | |
} | |
if(c.isEmpty) Stream.empty | |
else { | |
c.head match { | |
case '+' => turn(fromDeg + diffDeg) | |
case '-' => turn(fromDeg - diffDeg) | |
case 'F' => ahead | |
case 'f' => next(c.tail)(calc(from,fromDeg),fromDeg) | |
case _ => ahead | |
} | |
} | |
} | |
} | |
implicit class ReplaceSystem(self:String) { | |
def /(implicit rule:Map[Char,String]) = self map(r) mkString | |
def >>(n:Int)(implicit rule:Map[Char,String]):String = { | |
if(n == 0) self | |
else self./.>>(n-1)(rule) | |
} | |
def r(c:Char)(implicit rule:Map[Char,String]) = rule.get(c) match { | |
case Some(n) => n | |
case None => c | |
} | |
} | |
class LSystemRule { | |
var name:String = _ | |
var default:String = _ | |
implicit var rule:Map[(Char),String] = _ | |
var stroke:Double = 5.0 | |
var angle:Double = 90.0 | |
var isCenter:Boolean = false | |
var limit:Int = 10 | |
private var current:String = _ | |
private var generation = 0 | |
def >>(n:Int) = { | |
if((generation == 0) || (n < generation)) { | |
generation = 0 | |
current = default | |
} | |
current = current >> (n - generation) | |
generation = n | |
this | |
} | |
def draw = { | |
val ld =new LSystemDrawing(stroke,angle) | |
val drawablePoints = ld.next(current toList)((0,0),0) toList | |
val size = drawablePoints.imageSize | |
val points = if(isCenter){ | |
drawablePoints shiftCenter (size._1 / 2.0, size._2 / 2.0) | |
} else drawablePoints | |
val bi = points.createImage(size) | |
points >> bi.createGraphics | |
bi | |
} | |
def filename = name + "_" + generation | |
} | |
object LSystemRules { | |
val all = Array(koch_curve, koch_island, koch_island2, snake, sierpinski_triangle, levy_curve) | |
def koch_curve = { | |
val r = new LSystemRule | |
r.name = "koch_curve" | |
r.default = "F" | |
r.rule = Map('F' -> "F+F-F-F+F") | |
r.limit = 5 | |
r | |
} | |
def koch_island = { | |
val r = new LSystemRule | |
r.name = "koch_island" | |
r.default = "F-F-F-F" | |
r.rule = Map('F' -> "F+FF-FF-F-F+F+FF-F-F+F+FF+FF-F") | |
r.isCenter = true | |
r.limit = 3 | |
r | |
} | |
def koch_island2 = { | |
val r = new LSystemRule | |
r.name = "koch_island2" | |
r.default = "F-F-F-F" | |
r.rule = Map('F' -> "FF-F-F-F-FF") | |
r.isCenter = true | |
r.limit = 3 | |
r | |
} | |
def snake = { | |
val r = new LSystemRule | |
r.name = "snake" | |
r.default = "-F" | |
r.rule = Map('F' -> "F++F--F-F+F") | |
r.limit = 8 | |
r | |
} | |
def sierpinski_triangle = { | |
val r = new LSystemRule | |
r.name = "sierpinski_triangle" | |
r.default = "A" | |
r.rule = Map('A' -> "B-A-B", 'B' -> "A+B+A") | |
r.angle = 45 | |
r.limit = 6 | |
r | |
} | |
def levy_curve = { | |
val r = new LSystemRule | |
r.name = "lavy_curve" | |
r.default = "F" | |
r.rule = Map('F' -> "+F--F+") | |
r.angle = 45 | |
r.limit = 16 | |
r.isCenter = true | |
r | |
} | |
} | |
def main(args:Array[String]): Unit = { | |
for(lsr <- LSystemRules.all) { | |
for(count <- 1 to lsr.limit) { | |
println(lsr.name + " >>" + count) | |
ImageIO.write(lsr >> count draw,"png",new File(lsr.filename + ".png")) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment