|      1 // Mandelbrot pictures |      1 // Mandelbrot pictures | 
|         |      2 // | 
|      2 //   see https://en.wikipedia.org/wiki/Mandelbrot_set |      3 //   see https://en.wikipedia.org/wiki/Mandelbrot_set | 
|         |      4 //  | 
|         |      5 // under scala 2.13 needs to be called with  | 
|         |      6 // scala -cp `coursier fetch -p org.scala-lang.modules:scala-parallel-collections_2.13:0.2.0` mandelbrot.scala | 
|      3  |      7  | 
|      4 import java.awt.Color |      8 import java.awt.Color | 
|      5 import java.awt.Dimension |      9 import java.awt.Dimension | 
|      6 import java.awt.Graphics |     10 import java.awt.Graphics | 
|      7 import java.awt.Graphics2D |     11 import java.awt.Graphics2D | 
|      8 import java.awt.image.BufferedImage |     12 import java.awt.image.BufferedImage | 
|      9 import javax.swing.JFrame |     13 import javax.swing.JFrame | 
|     10 import javax.swing.JPanel |     14 import javax.swing.JPanel | 
|     11 import javax.swing.WindowConstants |     15 import javax.swing.WindowConstants | 
|     12 import scala.language.implicitConversions     |     16 import scala.language.implicitConversions     | 
|     13  |     17 import scala.collection.parallel.CollectionConverters._ | 
|     14  |     18  | 
|     15 // complex numbers |     19 // complex numbers | 
|     16 case class Complex(val re: Double, val im: Double) {  |     20 case class Complex(val re: Double, val im: Double) {  | 
|     17   // represents the complex number re + im * i |     21   // represents the complex number re + im * i | 
|     18   def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) |     22   def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) | 
|     37   new Color(134, 181, 229), new Color(211, 236, 248), |     41   new Color(134, 181, 229), new Color(211, 236, 248), | 
|     38   new Color(241, 233, 191), new Color(248, 201, 95), |     42   new Color(241, 233, 191), new Color(248, 201, 95), | 
|     39   new Color(255, 170, 0),   new Color(204, 128, 0), |     43   new Color(255, 170, 0),   new Color(204, 128, 0), | 
|     40   new Color(153, 87, 0),    new Color(106, 52, 3)) |     44   new Color(153, 87, 0),    new Color(106, 52, 3)) | 
|     41  |     45  | 
|     42 // the viewer panel with a canvas |     46 // the viewer panel with an image canvas | 
|     43 class Viewer(width: Int, height: Int) extends JPanel { |     47 class Viewer(width: Int, height: Int) extends JPanel { | 
|     44   val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) |     48   val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) | 
|     45    |     49    | 
|     46   override def paintComponent(g: Graphics) =  |     50   override def paintComponent(g: Graphics) =  | 
|     47     g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) |     51     g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) | 
|     54       canvas.setRGB(x, y, color.getRGB()) |     58       canvas.setRGB(x, y, color.getRGB()) | 
|     55     repaint() |     59     repaint() | 
|     56   }   |     60   }   | 
|     57 } |     61 } | 
|     58  |     62  | 
|     59 // initialising the viewer |     63 // initialising the viewer panel | 
|     60 def openViewer(width: Int, height: Int) : Viewer = { |     64 def openViewer(width: Int, height: Int) : Viewer = { | 
|     61   val frame = new JFrame("XYPlane") |     65   val frame = new JFrame("XYPlane") | 
|     62   val viewer = new Viewer(width, height) |     66   val viewer = new Viewer(width, height) | 
|     63   frame.add(viewer) |     67   frame.add(viewer) | 
|     64   frame.pack() |     68   frame.pack() | 
|     66   frame.setResizable(false) |     70   frame.setResizable(false) | 
|     67   frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) |     71   frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) | 
|     68   viewer |     72   viewer | 
|     69 } |     73 } | 
|     70  |     74  | 
|     71 // some hardcoded data |     75 // some hardcoded parameters | 
|     72 val W = 900   // width |     76 val W = 900   // width | 
|     73 val H = 800   // height |     77 val H = 800   // height | 
|     74 val black = Color.black |     78 val black = Color.black | 
|     75 val viewer = openViewer(W, H) |     79 val viewer = openViewer(W, H) | 
|     76  |     80  | 
|     77 // drawing a pixel on the canvas |     81 // draw a pixel on the canvas | 
|     78 def pixel(x: Int, y: Int, color: Color) =  |     82 def pixel(x: Int, y: Int, color: Color) =  | 
|     79   viewer.canvas.setRGB(x, y, color.getRGB()) |     83   viewer.canvas.setRGB(x, y, color.getRGB()) | 
|     80  |     84  | 
|     81  |     85  | 
|     82 // calculating the number of iterations using lazy streams |     86 // calculates the number of iterations using lazy lists (streams) | 
|     83 //   the iteration goes on for a maximum of max steps, |     87 //   the iteration goes on for a maximum of max steps, | 
|     84 //   but might leave early when the pred is satisfied |     88 //   but might leave early when the pred is satisfied | 
|     85 def iterations(c: Complex, max: Int) : Int = { |     89 def iterations(c: Complex, max: Int) : Int = { | 
|     86   def next(z: Complex) = z * z + c     |     90   def next(z: Complex) = z * z + c     | 
|     87   def pred(z: Complex) = z.abs < 2    // exit condition |     91   def pred(z: Complex) = z.abs < 2    // exit condition | 
|     88   Stream.iterate(0.0 * i, max)(next).takeWhile(pred).size |     92   LazyList.iterate(0.0 * i, max)(next).takeWhile(pred).size | 
|     89 } |     93 } | 
|     90  |     94  | 
|     91 // main function  |     95 // main function  | 
|     92 //    start and end are the upper-left and lower right corners  |     96 //    start and end are the upper-left and lower-right corners,  | 
|     93 //    max is the number of maximum iterations |     97 //    max is the number of maximum iterations | 
|     94 def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = { |     98 def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = { | 
|     95   viewer.clearCanvas(black) |     99   viewer.clearCanvas(black) | 
|     96    |    100    | 
|     97   // deltas for each grid step  |    101   // deltas for each grid step  | 
|    143 val exc1 = 0.435396403 + 0.367981352 * i |    147 val exc1 = 0.435396403 + 0.367981352 * i | 
|    144 val exc2 = 0.451687191 + 0.380210061 * i |    148 val exc2 = 0.451687191 + 0.380210061 * i | 
|    145  |    149  | 
|    146 //time_needed(mandelbrot(exc1, exc2, 1000)) |    150 //time_needed(mandelbrot(exc1, exc2, 1000)) | 
|    147  |    151  | 
|         |    152  | 
|         |    153  | 
|    148 // some more computations with example 3 |    154 // some more computations with example 3 | 
|    149  |    155  | 
|    150 val delta = (exc2 - exc1) * 0.0333 |    156 val delta = (exc2 - exc1) * 0.0333 | 
|    151  |    157  | 
|    152 /* |    158 /* | 
|    153 time_needed( |    159 time_needed( | 
|    154   for (n <- (0 to 12))  |    160   for (n <- (0 to 12))  | 
|    155      mandelbrot(exc1 + delta * n,  |    161      mandelbrot(exc1 + delta * n,  | 
|    156                 exc2 - delta * n, 100))  |    162                 exc2 - delta * n, 100))  | 
|    157 */ |    163 */ | 
|         |    164  | 
|    158 /* |    165 /* | 
|    159 time_needed( |    166 time_needed( | 
|    160   for (n <- (0 to 12))  |    167   for (n <- (0 to 12))  | 
|    161      mandelbrot(exc1 + delta * n,  |    168      mandelbrot(exc1 + delta * n,  | 
|    162                 exc2 - delta * n, 1000)) |    169                 exc2 - delta * n, 1000)) |