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 |