X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/graphlib.git/blobdiff_plain/03544dec36369a2d19c060e630338e69bda353b9..HEAD:/mandel/mandel.cpp diff --git a/mandel/mandel.cpp b/mandel/mandel.cpp index 1afd640..955d888 100644 --- a/mandel/mandel.cpp +++ b/mandel/mandel.cpp @@ -2,86 +2,120 @@ #include #include -void do_mandel(DrawingWindow &w, - double Rmin, double Rmax, double Imin, double Imax, - int maxiter) +struct parameters { + // nombre max d'itérations + int maxiter; + // zone d'intérêt par défaut + double Rmin; + double Rmax; + double Imin; + double Imax; + // facteur d'échelle + double Rscale; + double Iscale; +}; + +const parameters initial_parameters = { + 1000, // maxiter + -2.05, // Rmin + 0.55, // Rmax + -1.3, // Imin + 1.3, // Imax + 0.0, // Rscale + 0.0, // Iscale +}; + +static inline double sqr(double x) +{ + return x * x; +} + +static int check_point(parameters& p, double cr, double ci) { - int x, y; // le pixel considéré - double cr, ci; // le complexe correspondant - double zr, zi; // pour calculer la suite double zr2, zi2; - double pr, pi; // taille d'un pixel - double rouge, vert, bleu; + zi2 = sqr(ci); + if (sqr(cr + 1) + zi2 < 1.0 / 16.0) + return p.maxiter; + double x4 = cr - 1.0 / 4.0; + double q = sqr(x4) + zi2; + if (q * (q + x4) < zi2 / 4.0) + return p.maxiter; + zr2 = sqr(cr); + double zr = cr; + double zi = ci; int i; + for (i = 0 ; i < p.maxiter && zr2 + zi2 < 4 ; i++) { + zi = 2 * zr * zi + ci; + zr = zr2 - zi2 + cr; + zr2 = sqr(zr); + zi2 = sqr(zi); + } + return i; +} - pr = (Rmax - Rmin) / (w.width - 1); - pi = (Imax - Imin) / (w.height - 1); - - cr = Rmin; - for (x = 0; x < w.width; x++) { - ci = Imax; - for (y = 0; y < w.height; y++) { - // z_1 = c - zr = cr; - zi = ci; - for (i = 1; i <= maxiter; i++) { - zr2 = zr * zr; - zi2 = zi * zi; - if (zr2 + zi2 >= 4) { - // |z| >= 2 : on sort de la boucle - break; - } - // on calcule le z suivant - zi = 2 * zr * zi + ci; - zr = zr2 - zi2 + cr; - } - if (i > maxiter) { - rouge = vert = bleu = 0.0; - } else { - // on est sorti trop tôt du for(...): on affiche le - // pixel d'un couleur en fonction de i - int ii = (maxiter - i) % 96; - if (ii < 32) { - // vert -> bleu - bleu = ii / 32.0; - vert = 1.0 - bleu; - rouge = 0.0; - } else if (ii < 64) { - // bleu -> rouge - rouge = (ii - 32) / 32.0; - bleu = 1.0 - rouge; - vert = 0.0; - } else { - // rouge -> vert - vert = (ii - 64) / 32.0; - rouge = 1.0 - vert; - bleu = 0.0; - } - } - w.setColor(rouge, vert, bleu); - w.drawPoint(x, y); - - ci -= pi; +static void set_color(DrawingWindow& w, parameters& p, int i) +{ + double rouge, vert, bleu; + if (i >= p.maxiter) { + rouge = vert = bleu = 0.0; + } else { + int ii = (p.maxiter - 1 - i) % 96; + if (ii < 32) { + // vert -> bleu + bleu = ii / 32.0; + vert = 1.0 - bleu; + rouge = 0.0; + } else if (ii < 64) { + // bleu -> rouge + rouge = (ii - 32) / 32.0; + bleu = 1.0 - rouge; + vert = 0.0; + } else { + // rouge -> vert + vert = (ii - 64) / 32.0; + rouge = 1.0 - vert; + bleu = 0.0; } - cr += pr; } + w.setColor(rouge, vert, bleu); } -void mandel(DrawingWindow &w) +// Fonction de dessin de l'ensemble de Madelbrot, dans la zone +// spécifiée, et avec la précision souhgaitée. +static void do_mandel(DrawingWindow& w, parameters& p) { - // nombre max d'itérations - int maxiter = 500; - // zone d'intérêt par défaut - double Rmin = -2.05; - double Rmax = 0.55; - double Imin = -1.3; - double Imax = 1.3; - // cible du zoom - double Tr; - double Ti; + int x, y; // le pixel considéré + double cr, ci; // le complexe correspondant + for (y = 0 ; y < w.height ; y++) { + ci = p.Imax - y * p.Iscale; + cr = p.Rmin; + int x0 = 0; + int i0 = check_point(p, cr, ci); + for (x = 1 ; x < w.width ; x++) { + cr = p.Rmin + x * p.Rscale; + int i = check_point(p, cr, ci); + if (i != i0) { + set_color(w, p, i0); + w.drawLine(x0, y, x - 1, y); + i0 = i; + x0 = x; + } + } + set_color(w, p, i0); + w.drawLine(x0, y, w.width - 1, y); + } +} + +// Fonction de dessin principale, calcule la zone d'intérêt, appelle +// do_mandel(), pour dessiner l'ensemle, et permet le zoom. +static void mandel(DrawingWindow &w) +{ + parameters p = initial_parameters; while (1) { - do_mandel(w, Rmin, Rmax, Imin, Imax, maxiter); + p.Rscale = (p.Rmax - p.Rmin) / (w.width - 1); + p.Iscale = (p.Imax - p.Imin) / (w.height - 1); + do_mandel(w, p); w.setColor("white"); w.drawText(5, 5, "Cliquer sur l'image pour zoomer"); @@ -90,17 +124,17 @@ void mandel(DrawingWindow &w) int button; w.waitMousePress(x, y, button); - // calcul des coordonnées du point cliqué - Tr = Rmin + x * (Rmax - Rmin) / (w.width - 1); - Ti = Imax - y * (Imax - Imin) / (w.height - 1); + // calcul des coordonnées du point cliqué + double Tr = p.Rmin + x * p.Rscale; + double Ti = p.Imax - y * p.Rscale; - // calcul de la nouvelle zone d'intérêt : - // zoom ×2 en direction du point cliqué + // calcul de la nouvelle zone d'intérêt : + // zoom ×2 en direction du point cliqué const int zoom = 2; - double Rmin2 = Rmin / zoom; - double Rmax2 = Rmax / zoom; - double Imin2 = Imin / zoom; - double Imax2 = Imax / zoom; + double Rmin2 = p.Rmin / zoom; + double Rmax2 = p.Rmax / zoom; + double Imin2 = p.Imin / zoom; + double Imax2 = p.Imax / zoom; double Rshift = Tr - (Rmin2 + Rmax2) / 2; double Ishift = Ti - (Imin2 + Imax2) / 2; Rmin2 += Rshift; @@ -108,17 +142,15 @@ void mandel(DrawingWindow &w) Imin2 += Ishift; Imax2 += Ishift; - // affichage d'un rectangle autour de la nouvelle zone d'intérêt - double x_factor = (w.width - 1) / (Rmax - Rmin); - double y_factor = (w.height - 1) / (Imax - Imin); + // affichage d'un rectangle autour de la nouvelle zone d'intérêt w.setColor("white"); - w.drawRect((Rmin2 - Rmin) * x_factor, (Imax - Imin2) * y_factor, - (Rmax2 - Rmin) * x_factor, (Imax - Imax2) * y_factor); + w.drawRect((Rmin2 - p.Rmin) / p.Rscale, (p.Imax - Imin2) / p.Iscale, + (Rmax2 - p.Rmin) / p.Rscale, (p.Imax - Imax2) / p.Iscale); - Rmin = Rmin2; - Rmax = Rmax2; - Imin = Imin2; - Imax = Imax2; + p.Rmin = Rmin2; + p.Rmax = Rmax2; + p.Imin = Imin2; + p.Imax = Imax2; } }