Page 2 of 5
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 inital 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. First we need to create a WriteableBitmap ready to draw on.
WriteableBitmap drawSet(Rect area)
int PixelHeight = (int) image1.Height;
int PixelWidth = (int) image1.Width;
WriteableBitmap wbmap = new
96, 96, PixelFormats.Bgra32, null);
Using a dpi specification of 96 makes the bitmap display at 100% size in an Image control of the same size. In this case the size of the bitmap is determined by the size of the Image control but this can be changed if you need a different size. If you need to know more about WriteableBitmaps then see: WriteableBitmap.
Although the WriteableBitmap has "Writeable" in its name the way that this works is that you first create a byte array containing the new pixel data and store this in the bitmap. So first we need an array of the correct size:
byte pixels = new byte[
PixelHeight * PixelWidth * BytesPerPixel];
The "stride" is simply the number of bytes in the array that correspond to a single "row" or horizontal line of pixels in the bitmap - which in this case is just:
int s = PixelWidth * BytesPerPixel;
Most of the difficulties of the calculation is in converting between different co-ordinate systems. In this particular situation we have three co-ordinate systems to contend with. The first is the mapping of the linear 1D array to the 2D pixels of the bitmap. Normally in building up a plot you would create a nested pair of for loops that scanned the rows and columns taking each pixel in turn, e.g. the pixel at i,j. You would then use a storage mapping function to convert the i,j co-ordinate into the location of the pixel as stored in the byte array.
That is the data for pixel at i,j is stored in
notice that its i times the bytes it takes to store a pixel and j times the bytes it takes to store a row of pixels. Note the pixel data is at the BytesPerPixel locations starting at the indicated location.