Components Notebook
Home

Notebooks
C#
C++
Agile Hacker
Hardware
Photos

Book Reviews

Fractals in C#

This example program is for generating Mandelbrot and Julia sets. The purpose for this example is to learn a few things about working with bitmap graphics in C# and .NET.

Last changed: Sept 12, 2006.

The asynchronous drawing technique used here is based on the code from the article, Draw Asynchronously With .NET by Bill Storage, in the Aug 2002 issue of Visual Studio Magazine.

Download the source code: Graphics.zip

An earlier version that works with Visual Studio 2003: Graphics2003.zip

An even earlier version, probably done with even an older version of Visual Studio: Fractals.zip

This version contains all the tweeks I have made since the previous version which was done in 2002. The user interface was also regenerated using Visual Studio 2005. If you are using Visual Studio 2005, open up the Graphics.sln file and start playing with the code. For other development environments, create your own project files to compile the .cs files. The files in the Fractals directory should be compiled as a class library. The files in the DrawFractals directory should be compiled as a Windows application, which references the library compiled from the Fractals directory.

Using the program

Click the Draw button to create the Mandelbrot set.

To center on the region of interest, click the left mouse button on the point which you want to become the center.

Click the Zoom In button a few times.

Alternatively, draw a rectangle around the area you would like to zoom in on.

Select a C value for the Julia set by clicking on the Mandelbrot set. Selecting a point along the edge of one of the cardiod shapes works best.

Select Julia from the Draw menu, to draw the Julia set for the C value selected in the previous step

Adjust the Zoom and number of iterations to obtain an interesting Julia set. If you can't find anything interesting, you need to go back to the Mandelbrot set to select a new value for C.

Return to the Mandelbrot set by selecting Mandelbrot from the Draw menu.

Saving your art

From the File menu, you can save the image or the parameters. The parameters are serialized as XML.

Some screen shots and samples

Click image to see a larger version:

Program description

The graphics in this program take a while to generate, so multi-threaded code is used. This allows user interaction with the program while it is busy calculating and generating the graphics. Single threaded code would generate the graphics more quickly, but would give the appearance of a hung program, until the image is completely generated and displayed. We could update the display after each pixel is generated, but this would greatly slow down the program. By generating and displaying the image in strips, you get feedback as the image is being generated, but not excessive slowdown. If you have a multi-processor or multi-core computer, you might want to modify the program to generate multiple strips simultaneously. If you have a fast computer, you may want to increase the strip width.

A picture box is used to display the graphics. The picture box has two bitmaps associated with it, the image and background image. The background image is used for displaying the fractal images. The image is used for displaying select rectangles when using the mouse to select a portion of the image to zoom in on.

A FractalSet base class is defined which contains the code common for both Mandelbrot and Julia sets. To generate an image the public Start method is called, with a picture box passed as its parameter. After setting up the mouse handlers for the picture box, this method calls the private Start method, which sets up the graphics objects and worker thread. The CreateGraphicsObjects method creates the two bitmaps in the picture box. The worker thread executes the Draw method.

The Draw method creates an UpdateImageDelegate, which is used to transfer the bitmap strips to the picture box using the thread which created it.

UpdateImageDelegate UpdateDelegate = new UpdateImageDelegate( UpdateImage )

The UpdateImage method is invoked using the picture box BeginInvoke method.

itsPictureBox.BeginInvoke( UpdateDelegate, args )

The arguments for the UpdateImage method are placed in the args array which is passed to BeginInvoke. The UpdateImage method, copies the strip bitmap to a portion of the picture box background image.

The Draw method contains three nested loops. The outer loop iterates over the number of strips, which the image has been split into. If you were going to convert this program for enhanced speed on a multi-processor system you would send each of these strips to a worker thread instead of looping over them. The next loop in, iterates over the columns that make up the strip, essentially the bitmap x coordinate. The inner loop iterates over each pixel that makes up the column, essentially the bitmap y coordinate. The formulas inside these loops are to transform the bitmap x, y coordinates to the real and imaginary coordinates on the complex plane. This gives you the C value for use in the complex number equation Z(n) = Z(n-1)^2 +C. The GetColorVal method iterates this equation. By making GetColorVal a virtual method, the code for calculating the color is placed in the subclasses, since this is all that is different between generating Mandelbrot & Julia sets.


wburris at telusplanet dot net