progs/mandelbrot.scala
changeset 124 c45d3cd9a749
child 136 c08ba57a7f53
equal deleted inserted replaced
123:556cd74cbba9 124:c45d3cd9a749
       
     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