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)) |