progs/mandelbrot.scala
changeset 124 c45d3cd9a749
child 136 c08ba57a7f53
--- /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))
+
+
+