X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/graphlib.git/blobdiff_plain/7918f91adda9cdf88e79e01eb12ad69b79d7be9e..49b1adec952c57fc84dceea41933b7a3cad97ec3:/mandel/mandel.cpp diff --git a/mandel/mandel.cpp b/mandel/mandel.cpp index e57e2c8..955d888 100644 --- a/mandel/mandel.cpp +++ b/mandel/mandel.cpp @@ -2,126 +2,155 @@ #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; - pi = (Imax - Imin) / w.height; - - 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) { - std::cout << "[ " << Rmin - << (Imin >= 0.0 ? " + " : " - ") - << (Imin >= 0.0 ? Imin : -Imin) - << " i ; " << Rmax - << (Imax >= 0.0 ? " + " : " - ") - << (Imax >= 0.0 ? Imax : -Imax) - << " i ] (" << maxiter << ")" - << std::endl; + p.Rscale = (p.Rmax - p.Rmin) / (w.width - 1); + p.Iscale = (p.Imax - p.Imin) / (w.height - 1); + do_mandel(w, p); - do_mandel(w, Rmin, Rmax, Imin, Imax, maxiter); + w.setColor("white"); + w.drawText(5, 5, "Cliquer sur l'image pour zoomer"); int x, y; int button; - std::cout << "-=[ Cliquer sur l'image pour zoomer ]=-" << std::endl; w.waitMousePress(x, y, button); - Tr = Rmin + x * (Rmax - Rmin) / w.width; - Ti = Imax - y * (Imax - Imin) / w.height; - std::cout << "(" << x << ";" << y << ") -> (" - << Tr << ";" << Ti << ")" << std::endl; - double Rmin2 = Rmin / 2; - double Rmax2 = Rmax / 2; - double Imin2 = Imin / 2; - double Imax2 = Imax / 2; - double Rdecal = Tr - (Rmin2 + Rmax2) / 2; - double Idecal = Ti - (Imin2 + Imax2) / 2; - Rmin2 += Rdecal; - Rmax2 += Rdecal; - Imin2 += Idecal; - Imax2 += Idecal; + // 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é + const int zoom = 2; + 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; + Rmax2 += Rshift; + Imin2 += Ishift; + Imax2 += Ishift; - double x_factor = w.width / (Rmax - Rmin); - double y_factor = w.height / (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; } }