Skip to content

Instantly share code, notes, and snippets.

@gabrieljones
Forked from GabrielJones646/Mandelbrot.scala
Last active July 29, 2019 13:43
Show Gist options
  • Save gabrieljones/5e3e9565f251aa783da46453e96f23ed to your computer and use it in GitHub Desktop.
Save gabrieljones/5e3e9565f251aa783da46453e96f23ed to your computer and use it in GitHub Desktop.
// © 2015, 2019 Gabriel Jones
import org.scalajs.dom
import spire.math.Complex
import spire.implicits._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val TAU = 2*Math.PI
val LIMIT = 255
// val (xCenter, yCenter) = (3.5/2 - 2.5, 3.5/2 - 1.75)
// val width = 3.5
val (xCenter, yCenter) = (-0.55, 0.6)
val width = 0.1
val (xMin, xMax) = (xCenter - width/2, xCenter + width/2)
val (yMin, yMax) = (yCenter - width/2, yCenter + width/2)
val (rasterHeight, rasterWidth) = (512, 512)
def cAt(px: Int, py: Int) = {
val x = xMin + (xMax - xMin) / rasterWidth * px
val y = yMin + (yMax - yMin) / rasterHeight * (rasterHeight-py)
Complex[Double](x,y)
}
def mag(c: Complex[Double]) = { c.real * c.real + c.imag * c.imag }
def iterations(c: Complex[Double]) = {
lazy val zn: Stream[Complex[Double]] = c #:: zn.map{zp => zp * zp + c}
zn.take(LIMIT).takeWhile(c => mag(c) < 4).length
}
def hue(iters: Int) = iters % 360
for {
i <- 0 until 256
h = hue(i)
} {
Fiddle.draw.fillStyle = s"hsl($h,100%,50%)"
Fiddle.draw.fillRect(i, 0, 1, 1)
}
val palette = Fiddle.draw.getImageData(0, 0, 256, 1).data
val raster = Array.ofDim[Byte](rasterWidth, rasterHeight)
lazy val fs: Stream[Int] = 2 #:: fs.map(_ *2)
val drawPixels = (for {
f: Int <- fs.toIterator.take(9)
pRadius = 512.0 / f * 1.5
_ = dom.console.log(s"$f, $pRadius")
pixelY <- ((512 / f) until rasterHeight by (512 / (f / 2))).toIterator
pixelX <- ((512 / f) until rasterWidth by (512 / (f / 2))).toIterator
d = Future {
val iters = iterations(cAt(pixelX, pixelY))
val h = hue(iters)
val fillStyle = {
val grd = Fiddle.draw.createRadialGradient(pixelX, pixelY, 1, pixelX, pixelY, pRadius)
grd.addColorStop(0,if (iters >= LIMIT) "rgba(0,0,0,1.0)" else s"hsla($h,100%,50%,1.0)")
grd.addColorStop(1,if (iters >= LIMIT) "rgba(0,0,0,0.0)" else s"hsla($h,100%,50%,0.0)")
grd
}
Fiddle.draw.fillStyle = fillStyle
Fiddle.draw.beginPath()
Fiddle.draw.arc(pixelX, pixelY, pRadius, 0.0, TAU)
Fiddle.draw.fill()
raster(pixelX)(pixelY) = iters.toByte
}
} yield d) ++
( for {
(offsetX, offsetY) <- Seq((0,0), (1,0), (0,1)).toIterator
pRadius = 1.0
_ = dom.console.log(s"$offsetX,$offsetY, $pRadius")
pixelY <- (offsetX until rasterHeight by 2).toIterator
pixelX <- (offsetY until rasterWidth by 2).toIterator
d = Future {
val iters = iterations(cAt(pixelX, pixelY))
val h = hue(iters)
val fillStyle = if (iters >= LIMIT) "rgb(0,0,0)" else s"hsl($h,100%,50%)"
Fiddle.draw.fillStyle = fillStyle
Fiddle.draw.fillRect(pixelX, pixelY, 1, 1)
raster(pixelX)(pixelY) = iters.toByte
}
} yield d)
var cycleCount = 255 * 100
def cyclePalette = dom.window.setInterval(()=>{
val id = Fiddle.draw.getImageData(0, 0, rasterWidth, rasterHeight)
val idd = id.data
for {
py <- 0 until rasterHeight
px <- 0 until rasterWidth
if raster(px)(py) > 0
nCi = (raster(px)(py) + cycleCount) % 255
rgbi <- 0 until 3
} {
idd((px + py * rasterWidth) * 4 + rgbi) = palette(nCi * 4 + rgbi)
}
Fiddle.draw.putImageData(id, 0, 0)
cycleCount -= 1
}, 0)
def asynchronousIteration: Unit = {
var start = js.Date.now()
while (js.Date.now() - 2 < start && drawPixels.hasNext) drawPixels.next
if (drawPixels.hasNext) dom.window.setTimeout(asynchronousIteration _, 0) else {
println("done")
cyclePalette
}
}
asynchronousIteration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment