// 9.29.06 // mandelbrot.cpp // QT/OpenGL implementation of Mandelbrot set // Load in our mandelbrot.h #include "mandelbrot.h" ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::MandelbrotWidget() // Notes: Called at the beginning to setup variables ///////////////////////////////////////////////////////////////////// MandelbrotWidget::MandelbrotWidget() { h = 0; w = 0; // Zoom factor (e.g. 1=1x, 2=2x, etc.) zoom = 1; // Placement of zoom moveX = -0.5; moveY = 0; // Max number of iterations to determine escape MaxIter = 100; } ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::MandelbrotWidget() // Notes: Called at the beginning to setup CUSTOM varibles ///////////////////////////////////////////////////////////////////// MandelbrotWidget::MandelbrotWidget(double z, double mx, double my, int maxit) { // Zoom factor (e.g. 1=1x, 2=2x, etc.) zoom = z; // Placement of zoom moveX = mx; moveY = my; // Max number of iterations to determine escape MaxIter = maxit; } ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::initializeGL() // Notes: Called at the beginning to initialize GL specs ///////////////////////////////////////////////////////////////////// void MandelbrotWidget::initializeGL() { // Set clear (background) color to white // RGBA = Red,Green,Blue,Alpha (blending between old and new color at pixel location) glClearColor(1.0, 1.0, 1.0, 0.0); // Set shade model to basic flat not needed since we are drawing points, not lines or polygons // glShadeModel(GL_FLAT); } ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::resizeGL() // Notes: Called upon everytime there a resize event ///////////////////////////////////////////////////////////////////// void MandelbrotWidget::resizeGL(int width, int height ) { // ------------------------------------------------------ // Debugging information, print out screen size w = width; h = height; cout << "resize " << w << "x" << h << endl; // ------------------------------------------------------ // Change viewport to match resize glViewport(0, 0, width, height); // Change matrix mode to affect projection glMatrixMode(GL_PROJECTION); // Clear the matrix by loading identity matrix glLoadIdentity(); // Specify coordinate system (min x, max x, min y, max y, min z, max z) // For mandelbrot, we are only concerned with the circle of radio 2. gluOrtho2D(0.0, width, 0.0, height); // gluOrtho2D(-2.0, 2.0, -2.0, 2.0); // Change matrix mode to affect modelview glMatrixMode(GL_MODELVIEW); // Update drawing updateGL(); } ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::paintGL() // Notes: Called upon everytime there is a [re]paint event // needed. ///////////////////////////////////////////////////////////////////// void MandelbrotWidget::paintGL() { // Clear the window to clear (background) color glClear(GL_COLOR_BUFFER_BIT); // Paint points (as oppose to a shaded polygon) glBegin(GL_POINTS); // Draw mandelbrot DrawMandel(); } ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::mousePressEvent() // Notes: Called upon whenever the mouse button is pressed ///////////////////////////////////////////////////////////////////// void MandelbrotWidget::mousePressEvent(QMouseEvent *event) { // Calculate which way to spin if (event->button() == LeftButton) { cout << "left click\n"; // Zoom in // event->x() and event->y() // double CImag = (y-h/2) / (0.5*zoom*h)+moveY; // double CReal = 1.5*(x-w/2) / (0.5*zoom*w)+moveX; zoom = zoom + 1; moveY = (event->y()-h/2) / (0.5*zoom*h)+moveY; moveX = 1.5*(event->x()-w/2) / (0.5*zoom*w)+moveX; } else if (event->button() == RightButton) { cout << "right click\n"; // Zoom out } else if (event->button() == MidButton) { cout << "middle click\n"; // Reset zoom = 1; moveX = -0.5; moveY = 0; } // Update updateGL(); } ///////////////////////////////////////////////////////////////////// // Name: MandelbrotWidget::Drawmandel() // Notes: Draws mandelbrot based on currnet width/height ///////////////////////////////////////////////////////////////////// void MandelbrotWidget::DrawMandel() { // Cycle through every pixel determining whether Z escapes at that point for (int y = 0; y < h; y++) { // We must convert every pixel location (x,y) to it's repsective coordinates on the complex plane w/ circle radius 2 // Example: On a 100x100 screen, pixel location (50,50) is (0,0i) on the complex plane // on a 100x100 screen, pixel location (50,100) is (0,2i) on th complex plane // Method: Measure fraction of screen covered (so pixel 50w of a 100w screen is 1/2 screen) and // apply that to complex plane (1/2 of screen is equal to 0 on the complex plane of -2 to 2). // Imaginary porition of C // float CImag = (y-h/2) / (0.5*zoom*h)+moveY; float CImag = 2 -((y/(float)h)*4); for (int x = 0; x < w; x++) { // Real portion of C // float CReal = 1.5*(x-w/2) / (0.5*zoom*w)+moveX; float CReal = -2 + (x/(float)w)*4; // Define Z initially to C float ZReal = CReal; float ZImag = CImag; // Squre the two values of Z (real and imaginary) float ZRealSquared = ZReal * ZReal; float ZImagSquared = ZImag * ZImag; // Iteration counter int i = 0; // Loop until MaxIterations or |Z| escapes radius of 2 // Recall that |Z| = sqrt(Real^2+Imag^2) and Z^2 = Real^2 + Imag^2 while ( (i < MaxIter) && (sqrt(ZRealSquared + ZImagSquared) < 2) ) { // Calculate new Z (real and imaginary) ZReal = ZRealSquared - ZImagSquared + CReal; ZImag = 2*ZReal * ZImag + CImag; // Square the two values of Z (real and imaginary) ZRealSquared = ZReal * ZReal; ZImagSquared = ZImag * ZImag; // Increase counter i++; } // Paint pixel // Variate color choices float f1 = 0.5 + 0.5*cos((float)i*0.1); float f2 = 0.5 + 0.5*cos((float)(i+16)*0.1); float f3 = 0.5 + 0.5*cos((float)(i+32)*0.1); // Setup openGL color (RGB) glColor3f(f1,f2,f3); if (i == MaxIter) { glColor3f(0.0,0.0,1.0); } // Draw vertex (pixel) glVertex2f(x, y); // ------------------------------------------------------ // Debugging information, print out screen size // cout << "complex pos (" << CReal << "," << CImag << ") complete"; // ------------------------------------------------------ } } // End painting glEnd(); // Execute the previous commands immediately glFlush(); }