Click here to Skip to main content
Click here to Skip to main content

Mandelbrot in C# and Windows forms

By , 31 Jul 2006
 

Introduction

This project written in C# allows the user to interactively explore the Mandelbrot set, and to keep the pictures generated as well as the coordinates of the view Window. The picture can be saved as a bitmap file, or copied to the clipboard. The view Window information can be saved to an XML file or copied to the clipboard.

Description of the user interface

When the program starts the main image has not been calculated yet. To have an overview of the Mandelbrot set, simply click the "Calculate" button located in the top toolstrip. Besides the main image, two panels are located in the top right of the window, "Preview" and "Bird eye".

Preview

The preview provides for a small image of the current view on the Mandelbrot set. The preview is always up to date, unlike the main picture, which, for performance reasons, needs a click on "Calculate" to be refreshed.

Bird eye

The bird eye gives an overview of the Mandelbrot set, and never changes. The mouse can be dragged on the Bird eye Window to select a new view Window. At this time the preview is updated, as well as the numerical values of the view Window. The main picture still requires a click on "Calculate" to reflect the changes. The bird eye is useful to zoom out, or to quickly zoom to another part of the set.

Main picture

It shows the image of the view Window, automatically scaled to fit inside the available space. The user can drag the mouse on the main picture to select a new view Window. Unlike for the bird eye, the new view Window, is relative to the currently selected view Window.

Numerical values

The top of the Window has a number of controls to edit numerical values. Here is a description of those.

Image size

The "Width" and "Height" give the size in pixels of the bitmap created by the Mandelbrot routines. To avoid strange looking images, the ratio between "Width" and "Height" must be the same as for the view Window on the Mandelbrot set. The checkbox "Auto adjust" lets the program change the "Height" value when the user changes the view Window (if needed). As the user can manually change the values of "Width" and "Height", the button "Adjust ratio" forces the update of the "Height" value. A comment gives the current ratio, for those who would want to do some calculations by hand.

Mandelbrot set Window

XMin, XMax, YMin and YMax define the view Window on the Mandelbrot set. The values can be edited manually, the other controls are automatically updated. A comment shows the ratio of the current view Window.

Calculation parameters

Maximum iteration count sets the number of iterations after which a given point is classified as being outside the Mandelbrot set. It can be interesting to try a few different values. Note the image generated is 24 bits per pixels, so the max iteration count will give similar results modulo 256.

Toolstrip commands

  • Calculate: regenerate the main picture
  • Save: saves the main picture to a file, as a Windows bitmap. Also saves the parameters into an XML file, carrying the same name
  • Reset: restores all the parameters to default values
  • Copy: copies the main picture to the clipboard
  • Copy parameters: copies the parameters to the clipboard

Some code

The bitmap generation is done as follows:

public System.Drawing.Bitmap GetBitmap(
    int pImageWidth,
    int pImageHeight,
    double pXMin,
    double pXMax,
    double pYMin,
    double pYMax,
    int pMaxIterationCount)
{
    try
    {
        int i = 0;
        int j = 0;
        int[][] lValues = new int[pImageHeight][];

        for (i = 0; i < pImageHeight; i++)
        {
            lValues[i] = new int[pImageWidth];
        }

        CalculateLevels(
            lValues,
            pImageWidth,
            pImageHeight,
            pXMin,
            pXMax,
            pYMin,
            pYMax,
            pMaxIterationCount);

        System.Drawing.Bitmap lBitmap = new System.Drawing.Bitmap
        (pImageWidth, pImageHeight, 
        System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        byte lRed = 0;
        byte lGreen = 0;
        byte lBlue = 0;
        int lPixelByteCount = 4;
        int lAlphaPos = 3;
        int lRedPos = 2;
        int lGreenPos = 1;
        int lBluePos = 0;
        int lPixelCount = pImageHeight * pImageWidth;
        int lPixelPos = 0;

        m_ProgressBar.Minimum = 0;
        m_ProgressBar.Maximum = lPixelCount;
        m_ProgressBar.Value = 0;

        System.Drawing.Imaging.BitmapData lBitmapData = 
                new System.Drawing.Imaging.BitmapData();

        lBitmap.LockBits(
            new System.Drawing.Rectangle(
            0,
            0,
            pImageWidth,
            pImageHeight),
            System.Drawing.Imaging.ImageLockMode.WriteOnly,
            System.Drawing.Imaging.PixelFormat.Format32bppArgb,
            lBitmapData);

        unsafe
        {
            System.Byte* lStartPtr = (System.Byte*)((void*)lBitmapData.Scan0);
            int lEndToStart = lBitmapData.Stride - 
                    pImageWidth * lPixelByteCount;
            System.Byte* lPtr = lStartPtr;

            for (j = 0; j < pImageHeight; j++)
            {
                for (i = 0; i < pImageWidth; i++)
                {
                    GetColorFromLevel(
                        lValues[j][i],
                        pMaxIterationCount,
                        out lRed,
                        out lGreen,
                        out lBlue);

                    lPtr[lAlphaPos] = 255;
                    lPtr[lRedPos] = lRed;
                    lPtr[lGreenPos] = lGreen;
                    lPtr[lBluePos] = lBlue;

                    lPtr += lPixelByteCount;
                    lPixelPos++;
                }

                lPtr += lEndToStart;

                m_ProgressBar.Value = lPixelPos;
                System.Windows.Forms.Application.DoEvents();
            }
        }

        lBitmap.UnlockBits(lBitmapData);

        return lBitmap;
    }
    catch
    {
        return null;
    }
}            

This function gets an array of values describing the view Window on the Mandelbrot set. It then creates a bitmap of the appropriate size, locks it and fills it after inferring colors from the initial array.

The color inference

A very simple algorithm is used here. The potential is compared to the maximum available. The ratio is then divided into 8 intervals that will progress as follows: Black to Red - Red to Yellow - Yellow to Green - Green to Cyan - Cyan to Blue - Blue to Magenta - Magenta to White - White to Black

Sample XML file

<?xml version="1.0" encoding="utf-16"?>
<State xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <XMin>-0.040557444936069775</XMin>
  <XMax>-0.040016368521333778</XMax>
  <YMin>0.98423178672189038</YMin>
  <YMax>0.98491968869265967</YMax>
  <ImageWidth>1200</ImageWidth>
  <ImageHeight>1526</ImageHeight>
  <MaxIterationCount>100</MaxIterationCount>
</State>      

Sample images calculated with this piece of software

Note: These images have been scaled down to meet size requirements.

Known issues

When the user clicks on the NumericUpDown control to increase or decrease the values of XMin, XMax, YMin or YMax, the preview is updated. An exception is thrown when the user keeps the mouse down. After a number of milliseconds, the control starts speeding up, and the NumericUpDown control complains about some internal timer. I did not deem it appropriate to spend time fixing this problem.

References

For those interested in digging deeper into fractals, I recommend the book "The science of fractal images" written by Barnsley, Devaney, Mandelbrot (himself) Peitgen, Saupe and Voss. My copy was published in 1988 at Springer Verlag.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Pierre Leclercq
Software Developer (Senior)
France France
Member
Being a software developer since 1994, I have
worked in the US (DC area), and in France
(Paris area), on various types of projects
(device drivers, Imaging, Financial apps and
database-driven web sites).
 
My favourite technical interests are C++,
C#, .net, WPF, image analysis, GPUs, GPGPU,
AI, and compilers.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralI can learn very much from this source code.memberbuare2 Jan '13 - 14:49 
Big Grin | :-D Nice professionally!~~
GeneralThank you!memberStonie9 Dec '06 - 2:04 
The images produced are stunning! thanks for sharing this. Big Grin | :-D
GeneralRe: Thank you!memberPierre Leclercq10 Dec '06 - 8:53 
You're welcome!
GeneralFantastic!memberobsgef1 Aug '06 - 0:18 
I remember back in highschool, which is almost twenty years ago, I programmed a Mandelbrot set with turbo pascal on an Olivetti M24 computer. I had to attach a sheet of paper with the note "Do not switch off this computer!" to the monitor in order to allow the system to calculate an orange monochrome appelman with a ridiculous screen resolution.
 
I like to play with your tool, it's like discovering a strange world. Very nice tool!
GeneralRe: Fantastic!memberPierre Leclercq10 Dec '06 - 8:55 
obsgef wrote:
Very nice tool

 
Thanks!
GeneralVery nicememberShawn Poulson31 Jul '06 - 5:38 
I like it. I kinda wished the output would be displayed as it is calculated and full resolution. Pretty cool, regardless. Reminds me of the old Fractint.
 
---
Shawn Poulson
spoulson@explodingcoder.com

GeneralRe: Very nicememberPierre Leclercq31 Jul '06 - 6:51 
Thanks.
 
You're right, Fractint was running this way, calculating the image square by square.
That was back when PCs needed a separate coprocessor to do floating point arithmetics Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 31 Jul 2006
Article Copyright 2006 by Pierre Leclercq
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid