Page 1 of 4
The Mandelbrot set is fun, but implementing a simple viewer in WPF can be a challenge.Here's a project to plot the Mandelbrot set and allow the user to zoom in on any area of interest.
The Mandelbrot set is fun but implementing a simple viewer in WPF can be a challenge. The reason is that WPF is essentially a vector graphics system and the natural way to think of plotting the Mandelbrot set is to plot pixels.If you would like some background reading on fractals and the Mandelbrot set in particular then see - Fractals
In this project we plot the Mandelbrot set and allow the user to zoom in on any area of interest. The zooming is done "live" in the sense that the area is recomputed rather than simply zooming in to a pre-computed image.
The general programming topics covered in this project include:
The Mandelbrot set
The actual Mandelbrot computation is very easy.
In fact it is this very simplicity that makes it so amazing that something so complex is the end product.
If you consider a small 2D region centred on (0,0) i.e. the origin, then a point (a,b) is in the Mandelbrot set if the iteration:
does not diverge to infinity where c=a+ib and z is a general complex number of the form x=x+iy.
(Recall that i is a number such that i2=-1).
To compute the Mandelbrot set all we do is start off with a number c and an initial value for z, usually 0, and then replace z by its square plus c.
This operation is repeated, generating a sequence of z values. Either z gets bigger and bigger, in the sense of moving away from the origin, or it doesn't. If it doesn't then it is in the Mandelbrot set.
Until .NET 4.0 our next problem would have been finding a good way of doing complex arithmetic in C#. However, in .NET 4.0 a Complex type was introduced and we can now simply create complex variables and do complex arithmetic more or less as written in the usual notation.
For more details see Not so complex numbers in C#.
The only real problem concerns deciding when the iteration has resulted in a value which is going off to infinity and when it has not. B
asically what we do is iterate a large number of times and if by then the value has not wandered outside of the circle of radius 2 centred on the origin then it probably isn’t going to wander off to infinity. (It can be proved that if any point does go outside of this circle then is most certainly does go on to infinity.)
Putting all this together we have the following algorithm:
- Set c to the x,y co-ordinates of the point you want to test
- Set z to zero
- Set count to zero
- Using the current values work out z = z2 + c
- if mod(z) > 2 then point goes to infinity and is not part of the Mandelbrot set
- Add one to count if it’s > 1000 then the point is still close to the origin after 1000 iterations and is part of the Mandelbrot set
- Repeat by going back to step 4 unless you have determined whether or not the point is in the Mandelbrot set.
Translating this into a function is fairly easy:
Int32 mandelbrot(Complex c)
Int32 count = 0;
Complex z = Complex.Zero;
while (count < 1000 && z.Magnitude < 4)
z = z * z + c;
To make this work we have to load a reference to the System.Numerics assembly. Right click on References in the Project Explorer window and select Add References. Also add:
to the start of the program.
There’s very little to add to the earlier comments about this function except the fact that it returns the value of count. If count equals 1000 then the point is in the Mandelbrot set and any other value gives you a measure of how quickly the point goes off to infinity.
The value of count is often used to colour the non-Mandelbrot points according to how fast they shoot off to infinity and we will return to this topic when we get to plotting the set.
Now that we have the function that computes what we want to plot, the next part of the project is all about displaying the result and allowing the user to zoom in on sections of the plot.
The program was developed in a stepwise fashion but to save the trouble of having to keep on explaining a revised version to I’m going to present each part complete with everything need to make the whole work even if it doesn’t make much sense until later.
Place button on the window and set its content to "Reset". Next place a Canvas panel on the window and an Image control with it. Set the Image control to 400 by 400. The XAML should read something like:
<Window usual generated attributes>
Canvas.Left="0" Canvas.Top="0" />
Width="75" Click="button1_Click" />
The key idea is that we are going to use a Rect struct to specify the area that is going to be plotted. Notice that the area to be plotted is specified using standard Cartesian, i.e. x,y, co-ordinates which correspond to a complex value by the usual z=x+iy relationship.
The rectangle being plotted will have to be available to other methods so we have to declare is as a property:
private Rect area= new Rect(
new Point(-2.4, -1.5),
new Point(0.8, 1.5));
This is initialised to an area that provides a good initial view of the Mandelbrot set - found by trial and error.
The initial display can be constructed as soon as the application is loaded so we might as well put a call to the method that does the plotting into the main window's constructor:
image1.Source = drawSet(area);
Now we have to write the drawSet method.