--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/progs/mandelbrot2.scala Sat Mar 11 22:42:09 2023 +0000
@@ -0,0 +1,186 @@
+// Mandelbrot pictures
+//=====================
+//
+// see https://en.wikipedia.org/wiki/Mandelbrot_set
+//
+// under scala 2.13.XX needs to be called with
+//
+// scala -cp scala-parallel-collections_2.13-0.2.0.jar mandelbrot.scala
+
+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
+import scala.language.implicitConversions
+import scala.collection.parallel.CollectionConverters._
+
+// complex numbers
+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)
+}
+
+// to allow the notation n + m * i
+object i extends Complex(0, 1)
+implicit def double2complex(re: Double) = 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))
+
+// the viewer panel with an image canvas
+class Viewer(width: Int, height: Int) extends JPanel {
+ 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)
+
+ def clearCanvas(color: Color) = {
+ for (x <- 0 to width - 1; y <- 0 to height - 1)
+ canvas.setRGB(x, y, color.getRGB())
+ repaint()
+ }
+}
+
+// initialising the viewer panel
+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
+}
+
+// some hardcoded parameters
+val W = 900 // width
+val H = 800 // height
+val black = Color.black
+val viewer = openViewer(W, H)
+
+// draw a pixel on the canvas
+def pixel(x: Int, y: Int, color: Color) =
+ viewer.canvas.setRGB(x, y, color.getRGB())
+
+
+// calculates the number of iterations using lazy lists (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
+ LazyList.iterate(0.0 * i, max)(next).takeWhile(pred).size
+}
+
+// main function
+// start and end are the upper-left and lower-right corners,
+// max is the number of maximum iterations
+def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = {
+ viewer.clearCanvas(black)
+
+ // deltas for each grid step
+ val d_x = (end.re - start.re) / W
+ val d_y = (end.im - start.im) / H
+
+ for (y <- (0 until H).par) {
+ for (x <- (0 until W).par) {
+
+ 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)
+
+ pixel(x, y, col)
+ }
+ 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 = -2.0 + -1.5 * i
+val exa2 = 1.0 + 1.5 * i
+
+println(s"${time_needed(mandelbrot(exa1, exa2, 1000))} secs")
+
+// example 2
+val exb1 = -0.37465401 + 0.659227668 * i
+val exb2 = -0.37332410 + 0.66020767 * i
+
+//time_needed(mandelbrot(exb1, exb2, 1000))
+
+// example 3
+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
+
+//println(s"${time_needed(
+// for (n <- (0 to 12))
+// mandelbrot(exc1 + delta * n,
+// exc2 - delta * n, 100))} secs")
+
+
+
+// Larry Paulson's example
+val exl1 = -0.74364990 + 0.13188170 * i
+val exl2 = -0.74291189 + 0.13261971 * i
+
+//println(s"${time_needed(mandelbrot(exl1, exl2, 1000))} secs")
+
+
+// example by Jorgen Villadsen
+val exj1 = 0.10284 - 0.63275 * i
+val exj2 = 0.11084 - 0.64075 * i
+
+//time_needed(mandelbrot(exj1, exj2, 1000))
+
+
+// another example
+val exA = 0.3439274 + 0.6516478 * i
+val exB = 0.3654477 + 0.6301795 * i
+
+//time_needed(mandelbrot(exA, exB, 1000))