Skip to content

Instantly share code, notes, and snippets.

@kamiyaowl
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kamiyaowl/9501818 to your computer and use it in GitHub Desktop.
Save kamiyaowl/9501818 to your computer and use it in GitHub Desktop.
Scalaで自己相似図形を描画
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)
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