diff -r 5ab45f3fee1c -r f211d9cb856e progs/mandelbrot.scala --- a/progs/mandelbrot.scala Sat Jun 16 20:55:51 2018 +0100 +++ b/progs/mandelbrot.scala Fri Jun 22 13:34:05 2018 +0100 @@ -6,89 +6,105 @@ import javax.swing.JFrame import javax.swing.JPanel import javax.swing.WindowConstants +import scala.language.implicitConversions // 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) +case class Complex(val re: Double, val im: Double) { + // represents the complex number re + im * i + def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) + def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) + def *(that: Complex) = Complex(this.re * that.re - this.im * that.im, + this.re * that.im + that.re * this.im) + def *(that: Double) = Complex(this.re * that, this.im * that) + def abs() = Math.sqrt(this.re * this.re + this.im * this.im) } -// some customn colours +object i extends Complex(0, 1) + +implicit def double2complex(re: Double): Complex = Complex(re, 0) + +// some customn colours for the "sliding effect" 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)) + 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 +// the viewer panel with a canvas 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) + val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) + + override def paintComponent(g: Graphics) = + g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) + + override def getPreferredSize() = + new Dimension(width, height) - 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 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 +// initialising the viewer +def openViewer(width: Int, height: Int) : Viewer = { + 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 +// some hardcoded data +val W = 900 // width +val H = 800 // height val black = Color.black val viewer = openViewer(W, H) - +// drawing a pixel on the canvas def pixel(x: Int, y: Int, color: Color) = viewer.canvas.setRGB(x, y, color.getRGB()) - + -def mandelbrot(start: Complex, end: Complex, level: Int) : Unit = { +// calculating the number of iterations using lazy streams +// the iteration goes on for a maximum of max steps, +// but might leave early when the pred is satisfied +def iterations(c: Complex, max: Int) : Int = { + def next(z: Complex) = z * z + c + def pred(z: Complex) = z.abs < 2 // exit condition + Stream.iterate(0.0 * i, max)(next).takeWhile(pred).size +} + +// main function +def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = { viewer.clearCanvas(black) - - val delta_x = (end.a - start.a) / W - val delta_y = (end.b - start.b) / H + + // deltas for each grid step + val d_x = (end.re - start.re) / W + val d_y = (end.im - start.im) / H - for (y0 <- (0 until H)) { - for (x0 <- (0 until W)) { + for (y <- (0 until H).par) { + for (x <- (0 until W).par) { - val c = start + Complex(x0 * delta_x, y0 * delta_y) + val c = start + + (x * d_x + y * d_y * i) + val iters = iterations(c, max) + val col = + if (iters == max) black + else colours(iters % 16) - 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)) + pixel(x, y, col) } viewer.updateUI() - } + } } // Examples @@ -104,43 +120,38 @@ // example 1 -val exa1 = Complex(-2.0, -1.5) -val exa2 = Complex( 1.0, 1.5) +val exa1 = -2.0 + -1.5 * i +val exa2 = 1.0 + 1.5 * i time_needed(mandelbrot(exa1, exa2, 1000)) // example 2 -val exb1 = Complex(-0.37465401, 0.659227668) -val exb2 = Complex(-0.37332410, 0.66020767) +val exb1 = -0.37465401 + 0.659227668 * i +val exb2 = -0.37332410 + 0.66020767 * i -time_needed(mandelbrot(exb1, exb2, 1000)) +//time_needed(mandelbrot(exb1, exb2, 1000)) // example 3 -val exc1 = Complex(0.435396403, 0.367981352) -val exc2 = Complex(0.451687191, 0.380210061) +val exc1 = 0.435396403 + 0.367981352 * i +val exc2 = 0.451687191 + 0.380210061 * i //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)) - -val exc1 = Complex(0.435396403, 0.367981352) -val exc2 = Complex(0.451687191, 0.380210061) + for (n <- (0 to 12)) + mandelbrot(exc1 + delta * n, + exc2 - delta * n, 100)) -//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)) + for (n <- (0 to 12)) + mandelbrot(exc1 + delta * n, + exc2 - delta * n, 1000)) +*/ -