My programming ramblings

The Mandelbrot set in C++11

Posted on February 28, 2013 by Paul

Yet another how to draw the Mandelbrot set article ? Well, yes and no, on the one hand fractals are fun and on the other hand, it could be instructive to play with complex numbers and lambdas in C++11. Also, the article presents a not so common continuous coloring procedure based on a slight modification of the Bernstein polynomials.

Please note, that calculating the Mandelbrot set can be done more efficiently if one uses the GPU (using OpenGL shaders for example) and not the CPU.

Let’s start by creating a small class that will let us define the domain in which we search for points from the Mandelbrot set:

In order to obtain a nice picture, we are going to map the continuous domain in which we search for points from the Mandelbrot set to a discrete domain that represents pixel coordinates:

1 voidmandelbrot(){ 2 // Define the size of the image 3 window<int>scr(0,1200,0,1200); 4 // The domain in which we test for points 5 window<double>fract(-2.2,1.2,-1.7,1.7); 6 7 // The function used to calculate the fractal 8 autofunc=[](std::complex<double>z,std::complex<double>c)->std::complex<double>{returnz*z+c;}; 9 10 ....11 12 // Loop over all pixels from scr and check if every pixel is in the Mandelbrot set13 fractal(...);14 }

For simplicity, we will use the escape time algorithm. Basically, for every pixel, we iterate over the formula until or a maximum number of iterations is reached. We’ll use the iteration numbers to assign a particular color to every pixel. These are the functions called by mandelbrot():

The question that remains to be solved is how to assign colors to a point from the Mandelbrot set. My first attempt was to use a linear map between the number of iterations and the number of possible values for an RGB image. We start by dividing the number of iterations corresponding to a particular pixel to the maximum number of iterations, this will gives us a number t on the unit interval. An RGB image can have colors, so we multiply t with , cast the value to an integer that is used as an index in an array of colors. Obviously, we are not going to generate and store colors, that will be silly. If we imagine our virtual array of colors as a 3D array, we can get the r, g, b indices with the following function:

An alternative to the above approach, with similar results, will be to cast the value of t multiplied with to an unsigned 32 bits integer (4 bytes). Since the r, g, b numbers are 1 byte each, we can read their values from the 32 bits unsigned integer previously calculated.

The resulting image was saved on the disk with the FreeImage library, you can see the complete code, save_image.cpp, on the Github repository for this article.

The map between the iteration number and the 3D color space was made using three piecewise linear functions, the discontinuous nature of this map will be reflected in the resulting image band effect:

If we zoom close enough to one of the bulbs of the set, we’ll have an even nicer image, unfortunately still banded:

There are various tricks with which we can obtain a more continuous image, one of them, suggested in the cited Wikipedia article is the Normalized Iteration Count algorithm. The problem with this algorithm is that it needs modifications for different, but related, fractals like the Julia set.

The key to a nice image, without color bands, is the word continuous! I mean, how do we expect to obtain a smooth transition from color to color if we use a discontinuous map between the iteration count and the 3D color space ?

Well, the solution is not that complicated - use three smooth, continuous functions that will map every number t. Remember that t was obtained by dividing the number of iterations for every point in the set with the maximum number of iterations, on the unit interval. We could use any smooth polynomial that is defined on the unit interval and has values on the same interval. A slightly modified form of the Bernstein polynomials looks like the perfect match for what we need, they are continuous, smooth and have values in the [0, 1) interval:

Let’s see now, the effect of using a smooth map from the iteration numbers to the 3D RGB space:

If we zoom again close enough to one of the bulbs of the set, we’ll have an even nicer image, this time without any band effect:

Suppose now that you’ve had enough fun with the classical Mandelbrot set and you want to try something new, like the third order Mandelbrot set :). How can you add this to the above code ? We’ll need to define a new driver function, say triple_mandelbroot:

Disclaimer:All data and information provided on this site is for informational purposes only. solarianprogrammer.com makes no representations as to accuracy, completeness, currentness, suitability, or validity of any information on this site and will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use. All information is provided on an as-is basis. solarianprogrammer.com does not collect any personal information about its visitors except that which they provide voluntarily when leaving comments. This information will never be disclosed to any third party for any purpose. Some of the links contained within this site have my referral id, which provides me with a small commission for each sale. Thank you for understanding.