|
1 import java.awt.Color |
|
2 import java.awt.Dimension |
|
3 import java.awt.Graphics |
|
4 import java.awt.Graphics2D |
|
5 import java.awt.image.BufferedImage |
|
6 import javax.swing.JFrame |
|
7 import javax.swing.JPanel |
|
8 import javax.swing.WindowConstants |
|
9 |
|
10 // complex numbers |
|
11 case class Complex(val a: Double, val b: Double) { |
|
12 // represents the complex number a + b*i |
|
13 def +(that: Complex) = Complex(this.a + that.a, this.b + that.b) |
|
14 def -(that: Complex) = Complex(this.a - that.a, this.b - that.b) |
|
15 def *(that: Complex) = Complex(this.a * that.a - this.b * that.b, |
|
16 this.a * that.b + that.a * this.b) |
|
17 def *(that: Double) = Complex(this.a * that, this.b * that) |
|
18 def abs() = Math.sqrt(this.a * this.a + this.b * this.b) |
|
19 } |
|
20 |
|
21 // some customn colours |
|
22 val colours = List( |
|
23 new Color(66, 30, 15), new Color(25, 7, 26), |
|
24 new Color(9, 1, 47), new Color(4, 4, 73), |
|
25 new Color(0, 7, 100), new Color(12, 44, 138), |
|
26 new Color(24, 82, 177), new Color(57, 125, 209), |
|
27 new Color(134, 181, 229), new Color(211, 236, 248), |
|
28 new Color(241, 233, 191), new Color(248, 201, 95), |
|
29 new Color(255, 170, 0), new Color(204, 128, 0), |
|
30 new Color(153, 87, 0), new Color(106, 52, 3)) |
|
31 |
|
32 // the viewer panel |
|
33 class Viewer(width: Int, height: Int) extends JPanel { |
|
34 val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) |
|
35 clearCanvas(Color.black) |
|
36 |
|
37 override def paintComponent(g: Graphics) = |
|
38 g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) |
|
39 |
|
40 override def getPreferredSize() = |
|
41 new Dimension(width, height) |
|
42 |
|
43 def clearCanvas(color: Color) = { |
|
44 for(x <- 0 to width - 1; |
|
45 y <- 0 to height - 1) canvas.setRGB(x, y, color.getRGB()) |
|
46 repaint() |
|
47 } |
|
48 |
|
49 } |
|
50 |
|
51 def openViewer(width: Int, height: Int) = { |
|
52 val frame = new JFrame("XYPlane") |
|
53 val viewer = new Viewer(width, height) |
|
54 frame.add(viewer) |
|
55 frame.pack() |
|
56 frame.setVisible(true) |
|
57 frame.setResizable(false) |
|
58 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) |
|
59 viewer |
|
60 } |
|
61 |
|
62 val W = 900 |
|
63 val H = 800 |
|
64 val black = Color.black |
|
65 val viewer = openViewer(W, H) |
|
66 |
|
67 |
|
68 def pixel(x: Int, y: Int, color: Color) = |
|
69 viewer.canvas.setRGB(x, y, color.getRGB()) |
|
70 |
|
71 |
|
72 def mandelbrot(start: Complex, end: Complex, level: Int) : Unit = { |
|
73 viewer.clearCanvas(black) |
|
74 |
|
75 val delta_x = (end.a - start.a) / W |
|
76 val delta_y = (end.b - start.b) / H |
|
77 |
|
78 for (y0 <- (0 until H).par) { |
|
79 for (x0 <- (0 until W).par) { |
|
80 |
|
81 val c = start + Complex(x0 * delta_x, y0 * delta_y) |
|
82 |
|
83 def iters(z: Complex, it: Int) : Color = { |
|
84 if (it < level && z.abs < 2) iters(z * z + c, it + 1) else |
|
85 if (it == level) black else colours(it % 16) |
|
86 } |
|
87 |
|
88 pixel(x0, y0, iters(Complex(0, 0), 0)) |
|
89 } |
|
90 viewer.updateUI() |
|
91 } |
|
92 } |
|
93 |
|
94 // Examples |
|
95 //========== |
|
96 |
|
97 //for measuring time |
|
98 def time_needed[T](code: => T) = { |
|
99 val start = System.nanoTime() |
|
100 code |
|
101 val end = System.nanoTime() |
|
102 (end - start) / 1.0e9 |
|
103 } |
|
104 |
|
105 |
|
106 // example 1 |
|
107 val exa1 = Complex(-2.0, -1.5) |
|
108 val exa2 = Complex( 1.0, 1.5) |
|
109 |
|
110 time_needed(mandelbrot(exa1, exa2, 1000)) |
|
111 |
|
112 // ehxample 2 |
|
113 val exb1 = Compylex(-0.37465401, 0.659227668) |
|
114 val exb2 = Complex(-0.37332410, 0.66020767) |
|
115 |
|
116 time_needed(mandelbrot(exb1, exb2, 1000)) |
|
117 |
|
118 // example 3 |
|
119 val exc1 = Complex(0.435396403, 0.367981352) |
|
120 val exc2 = Complex(0.451687191, 0.380210061) |
|
121 |
|
122 time_needed(mandelbrot(exc1, exc2, 1000)) |
|
123 |
|
124 // some more computations with example 3 |
|
125 val delta = (exc2 - exc1) * 0.0333 |
|
126 |
|
127 time_needed( |
|
128 for (i <- (0 to 12)) |
|
129 mandelbrot(exc1 + delta * i, |
|
130 exc2 - delta * i, 1000)) |
|
131 |
|
132 |
|
133 |