Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Cleanup.
[graphlib.git] / mandel / mandel.cpp
index e57e2c8..955d888 100644 (file)
 #include <QApplication>
 #include <iostream>
 
-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;
     }
 }