Logo AND Algorithmique Numérique Distribuée

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