Salut,
Je viens de lire le petit tuto sur l'ensemble de Mandelbrot, qui est vraiment sympa. J'ai donc voulu implémenter l'algo proposé en C++, avec l'aide de la SFML ; pas de souci jusqu'à là, j'arrive à dessiner la figure.
J'ai ensuite voulu rajouter le zoom. Mais comme je veux les choses bien faite, j'ai voulu faire un zoom relatif à la position de la souris. C'est à dire que le programme commence à un niveau de zoom et une taille de fenêtre qui permettent de voire la fractale en entier, puis, quand l'utilisateur faire tourner sa molette, on zoome (zoom x2) en centrant la vue sur le curseur (sans modifier la taille de la fenêtre, ofc).
Mais, je ne sais pas comment implémenter ça.
Avant tout, je vous montre le code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | #include <iostream> #include <SFML/Graphics.hpp> struct Param { float x1; float x2; float y1; float y2; float zoom; int max_iter; }; sf::Image drawManderbolt(Param p); Param zoomIn(Param current, int mouseX, int mouseY, int w, int h); int main() { Param currentParameter; currentParameter.x1 = -2.1; currentParameter.x2 = 0.6; currentParameter.y1 = -1.2; currentParameter.y2 = 1.2; currentParameter.zoom = 400; currentParameter.max_iter = 50; sf::Image image = drawManderbolt(currentParameter); sf::RenderWindow window(sf::VideoMode(image.getSize().x, image.getSize().y), "Manderbolt"); // Chargement de l'image dans une texture sf::Texture texture; texture.loadFromImage(image); // Puis de la texture dans un sprite sf::Sprite sprite; sprite.setTexture(texture); while(window.isOpen()) { sf::Event event; while(window.pollEvent(event)) { if(event.type == sf::Event::Closed) { window.close(); } if(event.type == sf::Event::MouseWheelMoved) { int delta, x, y = 0; delta = event.mouseWheel.delta; x = sf::Mouse::getPosition(window).x; y = sf::Mouse::getPosition(window).y; // C'est pour debug, pataper pls, je sais c'est pas bien std::cout << delta << " : " << x << " : " << y << std::endl; currentParameter = zoomIn(currentParameter, x, y, image.getSize().x, image.getSize().y); image = drawManderbolt(currentParameter); texture.loadFromImage(image); sprite.setTexture(texture); } } window.clear(); // Affichage de l'image window.draw(sprite); window.display(); } return EXIT_SUCCESS; } sf::Image drawManderbolt(Param p) { int imageX = (p.x2 - p.x1) * p.zoom; int imageY = (p.y2 - p.y1) * p.zoom; sf::Image image; image.create(imageX, imageY, sf::Color::Black); for(int x = 0; x < imageX; ++x) { for(int y = 0; y < imageY; ++y) { float c_r = x / p.zoom + p.x1; float c_i = y / p.zoom + p.y1; float z_r = 0; float z_i = 0; int i = 0; do { float tmp = z_r; z_r = z_r * z_r - z_i * z_i + c_r; z_i = 2 * z_i * tmp + c_i; i++; }while(z_r * z_r + z_i * z_i < 4 && i < p.max_iter); if(i == p.max_iter) { image.setPixel(x, y, sf::Color::White); } else { image.setPixel(x, y, sf::Color(0, 0, i * 255 / p.max_iter)); } } } return image; } Param zoomIn(Param current, int mouseX, int mouseY, int w, int h) { Param newParameter; newParameter.zoom = current.zoom * 2; // Coordonnées de la sourie dans le "vrai" repère int X = current.x1 + mouseX * (current.x2 - current.x1) / w; int Y = current.y1 + mouseY * (current.y2 - current.y1) / h; newParameter.x1 = X - (current.x2 - current.x1) / 4; newParameter.x2 = X + (current.x2 - current.x1) / 4; newParameter.y1 = Y - (current.y2 - current.y1) / 4; newParameter.y2 = Y + (current.y2 - current.y1) / 4; newParameter.max_iter = current.max_iter * 2; // Pour debug aussi, pataper encore ^^ std::cout << newParameter.x1 << " : " << newParameter.x2 << " : " << newParameter.y1 << " : " << |newParameter.y2 << std::endl; return newParameter; } //zoomOut en préparation... //Param zoomOut(Param current, int mouseX, int mouseY, int w, int h) |
(Ah, les joies des balises sur 150 lignes…)
Donc, le problème, c'est le changement de repère. Je récupère les coordonnées de la position de ma souris au pixel près dans le repère dont l'origine se situe en haut à gauche de l'écran, avec 1 pixel = 1 unité. Or le repère de la figure est totalement différent, pas la même échelle et il n'est même pas centré sur le centre de la fenêtre. J'essaie donc de transposer les coords de la souris dans le repère de la fractale, puis d'effectuer laborieusement le zoom dessus. Or je n'y arrive pas. Dans le code ci-dessus on voit ma dernière tentative, infructueuse.
Un petit peu d'aide, please ?
Merci beaucoup
PS: Premier thread, woohoo !
PPS: Pour prouver que ça marche, quand même (si on omet le zoom), !