--- 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))
+*/
-