Mandelbrot Set - symatevo/fract-ol GitHub Wiki
To build a graphical representation of a Mandelbrot set, you can use an algorithm called escape-time.
Its essence is that the entire set is completely located inside a circle of radius 2 on the plane.
To determine if a particular point belongs to a set, a specified number of iterations of the formula below are performed:
If, after all the iterations, its value does not go beyond the specified circle, then the point belongs to the Mandelbrot set and, therefore, is painted black.
If the point has left the established boundaries, then using the number of the iteration, at which it happened, the color is set to show the speed of its "escape".
This sequence of actions must be done with each point on the plane.
To get a complete picture of such a set, you need to perform a huge amount of calculations - hundreds, thousands, millions. It would be extremely difficult to do this manually.
Therefore, we, like Benoit Mandelbrot in his time, need to implement a program for these purposes.
Let us outline the boundaries of the complex plane, where the Mandelbrot set will be depicted:
min.re = -2.0;
max.re = 2.0;
min.im = -2.0;
max.im = min.im + (max.re - min.re) * HEIGHT / WIDTH;
The above lines determine that the minimum real part of the complex numbers (that is, the left border of the image) is -2.0, and the maximum (that is, the right border) is 2.0.
The minimum imaginary part is determined in the same way. And the maximum is calculated based on the size of the window to avoid image distortion.
It is also necessary to calculate the relationship between complex numbers and pixels on the screen.
factor.re = (max.re - min.re) / (WIDTH - 1);
factor.im = (max.im - min.im) / (HEIGHT - 1);
c.re = min.re + x * factor.re;
c.im = max.im - y * factor.im;
As you can see, c.im is considered in a special way. This is due to the fact that the y-axis in the program window is directed from top to bottom, and not from bottom to top, as we are used to.
In addition to the calculations already made, it is also necessary to set the number of iterations:
max_iteration = 50;
The higher the specified number, the more accurate the resulting fractal image will be. And the more computational tasks will fall on the computer.
Therefore, when setting this variable, it is necessary to find a balance between the two possible extremes.
At the moment, the main part of the program looks like this:
min.re = -2.0;
max.re = 2.0;
min.im = -2.0;
max.im = min.im + (max.re - min.re) * HEIGHT / WIDTH;
factor.re = (max.re - min.re) / (WIDTH - 1);
factor.im = (max.im - min.im) / (HEIGHT - 1);
max_iteration = 50;
y = 0;
while (y <HEIGHT)
{
c.im = max.im - y * factor.im;
x = 0;
while (x <WIDTH)
{
c.re = min.re + x * factor.re;
// Formula of the Mandelbrot set
// Set point color
x ++;
}
y ++;
}
Since we have to perform initialization of a complex number quite often, it is worth writing a function for these purposes:
t_complex init_complex (double re, double im)
{
t_complex complex;
complex.re = re;
complex.im = im;
return (complex);
}
While the advantages of such a function are not obvious, but when writing the formula for the set itself, it will be very useful to us:
min = init_complex (-2.0, -2.0);
max.re = 2.0;
max.im = min.im + (max.re - min.re) * HEIGHT / WIDTH;
factor = init_complex (
(max.re - min.re) / (WIDTH - 1),
(max.im - min.im) / (HEIGHT - 1));
max_iteration = 50;
y = 0;
while (y <HEIGHT)
{
c.im = max.im - y * factor.im;
x = 0;
while (x <WIDTH)
{
c.re = min.re + x * factor.re;
// Formula of the Mandelbrot set
// Set point color
x ++;
}
y ++;
}
In place of the first comment, we need to write down the already mentioned formula of the Mandelbrot set, as well as the constraint described above in the form of a circle of radius 2.
Initializing the z variable is very simple:
z = init_complex (c.re, c.im);
To determine whether a point belongs to a circle, if its center coincides with the origin, you can use this simple formula:
It can also be written as follows:
If the value of the above expression is true, then the point with coordinates (x, y) belongs to a circle with radius r.
With this knowledge, we can supplement the existing code:
y = 0;
while (y <HEIGHT)
{
c.im = max.im - y * factor.im;
x = 0;
while (x <WIDTH)
{
c.re = min.re + x * factor.re;
z = init_complex (c.re, c.im);
iteration = 0;
while (pow (z.re, 2.0) + pow (z.im, 2.0) <= 4
&& iteration <max_iteration)
{
// Formula of the Mandelbrot set
iteration ++;
}
// Set point color
x ++;
}
y ++;
}
It remains only to write down the formula of the Mandelbrot set itself and the program is almost ready.
Here's just how to translate the following formula into your code:
It is very easy to add one complex number to another. The real part to the real one. Imaginary to imaginary. Ready.
But multiplication, like exponentiation, is a more complicated process:
The real part of the resulting number:
Its imaginary part:
In the code, the Mandelbrot formula will be written in the following form:
y = 0;
while (y <HEIGHT)
{
c.im = max.im - y * factor.im;
x = 0;
while (x <WIDTH)
{
c.re = min.re + x * factor.re;
z = init_complex (c.re, c.im);
iteration = 0;
while (pow (z.re, 2.0) + pow (z.im, 2.0) <= 4
&& iteration <max_iteration)
{
z = init_complex (
pow (z.re, 2.0) - pow (z.im, 2.0) + c.re,
2.0 * z.re * z.im + c.im);
iteration ++;
}
// Set point color
x ++;
}
y ++;
}
Fractal formula moved to code. It remains only to get acquainted with the code snippet responsible for choosing a color depending on the number of iterations performed:
t = (double) iteration / (double) max_iteration;
red = (int) (9 * (1 - t) * pow (t, 3) * 255);
green = (int) (15 * pow ((1 - t), 2) * pow (t, 2) * 255);
blue = (int) (8.5 * pow ((1 - t), 3) * t * 255);