diff -r 556cd74cbba9 -r c45d3cd9a749 progs/mandelbrot.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/progs/mandelbrot.scala Sat Nov 04 16:17:19 2017 +0000 @@ -0,0 +1,133 @@ +import java.awt.Color +import java.awt.Dimension +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.image.BufferedImage +import javax.swing.JFrame +import javax.swing.JPanel +import javax.swing.WindowConstants + +// complex numbers +case class Complex(val a: Double, val b: Double) { + // represents the complex number a + b*i + def +(that: Complex) = Complex(this.a + that.a, this.b + that.b) + def -(that: Complex) = Complex(this.a - that.a, this.b - that.b) + def *(that: Complex) = Complex(this.a * that.a - this.b * that.b, + this.a * that.b + that.a * this.b) + def *(that: Double) = Complex(this.a * that, this.b * that) + def abs() = Math.sqrt(this.a * this.a + this.b * this.b) +} + +// some customn colours +val colours = List( + new Color(66, 30, 15), new Color(25, 7, 26), + new Color(9, 1, 47), new Color(4, 4, 73), + new Color(0, 7, 100), new Color(12, 44, 138), + new Color(24, 82, 177), new Color(57, 125, 209), + new Color(134, 181, 229), new Color(211, 236, 248), + new Color(241, 233, 191), new Color(248, 201, 95), + new Color(255, 170, 0), new Color(204, 128, 0), + new Color(153, 87, 0), new Color(106, 52, 3)) + +// the viewer panel +class Viewer(width: Int, height: Int) extends JPanel { + val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) + clearCanvas(Color.black) + + override def paintComponent(g: Graphics) = + g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) + + override def getPreferredSize() = + new Dimension(width, height) + + def clearCanvas(color: Color) = { + for(x <- 0 to width - 1; + y <- 0 to height - 1) canvas.setRGB(x, y, color.getRGB()) + repaint() + } + +} + +def openViewer(width: Int, height: Int) = { + val frame = new JFrame("XYPlane") + val viewer = new Viewer(width, height) + frame.add(viewer) + frame.pack() + frame.setVisible(true) + frame.setResizable(false) + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) + viewer +} + +val W = 900 +val H = 800 +val black = Color.black +val viewer = openViewer(W, H) + + +def pixel(x: Int, y: Int, color: Color) = + viewer.canvas.setRGB(x, y, color.getRGB()) + + +def mandelbrot(start: Complex, end: Complex, level: Int) : Unit = { + viewer.clearCanvas(black) + + val delta_x = (end.a - start.a) / W + val delta_y = (end.b - start.b) / H + + for (y0 <- (0 until H).par) { + for (x0 <- (0 until W).par) { + + val c = start + Complex(x0 * delta_x, y0 * delta_y) + + def iters(z: Complex, it: Int) : Color = { + if (it < level && z.abs < 2) iters(z * z + c, it + 1) else + if (it == level) black else colours(it % 16) + } + + pixel(x0, y0, iters(Complex(0, 0), 0)) + } + viewer.updateUI() + } +} + +// Examples +//========== + +//for measuring time +def time_needed[T](code: => T) = { + val start = System.nanoTime() + code + val end = System.nanoTime() + (end - start) / 1.0e9 +} + + +// example 1 +val exa1 = Complex(-2.0, -1.5) +val exa2 = Complex( 1.0, 1.5) + +time_needed(mandelbrot(exa1, exa2, 1000)) + +// ehxample 2 +val exb1 = Compylex(-0.37465401, 0.659227668) +val exb2 = Complex(-0.37332410, 0.66020767) + +time_needed(mandelbrot(exb1, exb2, 1000)) + +// example 3 +val exc1 = Complex(0.435396403, 0.367981352) +val exc2 = Complex(0.451687191, 0.380210061) + +time_needed(mandelbrot(exc1, exc2, 1000)) + +// some more computations with example 3 +val delta = (exc2 - exc1) * 0.0333 + +time_needed( +for (i <- (0 to 12)) + mandelbrot(exc1 + delta * i, + exc2 - delta * i, 1000)) + + +