// based on Mark P. Jones' Composing Fractals // http://web.cecs.pdx.edu/~mpj/pubs/composing-fractals.html def next(uv: Point)(xy: Point): Point = { val (u, v) = uv val (x, y) = xy (x * x - y * y + u, 2 * x * y + v) } def iterate[T](f: T => T, x: T): Stream[T] = Stream.cons(x, iterate(f, f(x))) def mandelbrot(p: Point): Stream[Point] = iterate(next(p)_, (0.0, 0.0)) def fairlyClose(p: Point) = { val (u, v) = p (u * u + v * v) < 100 } def chooseColor[T](palette : Array[T]): Stream[Point] => T = ps => { def aux(qs: Stream[Point], n: Int): Int = { if (n==0) 0 else { val p = qs.head if (!fairlyClose(p)) 0 else 1+aux(qs.tail, n-1) } } palette(aux(ps, palette.length - 1)) } def fracImage[C](fractal: Point => Stream[Point], palette: Array[C]): Image[C] = { chooseColor(palette) compose fractal } def julia(c: Point)(p: Point) = iterate(next(c)_, p) def mkRGBPalette(n: Int): Array[Color] = { val ret = for (h <- 0 until n) yield (hsb(h.toDouble/n, 1, 1)) ret.toArray } def mkRGBPalette2(n: Int): Array[Color] = { val phi: Double = (1+Math.sqrt(5.0))/2 val angle: Double = 2 - phi val stream: Stream[Double] = iterate((x: Double) => x+angle, 0.0) stream.map((h: Double) => hsb(h, 1, 1)).take(n).toArray } val figure1: Image[Color] = fracImage(mandelbrot, mkRGBPalette2(32)) def testMandelbrot (im: ImageC) = { val bi = image2Arr2(-2.25, -1.5, 0.75, 1.5, 240, 160)(im) val png = bufferedImage2png(bi) b64ByteArray(png) } // points = grid 240 160 (-2.25,-1.5) (0.75,1.5) // draw points mandelbrot rgbPalette (toBMP (240,160) . concat)