progs/mandelbrot.scala
changeset 186 f211d9cb856e
parent 174 90e0b1cc460b
child 187 4d300409f2fe
equal deleted inserted replaced
185:5ab45f3fee1c 186:f211d9cb856e
     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