L'ensemble de Mandelbrot
A propos du code
Une forme célèbre
Les nombres complexes
z = a + b*i
a et b sont des nombres rééls.
i2 = -1
Comme vous le savez, le carré d'un nombre est toujours positif. Donc un nombre comme i ne devrait pas exister, mais
z1 = a1 + b1*i
z2 = a2 + b2*i
Quand on les additionne
z1 + z2 = a1 + b1*i + a2 + b2*i
si on regroupe ensemble les termes réels et imaginaires:
z1 + z2 = (a1 + a2) + (b1 + b2)*i
On obtient un nouveau nombre complexe dont la partie réelle est (a1+a2) et la partie imaginaire (b1+b2)*i
z1 * z2 = (a1 + b1*i) * (a2 + b2*i)
= a1*a2 + a1*b2*i + b1*a2*i + b1*b2*i2
Comme i2 = -1. Alors on a:
z1 * z2 = (a1*a2 - b1*b2) + (a1*b2 + b1*a2)*i
Encore une fois on obtient un nombre complexe avec une partie réelle et une partie imaginaire.
z2 = (a2 - b2) + (2*a*b)*i
Le plan complexe
La formule de l'ensemble
z0 = 0
zn+1 = zn2 + c
où les valeurs de z sont des nombres complexes.
z0 = 0
z1 = 02 + (2 + 2*i) = 2 + 2*i
z2 = (2 + 2*i)2 + (2 + 2*i)
...
Et ainsi de suite jusqu'à ce que z devienne trop grand ou que l'on atteigne le nmax-ième terme.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "main.h"
#include "Graphics.h"
#include "System.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define MAX_ITERATIONS 256
int main(int argc, char* argv[])
{
// init the window
gfx.init("Mandelbrot", SCREEN_WIDTH, SCREEN_HEIGHT);
gfx.init2D();
gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));
for (int y = 0; y < SCREEN_HEIGHT; y++)
for (int x = 0; x < SCREEN_WIDTH; x++)
{
// convert the pixel pos to a complex number
double c_re = (x - SCREEN_WIDTH / 2.0) * 4.0 / SCREEN_WIDTH - 0.7;
double c_im = (y - SCREEN_HEIGHT / 2.0) * 4.0 / SCREEN_WIDTH;
double z_re = 0;
double z_im = 0;
int iteration = 0;
while (z_re * z_re + z_im * z_im <= 16 &&
iteration < MAX_ITERATIONS)
{
// compute the new value
double zn_re = z_re * z_re - z_im * z_im + c_re;
double zn_im = 2 * z_re * z_im + c_im;
// copy back the result to z
z_re = zn_re;
z_im = zn_im;
iteration++;
}
// draw the pixel
Color col;
if (iteration == MAX_ITERATIONS)
col = Color(0, 0, 0);
else
col = Color(iteration, iteration, iteration/2 + 128);
gfx.setPixel(x, y, col);
// display and process the events
gfx.render();
sys.processEvents();
if (sys.isQuitRequested() == true)
exit(EXIT_SUCCESS);
}
// wait until we quit
while (sys.isQuitRequested() == false)
{
sys.processEvents();
sys.wait(50);
}
gfx.quit();
return EXIT_SUCCESS;
}
Télécharger le code source
Télécharger l'exécutable pour Windows
Remarquez qu'à chaque pixel on appelle gfx.render() parce que je voulais que ça soit animé et qu'on puisse voir
Dessiner en suivant un motif
void drawMandelbrot(int offsetx, int offsety)
{
for (int y = 0; y < SCREEN_HEIGHT; y += 8)
{
for (int x = 0; x < SCREEN_WIDTH; x += 8)
{
// convert the pixel pos to a complex number
double c_re = (x + offsetx - SCREEN_WIDTH / 2.0) * 4.0 / SCREEN_WIDTH - 0.7;
double c_im = (y + offsety - SCREEN_HEIGHT / 2.0) * 4.0 / SCREEN_WIDTH;
double z_re = 0;
double z_im = 0;
int iteration = 0;
while (z_re * z_re + z_im * z_im <= 16 &&
iteration < MAX_ITERATIONS)
{
// compute the new value
double zn_re = z_re * z_re - z_im * z_im + c_re;
double zn_im = 2 * z_re * z_im + c_im;
// copy back the result to z
z_re = zn_re;
z_im = zn_im;
iteration++;
}
// draw the pixel
Color col;
if (iteration == MAX_ITERATIONS)
col = Color(0, 0, 0);
else
col = Color(iteration, iteration, iteration/2 + 128);
gfx.setPixel(x + offsetx, y + offsety, col);
}
}
}
Ensuite, le code principal appellera cette fonction avec un offset qui viendra d'une table.
int main(int argc, char* argv[])
{
// init the window
gfx.init("Mandelbrot 2", SCREEN_WIDTH, SCREEN_HEIGHT);
gfx.init2D();
gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));
static Uint8 pattern[64] =
{
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
};
for (int i = 0; i < 64; i++)
{
int j = 0;
while (pattern[j] != i)
j++;
drawMandelbrot(j % 8, j / 8);
// display and process the events
gfx.render();
sys.wait(50);
sys.processEvents();
if (sys.isQuitRequested() == true)
exit(EXIT_SUCCESS);
}
// wait until we quit
while (sys.isQuitRequested() == false)
{
sys.processEvents();
sys.wait(50);
}
gfx.quit();
return EXIT_SUCCESS;
}
Télécharger le code source
Télécharger l'exécutable pour Windows
La classe Complex
class Complex
{
public:
Complex(double _re = 0.0, double _im = 0.0);
double squareMag();
double mag();
void operator=(const Complex rhs);
Complex operator+(const Complex rhs);
Complex operator*(const Complex rhs);
double re;
double im;
};
Ca simplifie grandement la fonction de dessin.
void drawMandelbrot(int offsetx, int offsety)
{
for (int y = 0; y < SCREEN_HEIGHT; y += 8)
{
for (int x = 0; x < SCREEN_WIDTH; x += 8)
{
// convert the pixel pos to a complex number
Complex c;
c.re = (x + offsetx - SCREEN_WIDTH / 2.0) * 4.0 / SCREEN_WIDTH - 0.7;
c.im = (y + offsety - SCREEN_HEIGHT / 2.0) * 4.0 / SCREEN_WIDTH;
Complex z;
int iteration = 0;
while (z.squareMag() <= 16 &&
iteration < MAX_ITERATIONS)
{
// compute the new value
z = z * z + c;
iteration++;
}
// draw the pixel
Color col;
if (iteration == MAX_ITERATIONS)
col = Color(0, 0, 0);
else
col = Color(iteration, iteration, iteration/2 + 128);
gfx.setPixel(x + offsetx, y + offsety, col);
}
}
}
Télécharger le code source
Télécharger l'exécutable pour Windows
Et maintenant on peut facilement changer la formule. Par exemple, voilà ce que zn+1 = zn3 + c donne:
Changer les couleurs
// set up the palette
for (int i = 0; i < 256; ++i)
{
float angle = 2.0 * M_PI * (float)i / 256.0;
float offset = 2.0 * M_PI / 3.0;
angle += 40.0 * M_PI / 128.0;
angle *= 1.3;
palette[i].r = 128 + 128 * sin(angle);
palette[i].g = 128 + 128 * sin(angle * 1.1 - offset);
palette[i].b = 128 + 128 * sin(angle * 1.5 + offset);
}
Télécharger le code source
Télécharger l'exécutable pour Windows
Et voilà à quoi ça ressemble:
Le coté obscur
// draw the pixel
Color col;
if (iteration == MAX_ITERATIONS)
{
int v = (int)(z.mag() * 128.0) % 256;
col = palette[v];
}
else
{
col = Color(0, 0, 0);
}
gfx.setPixel(x + offsetx, y + offsety, col);
Télécharger le code source
Télécharger l'exécutable pour Windows
Et voilà à quoi ressemble l'intérieur.