Exploring the Fractal Geometry of the Mandelbrot Set |
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.
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).
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.
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); } } }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;
The deadline is midnight, Saturday June 4. 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.
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.
Explorer 5: Animation. For the final stage of this year's Explorer project you are to produce a sequence of gif images that zoom in on a point of your choosing. Once completed, you will zip up these images into a file and send them to handin by the deadline. I will create a Flash video from your images and mount them in the ACES Fractal Archive. Click on the image to the right to view a sample Flash video created from the script: ElephantValleyCuspTrigonometric.exp
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 200 and 500 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 1000+).
Task.
Framework: The Palette Class. Rather than simply ignoring pixels for c value that escape the M-Set, colour can be used to reveal information about the orbit. A common colouring strategy is to use the number of iterations in the orbit it took to escape as an index into a palette of the users design.
![]() |
![]() |
---|
Assuming an array of colours is available, any pixel for which its corresponding c value escaped the M-Set, is drawn in a color selected from the palette using the number of iterations as the index into the array. Use of the modulus operator % is useful to prevent ArrayIndexOutOfBoundsExceptions from occuring in situations where the bailout value exceeds palette's size. BLACK remains the colour of choice for points inside the M-Set. This strategy is referred to as the Escape-Time Algorithm. Given that various strategies exist for developing a palette, this is the point in your project where the artist in you takes center stage.
ScepterValley (Monochrome) | ScepterValley (Grayscale) | ScepterValley (Trigonometric) |
---|---|---|
![]() |
![]() |
![]() |
Task.
To summarize:
Examine this Excel workbook to assist with a review of the basic transformations associated with the sine function (if the scroll bars do not function on a Mac, you'll simply have to type in some of the data). Ensuring the period was equal to the palette size would eliminate any unsightly borders as the lower and upper values of the sine wave would connect. With the amplitude and vertical translations set to 0.5, all that would be required to create different trigonometric palettes would be to randomly generate a value for the phase shift between 0 and the size of the palette for each of the three color streams.
Framework: The Mandelbrot Set (with Save).
You have reached the stage for which concepts examined in preliminary studies can be integrated into your Framework application.
Your most recent study considered the behaviour of a single `c` value in the context of the feedback formula `z_(i+1) larr z_i^2+c`. Those `c` values that orbited inward were determined to lie within the Mandelbrot Set (M-Set) and those that spiraled outward, escaped the M-Set.
For this stage, you are asked to provide a plot of ALL `c` values (mapped from pixels based on screen coordinates ) within a square subset of the Argand Plane bounded by,
`[xmin,xmax,ymin,ymax]=[-2.25,0.75,-1.5,1.5]`
Pixel coordinates corresponding to `c` values that lie within the M-Set (ie., do not escape) are to be coloured black. Those that do escape are not plotted.
Task.
Explorer 1: The Driver.
In this stage we code the driver for the Explorer application. To prepare for the eventual reading of .exp scripts, a menu bar is added enabling (for now) the limited ability to Open a file and Exit the application.
Task.
The Mandelbrot Class. The Mandelbrot Set consists of the set of points, c, in the Complex (Argand)
Plane, whose orbit under the iterative formula, z ← z2+c never
reaches a magnitude greater than 2.0 (given sufficient opportunity),
where z starts
at 0+0i.
Task.
![]() |
![]() |
---|
The ComplexNumber Class. The Mandelbrot Set is based on complex numbers (a.k.a. imaginary numbers - you remember these from your study of the roots of quadratic equations for which the corresponding parabolas did not have x-intercepts). To condition you for the authoring of a ComplexNumber class on your own, we will develop a similar class together. Create a project by the name of RealNumberTest and drop in this driver. From observation, note that the successful execution of this project requires the development of a RealNumber class. This class appears to formally encapsulate a real number and offers a constructor, a few arithmetic methods and a toString method. Collaborative development of a RealNumber class should yield the output below.
The ComplexNumber Class. Using the driver, ComplexNumberTest.java, develop the ComplexNumber class defined in the UML diagram below. Run the project and confirm that your results match the output below.
ComplexNumber UML | ComplexNumberTest Output |
---|---|
![]() |
![]() |