Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Make it publicly available after installation.
[graphlib.git] / mandel / mandel.cpp
1 #include <DrawingWindow.h>
2 #include <QApplication>
3 #include <iostream>
4
5 struct parameters {
6     // nombre max d'itérations
7     int maxiter;
8     // zone d'intérêt par défaut
9     double Rmin;
10     double Rmax;
11     double Imin;
12     double Imax;
13     // facteur d'échelle
14     double Rscale;
15     double Iscale;
16 };
17
18 const parameters initial_parameters = {
19     1000,                       // maxiter
20     -2.05,                      // Rmin
21     0.55,                       // Rmax
22     -1.3,                       // Imin
23     1.3,                        // Imax
24     0.0,                        // Rscale
25     0.0,                        // Iscale
26 };
27
28 static inline double sqr(double x)
29 {
30     return x * x;
31 }
32
33 static int check_point(parameters& p, double cr, double ci)
34 {
35     double zr2, zi2;
36     zi2 = sqr(ci);
37     if (sqr(cr + 1) + zi2 < 1.0 / 16.0)
38         return p.maxiter;
39     double x4 = cr - 1.0 / 4.0;
40     double q = sqr(x4) + zi2;
41     if (q * (q + x4) < zi2 / 4.0)
42         return p.maxiter;
43     zr2 = sqr(cr);
44     double zr = cr;
45     double zi = ci;
46     int i;
47     for (i = 0 ; i < p.maxiter && zr2 + zi2 < 4 ; i++) {
48         zi = 2 * zr * zi + ci;
49         zr = zr2 - zi2 + cr;
50         zr2 = sqr(zr);
51         zi2 = sqr(zi);
52     }
53     return i;
54 }
55
56 static void set_color(DrawingWindow& w, parameters& p, int i)
57 {
58     double rouge, vert, bleu;
59     if (i >= p.maxiter) {
60         rouge = vert = bleu = 0.0;
61     } else {
62         int ii = (p.maxiter - 1 - i) % 96;
63         if (ii < 32) {
64             // vert -> bleu
65             bleu = ii / 32.0;
66             vert = 1.0 - bleu;
67             rouge = 0.0;
68         } else if (ii < 64) {
69             // bleu -> rouge
70             rouge = (ii - 32) / 32.0;
71             bleu = 1.0 - rouge;
72             vert = 0.0;
73         } else {
74             // rouge -> vert
75             vert = (ii - 64) / 32.0;
76             rouge = 1.0 - vert;
77             bleu = 0.0;
78         }
79     }
80     w.setColor(rouge, vert, bleu);
81 }
82
83 // Fonction de dessin de l'ensemble de Madelbrot, dans la zone
84 // spécifiée, et avec la précision souhgaitée.
85 static void do_mandel(DrawingWindow& w, parameters& p)
86 {
87     int x, y;                   // le pixel considéré
88     double cr, ci;              // le complexe correspondant
89
90     for (y = 0 ; y < w.height ; y++) {
91         ci = p.Imax - y * p.Iscale;
92         cr = p.Rmin;
93         int x0 = 0;
94         int i0 = check_point(p, cr, ci);
95         for (x = 1 ; x < w.width ; x++) {
96             cr = p.Rmin + x * p.Rscale;
97             int i = check_point(p, cr, ci);
98             if (i != i0) {
99                 set_color(w, p, i0);
100                 w.drawLine(x0, y, x - 1, y);
101                 i0 = i;
102                 x0 = x;
103             }
104         }
105         set_color(w, p, i0);
106         w.drawLine(x0, y, w.width - 1, y);
107     }
108 }
109     
110 // Fonction de dessin principale, calcule la zone d'intérêt, appelle
111 // do_mandel(), pour dessiner l'ensemle, et permet le zoom.
112 static void mandel(DrawingWindow &w)
113 {
114     parameters p = initial_parameters;
115     while (1) {
116         p.Rscale = (p.Rmax - p.Rmin) / (w.width - 1);
117         p.Iscale = (p.Imax - p.Imin) / (w.height - 1);
118         do_mandel(w, p);
119
120         w.setColor("white");
121         w.drawText(5, 5, "Cliquer sur l'image pour zoomer");
122
123         int x, y;
124         int button;
125         w.waitMousePress(x, y, button);
126
127         // calcul des coordonnées du point cliqué
128         double Tr = p.Rmin + x * p.Rscale;
129         double Ti = p.Imax - y * p.Rscale;
130
131         // calcul de la nouvelle zone d'intérêt :
132         // zoom ×2 en direction du point cliqué
133         const int zoom = 2;
134         double Rmin2 = p.Rmin / zoom;
135         double Rmax2 = p.Rmax / zoom;
136         double Imin2 = p.Imin / zoom;
137         double Imax2 = p.Imax / zoom;
138         double Rshift = Tr - (Rmin2 + Rmax2) / 2;
139         double Ishift = Ti - (Imin2 + Imax2) / 2;
140         Rmin2 += Rshift;
141         Rmax2 += Rshift;
142         Imin2 += Ishift;
143         Imax2 += Ishift;
144
145         // affichage d'un rectangle autour de la nouvelle zone d'intérêt
146         w.setColor("white");
147         w.drawRect((Rmin2 - p.Rmin) / p.Rscale, (p.Imax - Imin2) / p.Iscale,
148                    (Rmax2 - p.Rmin) / p.Rscale, (p.Imax - Imax2) / p.Iscale);
149
150         p.Rmin = Rmin2;
151         p.Rmax = Rmax2;
152         p.Imin = Imin2;
153         p.Imax = Imax2;
154     }
155 }
156
157 int main(int argc, char *argv[])
158 {
159     QApplication app(argc, argv);
160     DrawingWindow win(mandel, 800, 800);
161     win.show();
162     return app.exec();
163 }