![]() ![]() Void keyPressEvent( QKeyEvent *event) override Void resizeEvent( QResizeEvent *event) override Void paintEvent( QPaintEvent *event) override MandelbrotWidget( QWidget *parent = nullptr) The MandelbrotWidget class uses RenderThread to draw the Mandelbrot set on screen. It is called from the constructor to initialize the colormap array with pleasing colors. The rgbFromWaveLength() function is a helper function that converts a wave length to a RGB value compatible with 32-bit QImages. Uint RenderThread ::rgbFromWaveLength( double wave) The core algorithm is beyond the scope of this tutorial. Similarly, if we discover that abort has been set to true (by the RenderThread destructor), we return from the function immediately, terminating the thread. If we discover inside the loop that restart has been set to true (by render()), we break out of the loop immediately, so that the control quickly returns to the very top of the outer loop (the forever loop) and we fetch the new rendering parameters. We create a high resolution pixmap by applying the device pixel ratio to the target size (see Drawing High Resolution Versions of Pixmaps and Images). Instead of trying to create a perfect Mandelbrot set image, we do multiple passes and generate more and more precise (and computationally expensive) approximations of the fractal. *scanLine + + = colormap Įmit renderedImage(image, requestedScaleFactor) scanLine(y + halfHeight)) Ĭonst double ay = centerY + (y * scaleFactor) QImage image(resultSize, QImage ::Format_RGB32) The mutex protects the other data member. In the private section, we have a QMutex, a QWaitCondition, and a few other data members. It is automatically called when the thread is started. ![]() The protected run() function is reimplemented from QThread. Whenever the thread is done rendering an image, it emits the renderedImage() signal. Apart from the constructor and destructor, render() is the only public function. The class inherits QThread so that it gains the ability to run in a separate thread. Static uint rgbFromWaveLength( double wave) Void renderedImage( const QImage &image, double scaleFactor) Void render( double centerX, double centerY, double scaleFactor, QSize resultSize, double devicePixelRatio) RenderThread( QObject *parent = nullptr) The sequence of screenshots below shows the original image, the scaled image, and the rerendered image. The result doesn't look as good as what the worker thread eventually ends up providing, but at least it makes the application more responsive. The thread emits a signal when it is done rendering the fractal.ĭuring the time where the worker thread is recomputing the fractal to reflect the new zoom factor position, the main thread simply scales the previously rendered pixmap to provide immediate feedback. To avoid freezing the main thread's event loop (and, as a consequence, the application's user interface), we put all the fractal computation in a separate worker thread. The Mandelbrot application supports zooming and scrolling using the mouse or the keyboard. ![]() The Blocking Fortune Client Example shows the same principle at work in a TCP client. In real life, the approach described here is applicable to a large set of problems, including synchronous network I/O and database access, where the user interface must remain responsive while some heavy operation is taking place. These days, while sophisticated programs such as XaoS that provide real-time zooming in the Mandelbrot set, the standard Mandelbrot algorithm is just slow enough for our purposes. The heavy computation here is the Mandelbrot set, probably the world's most famous fractal. ![]()
0 Comments
Leave a Reply. |