Exploring the Fractal Geometry of the Mandelbrot Set
  1. Automated Image Sequencer. The time has come for you to take your place in ACES history and join the ranks of those who have gone before you. All ICS3Mers are required to submit the final version of their Platform project that will yield an animated entry into our Fractal Archive. As you can see, your name is already there. Last year's was the weakest effort as you can see by the number of students whose name appears, but no video follows. These students bombed the exam. To avoid a similar fate, do a good job with this last stage.

    There are a number of careful considerations that must be made in order to produce a good animation. Look at this example. This is a poor offering for a host of reasons that include: a zoom factor that is too high (0.50-you'll likely prefer a value between 0.90 and 0.99 to be smooth), at 30 frames, it's too short (between 150 and 200 are required to keep the viewer engaged), and at deeper depths there weren't enough iterations to provide the necessary detail (you'll probably want to be between 500 and 1000).

    A good animation will synchronize smooth manipulations of both scale and position. However, since we're only able to devote one class session to this development, we'll focus exclusively on changing scale and work with a fixed position. An awkward jump from the default center at -0.75+0i to the centre of your zoom sequence ca nbe avoided by starting with a very large domain similar to the grapihic to the right (this will add some suspense as well!). Note: Inspired explorers can choose to remain after class and I will discuss the position considerations. Enough talk, let's begin.

    1. Using your manual Mouse Zoom capabilities, dig deep into the M-Set, identifying the Complex coordinates of a target destination for your video sequence. To assist this process, you should report the corresponding Complex coordinates of the mouse click to the Console Window along the way. One of the interesting features of any video is how deep it actually penetrates the Set.

      This begs the question, "How deep can we go?". After reflection you realize it would depend on the domain and range having 400 (or whatever dimension your screen canvas is set to) different values to work with. If there are less than 400, rounding would yield two or more blocks of similarly coloured pixels, degrading your resolution. Now, since your domain and range are doubles, this is currently the limiting factor relating to the depth. Since the primitive double type has an accuracy of roughly 15 significant digits, when your domain approaches this value, you're about as deep as you can go. Consequently it would also be wise to report the domain to the Console Window so you can monitor your depth (for inspired Mandelbrot explorers, switching to the BigDouble class removes this restriction and you can go as deep as RAM will allow, but with obvious performance degradations).

    2. To your KeyPressed(KeyEvent em) method, you add code to initiate the creation of your sequence on the pressing of the v key. At this point make a call to your Content class's generateFrames() method,
        public void generateFrames() {
          int frames = 10;
          // Parameters: vCentreX, vCentreY, vDomain, vZoomFactor, frames
          mandelbrot.setVideoProperties(-0.1732986271032131, 1.0601239993629323, 30, 0.50, frames);
      
          zoomLevel = 1;
          Graphics g = this.getGraphics();
      
          for (int f = 0; f < frames; f++) {
            System.out.println("Drawing Frame:" + zoomLevel);
            drawMandelbrot(g);
            screenCapture();
            // Updates viewing parameters for the next frame: domain, leftBound, rightBound, bottomBound and topBound 
            mandelbrot.nextFrame();
            zoomLevel++;
            
          }
        }
      

      will produce a sequence of saved .jpg images to the root of your Platform project folder. Ultimately you should have between 100 and 270 frames in your video, but I recommend starting with 10 and a substantial zoom factor (50%) to work out the code. Only after it's appears to be working, increase the frames to the final number and set your zoom factor to just under 1.0 to enable smooth scaling.

    3. The drawMandelbrot(g) method introduced above is similar to the code you have in your paintComponent() method. Something fashioned after the following will suffice,

        public void drawMandelbrot(Graphics g) {
          Graphics2D g2 = (Graphics2D) g;
      
          // draw the fractal
          for (int c = 0; c < WIDTH; c++) {
            for (int r = 0; r < HEIGHT; r++) {
              // determine if that point is part of the set
              if (mandelbrot.isPartOfSet(c, r)) {
                g2.setColor(Color.BLACK);
              } else {
                g2.setColor(palette.getColor(fractal.iteration() % 256));
              }
              g2.drawLine(c, r, c, r);
            }
          }
      	
        }
      
    4. We will now bypass the Mandelbrot class with further enhancements and add resources directly to the Fractal class. First, you'll need something to house the coordinates of the fixed target of your zoom sequence. You could use an object of the Point2D.Double class, but I suggest you simply add the declaration below to your Fractal class,
        private double TARGET[] = new double [2];

      along with the instance fields,

      private double videoCentreX, videoCentreY, videoDomain, videoZoomFactor;
    5. Now you can add can add the bodies of the setVideoProperties() and nextFrame() methods to your Fractal Class that does the setup and update of the viewing parameters for each subsequent image.

    6. Of course you don't have to follow anything I've said above. I just ask you to submit original code that produces the results I need to stitch your sequence together into a video.

    The deadline is midnight, Tuesday June 1. All project source files and a sequence of up to 270 .jpgs are to be attached to your email to handin. Once I create and mount all your videos, I'll call for your recommendations for the three you think best reflect our efforts over the past month and showcase them on the SSD over the exam period.

 

  1. KeyListener. The ability to record your Mandelbrot investigations either as still photos or animated sequences, would make it very easy to share your discoveries with family and friends. In this stage you will do just that.

    Since we've already incorporated Mouse behaviour into this project, we'll attach your keyboard to the capability of recording your graphics canvas in .jpg format, amongst other features your imagination suggests. Look over the resources within the KeyListener interface and its associated KeyEvent class. As was the case in last stage, although all three methods are required, only the keyPressed(KeyEvent e) method requires a non-empty body. The strategy here is to obtain the keyCode of the KeyEvent object and using either a switch statement or if..else ladder, call various methods to perform the recording tasks. A method for saving of .jpgs can be adapted from the following, that will be triggered when the user presses the lowercase s key,

    public void screenCapture()	{
      try {
        Robot robot = new Robot();
        BufferedImage screenShot = robot.createScreenCapture
          (new Rectangle(3,29, WIDTH-6, HEIGHT-7));
        File file = new File(mandelbrot.getClassName().toLowerCase()
          +"_"+zoomLevel+".jpg");
        javax.imageio.ImageIO.write(screenShot, "JPG", file);
      } catch(Exception e) {
        System.out.println("Exception found: " + e);
      }
    }
    
    A secondary method that uses a loop to assist with the creation of multiple frames, synchronized with automated zooming in can provide the basis for assembling a zoom sequence into either an animated gif or Flash file.

  1. MouseListener. When you zoom in on the set of points that form an arc of a circle, they appear to straighten out. This is a hallmark of Euclidean geometry and Newton capitalized on it in a big way in developing the basis for Calculus. On the other hand, the most compelling reality of Fractal geometry is that zooming in on points outside the Set yields no similar simplification. At any level of magnification, the level of complexity remains the same. Modify your Content class to have it implement the MouseListener interface, thereby allowing the user to zoom in on the image with a left button click and zooming out with a right button click. So, to have your Content object enabled for mouse events, perform the following steps.

    1. Declare that your Content class implements the MouseListener interface
    2. Using the inherited java.awt.Component's addMouseListener(MouseListener ml) method, declare that your Content object is to be added to the list of objects that receive notification of Mouse events.
    3. Include bodies for the MouseListener methods. You can leave the bodies of all but the MouseClicked(MouseEvent e) method, empty.
    4. Add the method public void modifyBounds(int col, int row) to your Mandelbrot class that will accept the screen coordinates of the mouse hotpoint. This method will adjust the bounds array such that the hotpoint is at it's center and the domain and range are tighter.
    5. Issue a repaint() statement that will result in the system calling your paintComponent() to redraw set with the new bounds! Voilá: Zoom!

  2. NOTE: It may be helpful to report current bounds and domain to the console window.

  1. The Graphics Platform. We are now ready to map the results of our algorithmic investigations (UML diagram). Create a project called Platform, add Platform.java as your driver and integrate methods of your Mandelbrot class into the paintComponent() method.

  1. The Mandelbrot Class. The Mandelbrot Set consists of the set of points, c, in the Argand (Complex) Plane, whose orbits under the iterative formula, z ← z2+c never reach a magnitude greater than 2.0 (given sufficient opportunity), where z starts at 0+0i. Develop the project, MandelbrotTest, that uses this driver to exercise an instance of the Mandelbrot class defined in this UML diagram for various c values determined by their location in screen coordinates. Output will appear as follows,


  1. The Orbit Class. Using the driver, OrbitTest.java, develop an application to exercise an instance of the Orbit class defined in this UML diagram. Output starts as follows,


  1. The ComplexNumber Class. Using the driver, ComplexNumberTest.java, exercise your ComplexNumber class defined in this UML diagram. Output should be as follows,