4 import java.awt.Graphics2D  | 
     4 import java.awt.Graphics2D  | 
     5 import java.awt.image.BufferedImage  | 
     5 import java.awt.image.BufferedImage  | 
     6 import javax.swing.JFrame  | 
     6 import javax.swing.JFrame  | 
     7 import javax.swing.JPanel  | 
     7 import javax.swing.JPanel  | 
     8 import javax.swing.WindowConstants  | 
     8 import javax.swing.WindowConstants  | 
         | 
     9 import scala.language.implicitConversions      | 
     9   | 
    10   | 
    10 // complex numbers  | 
    11 // complex numbers  | 
    11 case class Complex(val a: Double, val b: Double) {  | 
    12 case class Complex(val re: Double, val im: Double) {  | 
    12     // represents the complex number a + b * i  | 
    13   // represents the complex number re + im * i  | 
    13     def +(that: Complex) = Complex(this.a + that.a, this.b + that.b)  | 
    14   def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)  | 
    14     def -(that: Complex) = Complex(this.a - that.a, this.b - that.b)  | 
    15   def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)  | 
    15     def *(that: Complex) = Complex(this.a * that.a - this.b * that.b,  | 
    16   def *(that: Complex) = Complex(this.re * that.re - this.im * that.im,  | 
    16                                    this.a * that.b + that.a * this.b)  | 
    17                                  this.re * that.im + that.re * this.im)  | 
    17     def *(that: Double) = Complex(this.a * that, this.b * that)  | 
    18   def *(that: Double) = Complex(this.re * that, this.im * that)  | 
    18     def abs() = Math.sqrt(this.a * this.a + this.b * this.b)  | 
    19   def abs() = Math.sqrt(this.re * this.re + this.im * this.im)  | 
    19 }  | 
    20 }  | 
    20   | 
    21   | 
    21 // some customn colours  | 
    22 object i extends Complex(0, 1)  | 
         | 
    23   | 
         | 
    24 implicit def double2complex(re: Double): Complex = Complex(re, 0)  | 
         | 
    25   | 
         | 
    26 // some customn colours for the "sliding effect"  | 
    22 val colours = List(  | 
    27 val colours = List(  | 
    23     new Color(66, 30, 15),    new Color(25, 7, 26),  | 
    28   new Color(66, 30, 15),    new Color(25, 7, 26),  | 
    24     new Color(9, 1, 47),      new Color(4, 4, 73),  | 
    29   new Color(9, 1, 47),      new Color(4, 4, 73),  | 
    25     new Color(0, 7, 100),     new Color(12, 44, 138),  | 
    30   new Color(0, 7, 100),     new Color(12, 44, 138),  | 
    26     new Color(24, 82, 177),   new Color(57, 125, 209),  | 
    31   new Color(24, 82, 177),   new Color(57, 125, 209),  | 
    27     new Color(134, 181, 229), new Color(211, 236, 248),  | 
    32   new Color(134, 181, 229), new Color(211, 236, 248),  | 
    28     new Color(241, 233, 191), new Color(248, 201, 95),  | 
    33   new Color(241, 233, 191), new Color(248, 201, 95),  | 
    29     new Color(255, 170, 0),   new Color(204, 128, 0),  | 
    34   new Color(255, 170, 0),   new Color(204, 128, 0),  | 
    30     new Color(153, 87, 0),    new Color(106, 52, 3))  | 
    35   new Color(153, 87, 0),    new Color(106, 52, 3))  | 
    31   | 
    36   | 
    32 // the viewer panel  | 
    37 // the viewer panel with a canvas  | 
    33 class Viewer(width: Int, height: Int) extends JPanel { | 
    38 class Viewer(width: Int, height: Int) extends JPanel { | 
    34     val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)  | 
    39   val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)  | 
    35     clearCanvas(Color.black)  | 
    40     | 
         | 
    41   override def paintComponent(g: Graphics) =   | 
         | 
    42     g.asInstanceOf[Graphics2D].drawImage(canvas, null, null)  | 
         | 
    43     | 
         | 
    44   override def getPreferredSize() =   | 
         | 
    45     new Dimension(width, height)  | 
    36   | 
    46   | 
    37     override def paintComponent(g: Graphics) =   | 
    47   def clearCanvas(color: Color) = { | 
    38       g.asInstanceOf[Graphics2D].drawImage(canvas, null, null)  | 
    48     for (x <- 0 to width - 1; y <- 0 to height - 1)   | 
    39   | 
    49       canvas.setRGB(x, y, color.getRGB())  | 
    40     override def getPreferredSize() =   | 
    50     repaint()  | 
    41        new Dimension(width, height)  | 
    51   }    | 
    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 }  | 
    52 }  | 
    50   | 
    53   | 
    51 def openViewer(width: Int, height: Int) = { | 
    54 // initialising the viewer  | 
    52     val frame = new JFrame("XYPlane") | 
    55 def openViewer(width: Int, height: Int) : Viewer = { | 
    53     val viewer = new Viewer(width, height)  | 
    56   val frame = new JFrame("XYPlane") | 
    54     frame.add(viewer)  | 
    57   val viewer = new Viewer(width, height)  | 
    55     frame.pack()  | 
    58   frame.add(viewer)  | 
    56     frame.setVisible(true)  | 
    59   frame.pack()  | 
    57     frame.setResizable(false)  | 
    60   frame.setVisible(true)  | 
    58     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)  | 
    61   frame.setResizable(false)  | 
    59     viewer  | 
    62   frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)  | 
         | 
    63   viewer  | 
    60 }  | 
    64 }  | 
    61   | 
    65   | 
    62 val W = 900  | 
    66 // some hardcoded data  | 
    63 val H = 800   | 
    67 val W = 900   // width  | 
         | 
    68 val H = 800   // height  | 
    64 val black = Color.black  | 
    69 val black = Color.black  | 
    65 val viewer = openViewer(W, H)  | 
    70 val viewer = openViewer(W, H)  | 
    66   | 
    71   | 
    67   | 
    72 // drawing a pixel on the canvas  | 
    68 def pixel(x: Int, y: Int, color: Color) =   | 
    73 def pixel(x: Int, y: Int, color: Color) =   | 
    69   viewer.canvas.setRGB(x, y, color.getRGB())  | 
    74   viewer.canvas.setRGB(x, y, color.getRGB())  | 
         | 
    75   | 
         | 
    76   | 
         | 
    77 // calculating the number of iterations using lazy streams  | 
         | 
    78 //   the iteration goes on for a maximum of max steps,  | 
         | 
    79 //   but might leave early when the pred is satisfied  | 
         | 
    80 def iterations(c: Complex, max: Int) : Int = { | 
         | 
    81   def next(z: Complex) = z * z + c      | 
         | 
    82   def pred(z: Complex) = z.abs < 2    // exit condition  | 
         | 
    83   Stream.iterate(0.0 * i, max)(next).takeWhile(pred).size  | 
         | 
    84 }  | 
         | 
    85   | 
         | 
    86 // main function   | 
         | 
    87 def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = { | 
         | 
    88   viewer.clearCanvas(black)  | 
    70     | 
    89     | 
         | 
    90   // deltas for each grid step   | 
         | 
    91   val d_x = (end.re - start.re) / W  | 
         | 
    92   val d_y = (end.im - start.im) / H  | 
         | 
    93      | 
         | 
    94   for (y <- (0 until H).par) { | 
         | 
    95     for (x <- (0 until W).par) { | 
         | 
    96       | 
         | 
    97      val c = start +   | 
         | 
    98       (x * d_x + y * d_y * i)  | 
         | 
    99      val iters = iterations(c, max)   | 
         | 
   100      val col =   | 
         | 
   101        if (iters == max) black   | 
         | 
   102        else colours(iters % 16)  | 
    71   | 
   103   | 
    72 def mandelbrot(start: Complex, end: Complex, level: Int) : Unit = { | 
   104      pixel(x, y, col)  | 
    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)) { | 
         | 
    79     for (x0 <- (0 until W)) { | 
         | 
    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     }  | 
   105     }  | 
    90     viewer.updateUI()  | 
   106     viewer.updateUI()  | 
    91   }  | 
   107   }     | 
    92 }  | 
   108 }  | 
    93   | 
   109   | 
    94 // Examples  | 
   110 // Examples  | 
    95 //==========  | 
   111 //==========  | 
    96   | 
   112   | 
   102   (end - start) / 1.0e9  | 
   118   (end - start) / 1.0e9  | 
   103 }  | 
   119 }  | 
   104   | 
   120   | 
   105   | 
   121   | 
   106 // example 1  | 
   122 // example 1  | 
   107 val exa1 = Complex(-2.0, -1.5)  | 
   123 val exa1 = -2.0 + -1.5 * i  | 
   108 val exa2 = Complex( 1.0,  1.5)  | 
   124 val exa2 =  1.0 +  1.5 * i  | 
   109   | 
   125   | 
   110 time_needed(mandelbrot(exa1, exa2, 1000))  | 
   126 time_needed(mandelbrot(exa1, exa2, 1000))  | 
   111   | 
   127   | 
   112 // example 2  | 
   128 // example 2  | 
   113 val exb1 = Complex(-0.37465401, 0.659227668)  | 
   129 val exb1 = -0.37465401 + 0.659227668 * i  | 
   114 val exb2 = Complex(-0.37332410, 0.66020767)  | 
   130 val exb2 = -0.37332410 + 0.66020767 * i  | 
   115   | 
   131   | 
   116 time_needed(mandelbrot(exb1, exb2, 1000))  | 
   132 //time_needed(mandelbrot(exb1, exb2, 1000))  | 
   117   | 
   133   | 
   118 // example 3  | 
   134 // example 3  | 
   119 val exc1 = Complex(0.435396403, 0.367981352)  | 
   135 val exc1 = 0.435396403 + 0.367981352 * i  | 
   120 val exc2 = Complex(0.451687191, 0.380210061)  | 
   136 val exc2 = 0.451687191 + 0.380210061 * i  | 
   121   | 
   137   | 
   122 //time_needed(mandelbrot(exc1, exc2, 1000))  | 
   138 //time_needed(mandelbrot(exc1, exc2, 1000))  | 
   123   | 
   139   | 
   124 // some more computations with example 3  | 
   140 // some more computations with example 3  | 
         | 
   141   | 
   125 val delta = (exc2 - exc1) * 0.0333  | 
   142 val delta = (exc2 - exc1) * 0.0333  | 
   126   | 
   143   | 
   127 time_needed(  | 
         | 
   128   for (i <- (0 to 12))   | 
         | 
   129      mandelbrot(exc1 + delta * i,   | 
         | 
   130                 exc2 - delta * i, 1000))  | 
         | 
   131   | 
         | 
   132 val exc1 = Complex(0.435396403, 0.367981352)  | 
         | 
   133 val exc2 = Complex(0.451687191, 0.380210061)  | 
         | 
   134   | 
         | 
   135 //time_needed(mandelbrot(exc1, exc2, 1000))  | 
         | 
   136   | 
         | 
   137 // some more computations with example 3  | 
         | 
   138 val delta = (exc2 - exc1) * 0.0333  | 
         | 
   139   | 
   144   | 
   140 time_needed(  | 
   145 time_needed(  | 
   141   for (i <- (0 to 12))   | 
   146   for (n <- (0 to 12))   | 
   142      mandelbrot(exc1 + delta * i,   | 
   147      mandelbrot(exc1 + delta * n,   | 
   143                 exc2 - delta * i, 1000))  | 
   148                 exc2 - delta * n, 100))   | 
         | 
   149   | 
         | 
   150 /*  | 
         | 
   151 time_needed(  | 
         | 
   152   for (n <- (0 to 12))   | 
         | 
   153      mandelbrot(exc1 + delta * n,   | 
         | 
   154                 exc2 - delta * n, 1000))  | 
         | 
   155 */  | 
   144   | 
   156   | 
   145   | 
   157   | 
   146   | 
         |