Recently I had some spare time, and used it to create a program to render the Mandelbrot Set fractal. It has been a very cool problem to write a quick application for. I want to share what I have learned in case someone else wants to build something similar or just wants to know how cool fractal images can be created. The program itself is written in C# with WPF. It will run faster if done in C, and I am not using any features for the image generation that WPF is necessary for. The reason I chose C# with WPF was that I wanted to get some practice with them before I start my new job.
The inclusion of any complex number C in the Mandelbrot set is determined by applying the following algorithm to that point: 1. Set a complex number Z to 0 2. Square Z and add C to it 3. Map Z to 2 dimensional space with the real component of Z as x and the imaginary component as y. Then test if the point (x, y) lies in a circle of radius > 2 with origin at 0. If it is not, C is not in the set 4. Go To 2
Technically, infinite repetition is required to determine whether a point is in the set, but it is possible to get a decent approximation by running the loop through a large number (my application uses 1000) of iterations. This assumption only breaks down at extremely high zoom levels.
In order to display the set as a 2 dimensional image, we map each point in the image to a complex number, with the x axis being the real component and the y axis as the imaginary.

Mandelbrot Set Without Coloring
The image created by just coloring what is or is not in the set is not very interesting. It just looks like a blob with other blobs attached to it; far from the cool colorful pictures that you will find online. In order to add more color, you need to bring in additional data. The two popular types of data used for this elaboration are the number of iterations necessary to prove a point is outside the set, and the distance between a point and the closest member of the set. My application uses the iterations method as it requires less math.
Here is the code for coloring a point based on its real/imaginary coordinates:
1 private Color getCoordColorEscape(double realCoord, double imaginaryCoord) 2 { 3 int i; 4 double zReal = 0; 5 double zImaginary = 0; 6 for (i = 0; i < _ESCAPE_ITERATIONS; i++) 7 { 8 if (zReal * zReal + zImaginary * zImaginary > (_ESCAPE_RADIUS_NORMAL * _ESCAPE_RADIUS_NORMAL)) 9 break; 10 double zRealTemp = zReal * zReal - zImaginary * zImaginary + realCoord; 11 zImaginary = 2 * zReal * zImaginary + imaginaryCoord; 12 zReal = zRealTemp; 13 } 14 if (i == _ESCAPE_ITERATIONS) 15 { 16 return Color.FromRgb(0, 0, 0); 17 } 18 else 19 { 20 return _gradiant.getColor(i, _gradiantPeriod); 21 } 22 }
In order to do the coloring I have a class designed to programmatically generate a gradient. It is constructed with a list of key colors and called with the value you wish to color and the period of the gradients cycle. In this rendering, the colors were Blue, White, Yellow, and Black and the period was 128 values per cycle of the gradient. The algorithm takes the iterations needed to escape, mods it by 128, and then based on the remaining value, it determines what transition the color lies in, and how far into that transition it is, and calculates an output color.
Here us the code for that class:
1 public class ColorGradiant 2 { 3 private List<Color> _keyColors; 4 private string _name; 5 public ColorGradiant(List<Color> keys, string name) 6 { 7 _keyColors = new List<Color>(keys); 8 _name = name; 9 } 10 11 public Color getColor(int value, int cyclePeriod) 12 { 13 //limit value to range of gradiant 14 value %= cyclePeriod; 15 int valuesPerTransition = (cyclePeriod / _keyColors.Count); 16 //select transition 17 int transition = value / valuesPerTransition; 18 Color startColor = _keyColors[transition]; 19 Color endColor = _keyColors[(transition + 1) % _keyColors.Count]; 20 int locationInTransition = value - (transition * valuesPerTransition); 21 byte rValue = Convert.ToByte(((endColor.R - startColor.R) * locationInTransition) / valuesPerTransition + startColor.R); 22 byte gValue = Convert.ToByte(((endColor.G - startColor.G) * locationInTransition) / valuesPerTransition + startColor.G); 23 byte bValue = Convert.ToByte(((endColor.B - startColor.B) * locationInTransition) / valuesPerTransition + startColor.B); 24 return Color.FromRgb(rValue, gValue, bValue); 25 } 26 27 public override string ToString() 28 { 29 return _name; 30 } 31 }

Mandelbrot Set with Coloring
Now, there is a problem with this: the output has obvious steps, as the number of iterations is a integer value. It still looks good this way, and some people even prefer it, but the look I was looking for was smoother. A way to smooth the obvious steps away is to factor in the amount each point escapes by on the iteration it escaped, rather than just how many iterations it took to escape. Proof of the adjustment I use can be found here and here is the code for the adjustment:
1 double escapedValue = Math.Sqrt(zReal * zReal + zImaginary * zImaginary); 2 double normalizedIterationCount = i - (Math.Log(Math.Log(escapedValue))) / Math.Log(2); 3 return _gradiant.getColor((int)(normalizedIterationCount * _SMOOTHING_FACTOR), _gradiantPeriod * _SMOOTHING_FACTOR);
The result is that, instead of an integer you now have a real number expressing how many iterations it took to escape, and you can multiply that by a scalar telling it how many colors you want per iterative step. In my case this smoothing factor is 256.

Mandelbrot Set with Smoothing
Now you have a nice smoothed fractal, but it still looks grainy. This is because fractals are basically a case study in aliasing. Each pixel could potentially contain an infinite amount of complexity, but the image is just displaying the exact coordinate that pixel maps to. The solution to this is to zoom in on each pixel, render some amount of data (the more the better, but also slower) and then average out all the values. Here is an example in which 64 values (8x8) are calculated per pixel.

Mandelbrot Set with Anti-Aliasing
I am including the program I wrote to explore the Mandelbrot Set. The program allows a user to explore around the set using an interface inspired by Google Maps. Double clicking zooms in, a button zooms out, and dragging moves the fractal around. There is also a control panel to change some of the settings described in this post, such as anti-aliasing, gradient colors and smoothing. You can download the source code here
Comments: