[QGIS Commit] r13728 - in branches/threading-branch/src: app core
gui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sun Jun 13 18:06:25 EDT 2010
Author: wonder
Date: 2010-06-13 22:06:25 +0000 (Sun, 13 Jun 2010)
New Revision: 13728
Modified:
branches/threading-branch/src/app/qgisapp.cpp
branches/threading-branch/src/core/qgsmaplayer.h
branches/threading-branch/src/core/qgsmaprenderer.cpp
branches/threading-branch/src/core/qgsmaprenderer.h
branches/threading-branch/src/core/qgsvectorlayer.cpp
branches/threading-branch/src/gui/qgsmapcanvas.cpp
branches/threading-branch/src/gui/qgsmapcanvas.h
branches/threading-branch/src/gui/qgsmapcanvasmap.cpp
branches/threading-branch/src/gui/qgsmapcanvasmap.h
branches/threading-branch/src/gui/qgsmapoverviewcanvas.cpp
Log:
Added support for asynchronous rendering of maps in QgsMapRenderer (an alternative to the synchronous rendering).
Made QgsMapCanvas use the asynchronous rendering - the map is updated continuously while the rendering is underway.
(things are still very fragile - no locking, gui is only half-functional while rendering etc.)
Modified: branches/threading-branch/src/app/qgisapp.cpp
===================================================================
--- branches/threading-branch/src/app/qgisapp.cpp 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/app/qgisapp.cpp 2010-06-13 22:06:25 UTC (rev 13728)
@@ -2883,10 +2883,7 @@
void QgisApp::fileExit()
{
- if ( mMapCanvas && mMapCanvas->isDrawing() )
- {
- return;
- }
+ mMapCanvas->cancelRendering();
if ( saveDirty() )
{
@@ -3640,15 +3637,7 @@
{
if ( mMapCanvas )
{
- QgsMapRenderer* mypMapRenderer = mMapCanvas->mapRenderer();
- if ( mypMapRenderer )
- {
- QgsRenderContext* mypRenderContext = mypMapRenderer->rendererContext();
- if ( mypRenderContext )
- {
- mypRenderContext->setRenderingStopped( true );
- }
- }
+ mMapCanvas->cancelRendering();
}
}
Modified: branches/threading-branch/src/core/qgsmaplayer.h
===================================================================
--- branches/threading-branch/src/core/qgsmaplayer.h 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/core/qgsmaplayer.h 2010-06-13 22:06:25 UTC (rev 13728)
@@ -341,6 +341,7 @@
/**The layer emits this signal when a screen update is requested.
This signal should be connected with the slot QgsMapCanvas::updateMap()*/
+ //! @deprecated not used anymore
void screenUpdateRequested();
/** This is used to send a request that any mapcanvas using this layer update its extents */
Modified: branches/threading-branch/src/core/qgsmaprenderer.cpp
===================================================================
--- branches/threading-branch/src/core/qgsmaprenderer.cpp 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/core/qgsmaprenderer.cpp 2010-06-13 22:06:25 UTC (rev 13728)
@@ -42,14 +42,6 @@
#include "qgslogger.h"
-typedef struct ThreadedRenderContext
-{
- QgsMapRenderer* mr; // renderer that governs the rendering
- QgsMapLayer* ml; // source map layer
- QImage* img; // destination image
- QgsRenderContext ctx; // private render context
-} ThreadedRenderContext;
-
void _renderLayerThreading( ThreadedRenderContext& tctx );
/////
@@ -75,10 +67,18 @@
mOutputUnits = QgsMapRenderer::Millimeters;
mLabelingEngine = NULL;
+
+ //connect(&mFW, SIGNAL(finished()), SLOT(futureFinished()));
}
QgsMapRenderer::~QgsMapRenderer()
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("canceling the rendering...");
+ cancelThreadedRendering();
+ }
+
delete mScaleCalculator;
delete mDistArea;
delete mDestCRS;
@@ -98,6 +98,12 @@
bool QgsMapRenderer::setExtent( const QgsRectangle& extent )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return false; // do not allow changes while rendering
+ }
+
//remember the previous extent
mLastExtent = mExtent;
@@ -140,6 +146,12 @@
void QgsMapRenderer::setOutputSize( QSize size, int dpi )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
mSize = size;
mScaleCalculator->setDpi( dpi );
adjustExtentToSize();
@@ -195,9 +207,9 @@
dymax = mExtent.yMaximum() + whitespace;
}
- QgsDebugMsg( QString( "Map units per pixel (x,y) : %1, %2\n" ).arg( mapUnitsPerPixelX ).arg( mapUnitsPerPixelY ) );
- QgsDebugMsg( QString( "Pixmap dimensions (x,y) : %1, %2\n" ).arg( myWidth ).arg( myHeight ) );
- QgsDebugMsg( QString( "Extent dimensions (x,y) : %1, %2\n" ).arg( mExtent.width() ).arg( mExtent.height() ) );
+ QgsDebugMsg( QString( "Map units per pixel (x,y) : %1, %2" ).arg( mapUnitsPerPixelX ).arg( mapUnitsPerPixelY ) );
+ QgsDebugMsg( QString( "Pixmap dimensions (x,y) : %1, %2" ).arg( myWidth ).arg( myHeight ) );
+ QgsDebugMsg( QString( "Extent dimensions (x,y) : %1, %2" ).arg( mExtent.width() ).arg( mExtent.height() ) );
QgsDebugMsg( mExtent.toString() );
// update extent
@@ -217,8 +229,10 @@
}
-void QgsMapRenderer::render( QPainter* painter )
+void QgsMapRenderer::initRendering( QPainter* painter, double deviceDpi )
{
+ mDrawing = true;
+
//flag to see if the render context has changed
//since the last time we rendered. If it hasnt changed we can
//take some shortcuts with rendering
@@ -228,30 +242,9 @@
QgsDebugMsg( "caching enabled? " + QString::number(mCachingEnabled) );
- if ( mExtent.isEmpty() )
- {
- QgsDebugMsg( "empty extent... not rendering" );
- return;
- }
-
- if ( mDrawing )
- {
- return;
- }
-
- QPaintDevice* thePaintDevice = painter->device();
- if ( !thePaintDevice )
- {
- return;
- }
-
- mDrawing = true;
-
-
#ifdef QGISDEBUG
QgsDebugMsg( "Starting to render layer stack." );
- QTime renderTime;
- renderTime.start();
+ mRenderTime.start();
#endif
mRenderContext.setDrawEditingInformation( !mOverview );
@@ -270,7 +263,7 @@
{
scaleFactor = sceneDpi / 25.4;
}
- double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi;
+ double rasterScaleFactor = deviceDpi / sceneDpi;
if ( mRenderContext.rasterScaleFactor() != rasterScaleFactor )
{
mRenderContext.setRasterScaleFactor( rasterScaleFactor );
@@ -308,13 +301,11 @@
}
}
- QgsOverlayObjectPositionManager* overlayManager = overlayManagerFromSettings();
+ mOverlayManager = overlayManagerFromSettings();
+}
- // do the rendering of all layers
- renderLayers( overlayManager );
-
- QgsDebugMsg( "Done rendering map layers" );
-
+void QgsMapRenderer::finishRendering()
+{
// render labels for vector layers (not using PAL)
if ( !mOverview )
{
@@ -322,11 +313,11 @@
}
//find overlay positions and draw the vector overlays
- if ( overlayManager )
+ if ( mOverlayManager )
{
- overlayManager->drawOverlays( mRenderContext, mScaleCalculator->mapUnits() );
- delete overlayManager;
- overlayManager = NULL;
+ mOverlayManager->drawOverlays( mRenderContext, mScaleCalculator->mapUnits() );
+ delete mOverlayManager;
+ mOverlayManager = NULL;
}
// make sure progress bar arrives at 100%!
@@ -342,16 +333,47 @@
mLabelingEngine->exit();
}
- QgsDebugMsg( "Rendering completed in (seconds): " + QString( "%1" ).arg( renderTime.elapsed() / 1000.0 ) );
+ QgsDebugMsg( "Rendering completed in (seconds): " + QString( "%1" ).arg( mRenderTime.elapsed() / 1000.0 ) );
mDrawing = false;
+}
+void QgsMapRenderer::render( QPainter* painter )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return;
+ }
+
+ if ( mExtent.isEmpty() )
+ {
+ QgsDebugMsg( "empty extent... not rendering" );
+ return;
+ }
+
+ QPaintDevice* thePaintDevice = painter->device();
+ if ( !thePaintDevice )
+ {
+ return;
+ }
+
+ double deviceDpi = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0;
+
+ mThreadingEnabled = false;
+
+ initRendering( painter, deviceDpi );
+
+ // do the rendering of all layers
+ renderLayers();
+
+ finishRendering();
}
-void QgsMapRenderer::renderLayers( QgsOverlayObjectPositionManager* overlayManager )
+void QgsMapRenderer::renderLayers()
{
- QList<ThreadedRenderContext> layers;
+ mThreadedJobs.clear();
// render all layers in the stack, starting at the base
QListIterator<QString> li( mLayerSet );
@@ -396,12 +418,12 @@
mRenderContext.setCoordinateTransform( ct );
//create overlay objects for features within the view extent
- if ( ml->type() == QgsMapLayer::VectorLayer && overlayManager )
+ if ( ml->type() == QgsMapLayer::VectorLayer && mOverlayManager )
{
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
if ( vl )
{
- overlayManager->addOverlaysForLayer( vl, mRenderContext );
+ mOverlayManager->addOverlaysForLayer( vl, mRenderContext );
}
}
@@ -426,7 +448,7 @@
if ( !mThreadingEnabled )
renderLayerNoThreading( ml );
else
- renderLayerThreading( ml, layers );
+ renderLayerThreading( ml );
disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
}
@@ -435,23 +457,111 @@
{
QgsDebugMsg("STARTING THREADED RENDERING!");
- QtConcurrent::blockingMap(layers, _renderLayerThreading);
+ //QtConcurrent::blockingMap(layers, _renderLayerThreading);
- QgsDebugMsg("THREADED RENDERING FINISHED!");
+ connect(&mFW, SIGNAL(finished()), SLOT(futureFinished()));
- // draw rendered images and delete temporary painters
- foreach (ThreadedRenderContext tctx, layers)
- {
- mRenderContext.painter()->drawImage( 0, 0, *tctx.img );
- delete tctx.ctx.painter();
- delete tctx.img;
- }
+ mFuture = QtConcurrent::map(mThreadedJobs, _renderLayerThreading);
+ mFW.setFuture(mFuture);
+ }
- QgsDebugMsg("THREADED RENDERING DONE!");
+}
+
+QImage QgsMapRenderer::threadedRenderingOutput()
+{
+ QImage i( mSize, QImage::Format_ARGB32_Premultiplied );
+ i.fill(0);
+ QPainter p;
+ p.begin(&i);
+ foreach (const ThreadedRenderContext& tctx, mThreadedJobs)
+ {
+ if (tctx.img == 0)
+ return QImage(); // destroyed already
+ p.drawImage( 0, 0, *tctx.img );
}
+ p.end();
+ return i;
+}
+void QgsMapRenderer::futureFinished()
+{
+ QgsDebugMsg("THREADED RENDERING FINISHED!");
+
+ QImage i = threadedRenderingOutput();
+
+ // delete temporary painters
+ foreach (ThreadedRenderContext tctx, mThreadedJobs)
+ {
+ delete tctx.ctx.painter();
+ delete tctx.img;
+ tctx.img = 0;
+ }
+ mThreadedJobs.clear();
+
+ QgsDebugMsg("THREADED RENDERING DONE!");
+
+ disconnect(&mFW, SIGNAL(finished()), this, SLOT(futureFinished()));
+
+ QPainter painter;
+ painter.begin(&i);
+ mRenderContext.setPainter(&painter);
+
+ // postprocessing
+ finishRendering();
+
+ painter.end();
+
+ emit finishedThreadedRendering(i);
}
+void QgsMapRenderer::startThreadedRendering()
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ if ( mExtent.isEmpty() )
+ {
+ QgsDebugMsg( "empty extent... not rendering" );
+ return;
+ }
+
+ mThreadingEnabled = true;
+ initRendering(NULL, 96); // TODO: what dpi to use?
+
+ renderLayers();
+}
+
+
+void QgsMapRenderer::cancelThreadedRendering()
+{
+ if (!mDrawing)
+ {
+ QgsDebugMsg("nothing to cancel.");
+ return;
+ }
+
+ QgsDebugMsg("canceling render");
+ for (int i = 0; i < mThreadedJobs.count(); i++)
+ {
+ mThreadedJobs[i].ctx.setRenderingStopped(true);
+ }
+
+ disconnect(&mFW, SIGNAL(finished()), this, SLOT(futureFinished()));
+
+ mFuture.cancel();
+ QTime t;
+ t.start();
+ mFW.waitForFinished();
+
+ QgsDebugMsg(QString("waited %1 ms").arg(t.elapsed() / 1000.0));
+
+ futureFinished(); // manually trigger the routines for finalization
+}
+
+
void _renderLayerThreading( ThreadedRenderContext& tctx )
{
QgsDebugMsg("threaded rendering start: "+tctx.ml->getLayerID());
@@ -461,7 +571,7 @@
QgsDebugMsg("threaded rendering end : "+tctx.ml->getLayerID());
}
-void QgsMapRenderer::renderLayerThreading( QgsMapLayer* ml, QList<ThreadedRenderContext>& lst )
+void QgsMapRenderer::renderLayerThreading( QgsMapLayer* ml )
{
if ( mCachingEnabled && ml->cacheImage() != 0 )
{
@@ -474,8 +584,7 @@
tctx.ml = ml;
// create image
- QPaintDevice* device = mRenderContext.painter()->device();
- tctx.img = new QImage( device->width(), device->height(), QImage::Format_ARGB32_Premultiplied );
+ tctx.img = new QImage( mSize, QImage::Format_ARGB32_Premultiplied );
tctx.img->fill( 0 );
// create private context
@@ -483,14 +592,11 @@
tctx.ctx = mRenderContext;
QPainter* painter = new QPainter(tctx.img);
- if ( mRenderContext.painter()->testRenderHint( QPainter::Antialiasing ) )
- {
- painter->setRenderHint( QPainter::Antialiasing );
- }
+ painter->setRenderHint( QPainter::Antialiasing, mAntialiasingEnabled );
tctx.ctx.setPainter( painter );
// schedule DRAW to a list
- lst.append(tctx);
+ mThreadedJobs.append(tctx);
}
}
@@ -513,10 +619,7 @@
// alter painter
QPainter * mypPainter = new QPainter( ml->cacheImage() );
- if ( mypContextPainter->testRenderHint( QPainter::Antialiasing ) )
- {
- mypPainter->setRenderHint( QPainter::Antialiasing );
- }
+ mypPainter->setRenderHint( QPainter::Antialiasing, mAntialiasingEnabled );
mRenderContext.setPainter( mypPainter );
// DRAW!
@@ -660,6 +763,12 @@
void QgsMapRenderer::setMapUnits( QGis::UnitType u )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
mScaleCalculator->setMapUnits( u );
// Since the map units have changed, force a recalculation of the scale.
@@ -684,6 +793,12 @@
void QgsMapRenderer::setProjectionsEnabled( bool enabled )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
if ( mProjectionsEnabled != enabled )
{
mProjectionsEnabled = enabled;
@@ -701,6 +816,12 @@
void QgsMapRenderer::setDestinationSrs( const QgsCoordinateReferenceSystem& srs )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
QgsDebugMsg( "* Setting destCRS : = " + srs.toProj4() );
QgsDebugMsg( "* DestCRS.srsid() = " + QString::number( srs.srsid() ) );
if ( *mDestCRS != srs )
@@ -936,6 +1057,12 @@
void QgsMapRenderer::setLayerSet( const QStringList& layers )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
mLayerSet = layers;
updateFullExtent();
}
@@ -1124,9 +1251,81 @@
void QgsMapRenderer::setLabelingEngine( QgsLabelingEngineInterface* iface )
{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
if ( mLabelingEngine )
delete mLabelingEngine;
mLabelingEngine = iface;
}
+
+void QgsMapRenderer::setScale( double scale )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ mScale = scale;
+}
+
+void QgsMapRenderer::enableOverviewMode( bool isOverview )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ mOverview = isOverview;
+}
+
+void QgsMapRenderer::setOutputUnits( OutputUnits u )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ mOutputUnits = u;
+}
+
+void QgsMapRenderer::setThreadingEnabled( bool use )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ mThreadingEnabled = use;
+}
+
+void QgsMapRenderer::setCachingEnabled( bool enabled )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ mCachingEnabled = enabled;
+}
+
+void QgsMapRenderer::setAntialiasingEnabled( bool enabled )
+{
+ if ( mDrawing )
+ {
+ QgsDebugMsg("Ignored --- drawing now!");
+ return; // do not allow changes while rendering
+ }
+
+ mAntialiasingEnabled = enabled;
+}
Modified: branches/threading-branch/src/core/qgsmaprenderer.h
===================================================================
--- branches/threading-branch/src/core/qgsmaprenderer.h 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/core/qgsmaprenderer.h 2010-06-13 22:06:25 UTC (rev 13728)
@@ -19,6 +19,10 @@
#include <QSize>
#include <QStringList>
+#include <QFuture>
+#include <QFutureWatcher>
+#include <QTime>
+#include <QImage>
#include "qgis.h"
#include "qgsrectangle.h"
@@ -38,8 +42,16 @@
class QgsVectorLayer;
class QgsFeature;
-struct ThreadedRenderContext;
+typedef struct ThreadedRenderContext
+{
+ QgsMapRenderer* mr; // renderer that governs the rendering
+ QgsMapLayer* ml; // source map layer
+ QImage* img; // destination image
+ QgsRenderContext ctx; // private render context
+} ThreadedRenderContext;
+
+
/** Labeling engine interface.
* \note Added in QGIS v1.4
*/
@@ -104,7 +116,7 @@
double scale() const { return mScale; }
/**Sets scale for scale based visibility. Normally, the scale is calculated automatically. This
function is only used to force a preview scale (e.g. for print composer)*/
- void setScale( double scale ) {mScale = scale;}
+ void setScale( double scale );
double mapUnitsPerPixel() const { return mMapUnitsPerPixel; }
int width() const { return mSize.width(); };
@@ -119,7 +131,7 @@
void setMapUnits( QGis::UnitType u );
//! sets whether map image will be for overview
- void enableOverviewMode( bool isOverview = true ) { mOverview = isOverview; }
+ void enableOverviewMode( bool isOverview = true );
void setOutputSize( QSize size, int dpi );
@@ -152,7 +164,7 @@
//! returns CRS ID of destination spatial reference system
const QgsCoordinateReferenceSystem& destinationSrs();
- void setOutputUnits( OutputUnits u ) {mOutputUnits = u;}
+ void setOutputUnits( OutputUnits u );
OutputUnits outputUnits() const {return mOutputUnits;}
@@ -188,7 +200,7 @@
//! Enable or disable rendering in multiple threads on multiprocessor computers
//! Added in QGIS v1.6
- void setThreadingEnabled( bool use ) { mThreadingEnabled = use; }
+ void setThreadingEnabled( bool use );
//! Determine whether we are using threaded rendering
//! Added in QGIS v1.6
@@ -196,14 +208,46 @@
//! Enable or disable caching of rendered layers
//! Added in QGIS v1.6
- void setCachingEnabled( bool enabled ) { mCachingEnabled = enabled; }
+ void setCachingEnabled( bool enabled );
//! Determine whether the rendered layers are cached
//! Added in QGIS v1.6
bool isCachingEnabled() const { return mCachingEnabled; }
+ //! Added in QGIS v1.6
+ void setAntialiasingEnabled( bool enabled );
+
+ //! Added in QGIS v1.6
+ bool isAntialiasingEnabled() const { return mAntialiasingEnabled; }
+
+ //! Schedule a redraw of the layers.
+ //! This function returns immediately after starting the asynchronous rendering process.
+ //! Any previous rendering operations must be finished/canceled first.
+ //! Added in QGIS v1.6
+ void startThreadedRendering();
+
+ //! Cancel pending asynchronous rendering. Waits until the rendering is canceled.
+ //! Does nothing if no asynchronous rendering is running.
+ //! Added in QGIS v1.6
+ void cancelThreadedRendering();
+
+ //! Return the intermediate output of the asynchronous rendering.
+ //! An invalid image is returned when the rendering has finished.
+ //! (to obtain the final output image, use finishedThreadedRendering signal)
+ //! Added in QGIS v1.6
+ QImage threadedRenderingOutput();
+
+ //! Tell whether the rendering takes place
+ //! Added in QGIS v1.6
+ bool isDrawing() const { return mDrawing; }
+
signals:
+ //! emitted when asynchronous rendering is finished (or canceled).
+ //! The passed image is the result of the rendering process.
+ //! Added in QGIS v1.6
+ void finishedThreadedRendering(QImage i);
+
void drawingProgress( int current, int total );
void hasCrsTransformEnabled( bool flag );
@@ -222,6 +266,8 @@
//! called by signal from layer current being drawn
void onDrawingProgress( int current, int total );
+ void futureFinished();
+
protected:
//! adjust extent to fit the pixmap size
@@ -235,14 +281,20 @@
*/
bool splitLayersExtent( QgsMapLayer* layer, QgsRectangle& extent, QgsRectangle& r2 );
+ //! initialize the rendering process
+ void initRendering( QPainter* painter, double deviceDpi );
+
+ //! finalize the rendering process (labeling, overlays)
+ void finishRendering();
+
//! render the whole layer set
- void renderLayers( QgsOverlayObjectPositionManager* overlayManager );
+ void renderLayers();
//! render one layer
void renderLayerNoThreading( QgsMapLayer* ml );
//! schedule rendering of a layer
- void renderLayerThreading( QgsMapLayer* ml, QList<ThreadedRenderContext>& lst );
+ void renderLayerThreading( QgsMapLayer* ml );
//! invoke rendering of the layer with given context
bool renderLayer( QgsMapLayer* ml, QgsRenderContext& ctx );
@@ -300,9 +352,6 @@
//! tool for measuring
QgsDistanceArea* mDistArea;
- //!Encapsulates context of rendering
- QgsRenderContext mRenderContext;
-
//!Output units
OutputUnits mOutputUnits;
@@ -314,6 +363,18 @@
//! Render caching
bool mCachingEnabled;
+
+ bool mAntialiasingEnabled;
+
+ QFuture<void> mFuture;
+ QFutureWatcher<void> mFW;
+
+ // variables valid only while rendering:
+ QTime mRenderTime;
+ QgsOverlayObjectPositionManager* mOverlayManager;
+ //!Encapsulates context of rendering
+ QgsRenderContext mRenderContext;
+ QList<ThreadedRenderContext> mThreadedJobs;
};
#endif
Modified: branches/threading-branch/src/core/qgsvectorlayer.cpp
===================================================================
--- branches/threading-branch/src/core/qgsvectorlayer.cpp 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/core/qgsvectorlayer.cpp 2010-06-13 22:06:25 UTC (rev 13728)
@@ -705,10 +705,6 @@
mRendererV2->startRender( rendererContext, this );
-#ifndef Q_WS_MAC
- int featureCount = 0;
-#endif //Q_WS_MAC
-
QgsFeature fet;
while ( nextFeature( fet ) )
{
@@ -719,20 +715,6 @@
break;
}
-#ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
- if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
- {
- emit screenUpdateRequested();
- // emit drawingProgress( featureCount, totalFeatures );
- qApp->processEvents();
- }
- else if ( featureCount % 1000 == 0 )
- {
- // emit drawingProgress( featureCount, totalFeatures );
- qApp->processEvents();
- }
-#endif //Q_WS_MAC
-
bool sel = mSelectedFeatureIds.contains( fet.id() );
bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) );
@@ -754,9 +736,6 @@
QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Ignoring this feature. %2" )
.arg( fet.typeName() ).arg( cse.what() ) );
}
-#ifndef Q_WS_MAC
- ++featureCount;
-#endif //Q_WS_MAC
}
}
@@ -781,9 +760,6 @@
// 1. fetch features
QgsFeature fet;
-#ifndef Q_WS_MAC
- int featureCount = 0;
-#endif //Q_WS_MAC
while ( nextFeature( fet ) )
{
if ( rendererContext.renderingStopped() )
@@ -791,12 +767,6 @@
stopRendererV2( rendererContext, selRenderer );
return;
}
-#ifndef Q_WS_MAC
- if ( featureCount % 1000 == 0 )
- {
- qApp->processEvents();
- }
-#endif //Q_WS_MAC
QgsSymbolV2* sym = mRendererV2->symbolForFeature( fet );
if ( !features.contains( sym ) )
{
@@ -812,9 +782,6 @@
// Cache this for the use of (e.g.) modifying the feature's uncommitted geometry.
mCachedGeometries[fet.id()] = *fet.geometry();
}
-#ifndef Q_WS_MAC
- ++featureCount;
-#endif //Q_WS_MAC
}
// find out the order
@@ -848,9 +815,6 @@
int layer = item.layer();
QList<QgsFeature>& lst = features[item.symbol()];
QList<QgsFeature>::iterator fit;
-#ifndef Q_WS_MAC
- featureCount = 0;
-#endif //Q_WS_MAC
for ( fit = lst.begin(); fit != lst.end(); ++fit )
{
if ( rendererContext.renderingStopped() )
@@ -858,12 +822,6 @@
stopRendererV2( rendererContext, selRenderer );
return;
}
-#ifndef Q_WS_MAC
- if ( featureCount % 1000 == 0 )
- {
- qApp->processEvents();
- }
-#endif //Q_WS_MAC
bool sel = mSelectedFeatureIds.contains( fit->id() );
// maybe vertex markers should be drawn only during the last pass...
bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) );
@@ -877,9 +835,6 @@
QgsDebugMsg( QString( "Failed to transform a point while drawing a feature of type '%1'. Ignoring this feature. %2" )
.arg( fet.typeName() ).arg( cse.what() ) );
}
-#ifndef Q_WS_MAC
- ++featureCount;
-#endif //Q_WS_MAC
}
}
}
@@ -998,22 +953,6 @@
break;
}
-#ifndef Q_WS_MAC //MH: disable this on Mac for now to avoid problems with resizing
- if ( mUpdateThreshold > 0 && 0 == featureCount % mUpdateThreshold )
- {
- emit screenUpdateRequested();
- // emit drawingProgress( featureCount, totalFeatures );
- qApp->processEvents();
- }
- else if ( featureCount % 1000 == 0 )
- {
- // emit drawingProgress( featureCount, totalFeatures );
- qApp->processEvents();
- }
-// #else
-// Q_UNUSED( totalFeatures );
-#endif //Q_WS_MAC
-
// check if feature is selected
// only show selections of the current layer
// TODO: create a mechanism to let layer know whether it's current layer or not [MD]
Modified: branches/threading-branch/src/gui/qgsmapcanvas.cpp
===================================================================
--- branches/threading-branch/src/gui/qgsmapcanvas.cpp 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/gui/qgsmapcanvas.cpp 2010-06-13 22:06:25 UTC (rev 13728)
@@ -91,7 +91,6 @@
mMapTool = NULL;
mLastNonZoomMapTool = NULL;
- mDrawing = false;
mFrozen = false;
mDirty = true;
@@ -104,6 +103,7 @@
setFocusPolicy( Qt::StrongFocus );
mMapRenderer = new QgsMapRenderer;
+ connect(mMapRenderer, SIGNAL(finishedThreadedRendering(QImage)), SLOT(renderingFinished(QImage)));
// create map canvas item which will show the map
mMap = new QgsMapCanvasMap( this );
@@ -112,7 +112,7 @@
moveCanvasContents( true );
- //connect(mMapRenderer, SIGNAL(updateMap()), this, SLOT(updateMap()));
+ connect( &mMapUpdateTimer, SIGNAL(timeout()), this, SLOT(updateMap()));
connect( mMapRenderer, SIGNAL( drawError( QgsMapLayer* ) ), this, SLOT( showError( QgsMapLayer* ) ) );
// project handling
@@ -126,6 +126,8 @@
QgsMapCanvas::~QgsMapCanvas()
{
+ cancelRendering();
+
if ( mMapTool )
{
mMapTool->deactivate();
@@ -155,7 +157,8 @@
void QgsMapCanvas::enableAntiAliasing( bool theFlag )
{
- mMap->enableAntiAliasing( theFlag );
+ mMapRenderer->setAntialiasingEnabled( theFlag );
+
if ( mMapOverview )
mMapOverview->enableAntiAliasing( theFlag );
} // anti aliasing
@@ -211,7 +214,7 @@
bool QgsMapCanvas::isDrawing()
{
- return mDrawing;
+ return mMapRenderer->isDrawing();
} // isDrawing
@@ -224,7 +227,7 @@
void QgsMapCanvas::setLayerSet( QList<QgsMapCanvasLayer> &layers )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -264,7 +267,6 @@
// Ticket #811 - racicot
QgsMapLayer *currentLayer = layer( i );
disconnect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
- disconnect( currentLayer, SIGNAL( screenUpdateRequested() ), this, SLOT( updateMap() ) );
QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
if ( isVectLyr )
{
@@ -280,7 +282,6 @@
// Ticket #811 - racicot
QgsMapLayer *currentLayer = layer( i );
connect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
- connect( currentLayer, SIGNAL( screenUpdateRequested() ), this, SLOT( updateMap() ) );
QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
if ( isVectLyr )
{
@@ -359,47 +360,37 @@
void QgsMapCanvas::refresh()
{
- // we can't draw again if already drawing...
- if ( mDrawing )
+ if ( !mRenderFlag || mFrozen )
return;
- mDrawing = true;
+ cancelRendering();
- if ( mRenderFlag && !mFrozen )
- {
- clear();
+ clear();
- // Tell the user we're going to be a while
- QApplication::setOverrideCursor( Qt::WaitCursor );
+ // Tell the user we're going to be a while
+ //QApplication::setOverrideCursor( Qt::WaitCursor );
- emit renderStarting();
+ emit renderStarting();
- mMap->render();
+ // TRIGGER RENDERING
+ //mMap->render();
+ qDebug("STARTING \n\n\n\n\n");
+ mMapRenderer->startThreadedRendering();
- mDirty = false;
+ mMapUpdateTimer.start(250);
- // notify any listeners that rendering is complete
- QPainter p;
- p.begin( &mMap->paintDevice() );
- emit renderComplete( &p );
- p.end();
+ updateMap();
- // notifies current map tool
- if ( mMapTool )
- mMapTool->renderComplete();
-
- // Tell the user we've finished going to be a while
- QApplication::restoreOverrideCursor();
- }
-
- mDrawing = false;
} // refresh
void QgsMapCanvas::updateMap()
{
- if ( mMap )
+ QgsDebugMsg("updating map!");
+ QImage i = mMapRenderer->threadedRenderingOutput();
+ if (!i.isNull())
{
- mMap->updateContents();
+ mMap->setMap(i);
+ mMap->update();
}
}
@@ -482,7 +473,7 @@
void QgsMapCanvas::setExtent( QgsRectangle const & r )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -551,7 +542,7 @@
void QgsMapCanvas::zoomToFullExtent()
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -572,7 +563,7 @@
void QgsMapCanvas::zoomToPreviousExtent()
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -595,7 +586,7 @@
void QgsMapCanvas::zoomToNextExtent()
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -650,7 +641,7 @@
void QgsMapCanvas::zoomToSelected( QgsVectorLayer* layer )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -698,7 +689,7 @@
void QgsMapCanvas::keyPressEvent( QKeyEvent * e )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
e->ignore();
}
@@ -799,7 +790,7 @@
{
QgsDebugMsg( "keyRelease event" );
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -835,7 +826,7 @@
void QgsMapCanvas::mouseDoubleClickEvent( QMouseEvent * e )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -848,10 +839,6 @@
void QgsMapCanvas::mousePressEvent( QMouseEvent * e )
{
- if ( mDrawing )
- {
- return;
- }
//use middle mouse button for panning, map tools won't receive any events in that case
if ( e->button() == Qt::MidButton )
@@ -880,11 +867,6 @@
void QgsMapCanvas::mouseReleaseEvent( QMouseEvent * e )
{
- if ( mDrawing )
- {
- return;
- }
-
//use middle mouse button for panning, map tools won't receive any events in that case
if ( e->button() == Qt::MidButton )
{
@@ -925,25 +907,11 @@
void QgsMapCanvas::resizeEvent( QResizeEvent * e )
{
- static bool isAlreadyIn = false;
static QSize lastSize = QSize( -1, -1 );
lastSize = e->size();
- if ( isAlreadyIn || mDrawing )
- {
- //cancel current render progress
- if ( mMapRenderer )
- {
- QgsRenderContext* theRenderContext = mMapRenderer->rendererContext();
- if ( theRenderContext )
- {
- theRenderContext->setRenderingStopped( true );
- }
- }
- return;
- }
- isAlreadyIn = true;
+ cancelRendering();
while ( lastSize != QSize( -1, -1 ) )
{
@@ -968,7 +936,6 @@
#endif
emit extentsChanged();
}
- isAlreadyIn = false;
} // resizeEvent
@@ -997,10 +964,7 @@
QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
- if ( mDrawing )
- {
- return;
- }
+ cancelRendering();
switch ( mWheelAction )
{
@@ -1064,7 +1028,7 @@
void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -1081,11 +1045,6 @@
void QgsMapCanvas::mouseMoveEvent( QMouseEvent * e )
{
- if ( mDrawing )
- {
- return;
- }
-
mCanvasProperties->mouseLastXY = e->pos();
if ( mCanvasProperties->panSelectorDown )
@@ -1245,19 +1204,15 @@
void QgsMapCanvas::setRenderFlag( bool theFlag )
{
mRenderFlag = theFlag;
- if ( mMapRenderer )
- {
- QgsRenderContext* rc = mMapRenderer->rendererContext();
- if ( rc )
- {
- rc->setRenderingStopped( !theFlag );
- }
- }
if ( mRenderFlag )
{
refresh();
}
+ else
+ {
+ cancelRendering();
+ }
}
void QgsMapCanvas::connectNotify( const char * signal )
@@ -1274,7 +1229,7 @@
void QgsMapCanvas::panActionEnd( QPoint releasePoint )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -1322,24 +1277,14 @@
void QgsMapCanvas::panAction( QMouseEvent * e )
{
- if ( mDrawing )
- {
- return;
- }
+ cancelRendering();
// move all map canvas items
moveCanvasContents();
-
- // update canvas
- //updateContents(); // TODO: need to update?
}
void QgsMapCanvas::moveCanvasContents( bool reset )
{
- if ( mDrawing )
- {
- return;
- }
QPoint pnt( 0, 0 );
if ( !reset )
@@ -1431,7 +1376,7 @@
void QgsMapCanvas::zoomByFactor( double scaleFactor )
{
- if ( mDrawing )
+ if ( isDrawing() )
{
return;
}
@@ -1449,3 +1394,35 @@
emit selectionChanged( layer );
refresh();
}
+
+void QgsMapCanvas::renderingFinished(QImage img)
+{
+ QgsDebugMsg("finished!!!");
+ mMapUpdateTimer.stop();
+
+ mDirty = false;
+
+ // notify any listeners that rendering is complete
+ QPainter p;
+ p.begin( &img );
+ emit renderComplete( &p );
+ p.end();
+
+ mMap->setMap(img);
+ mMap->update();
+
+ // notifies current map tool
+ if ( mMapTool )
+ mMapTool->renderComplete();
+
+ // Tell the user we've finished going to be a while
+ //QApplication::restoreOverrideCursor();
+}
+
+void QgsMapCanvas::cancelRendering()
+{
+ if ( isDrawing() )
+ {
+ mMapRenderer->cancelThreadedRendering();
+ }
+}
Modified: branches/threading-branch/src/gui/qgsmapcanvas.h
===================================================================
--- branches/threading-branch/src/gui/qgsmapcanvas.h 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/gui/qgsmapcanvas.h 2010-06-13 22:06:25 UTC (rev 13728)
@@ -30,6 +30,7 @@
#include <QDomDocument>
#include <QGraphicsView>
#include <QtCore>
+#include <QTimer>
class QWheelEvent;
class QPixmap;
@@ -255,7 +256,12 @@
//! returns last position of mouse cursor
QPoint mouseLastXY();
+ //! force stop of the rendering process
+ void cancelRendering();
+
public slots:
+ //! Called when asynchronous rendering is finished
+ void renderingFinished(QImage img);
/**Repaints the canvas map*/
void refresh();
@@ -400,7 +406,7 @@
QgsMapOverviewCanvas* mMapOverview;
//! Flag indicating a map refresh is in progress
- bool mDrawing;
+ //bool mDrawing;
//! Flag indicating if the map canvas is frozen.
bool mFrozen;
@@ -451,6 +457,8 @@
//! Mouse wheel action
WheelAction mWheelAction;
+ QTimer mMapUpdateTimer;
+
}; // class QgsMapCanvas
Modified: branches/threading-branch/src/gui/qgsmapcanvasmap.cpp
===================================================================
--- branches/threading-branch/src/gui/qgsmapcanvasmap.cpp 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/gui/qgsmapcanvasmap.cpp 2010-06-13 22:06:25 UTC (rev 13728)
@@ -28,6 +28,7 @@
setPos( 0, 0 );
resize( QSize( 1, 1 ) );
mUseQImageToRender = false;
+
}
void QgsMapCanvasMap::paint( QPainter* p, const QStyleOptionGraphicsItem*, QWidget* )
@@ -47,7 +48,8 @@
prepareGeometryChange(); // to keep QGraphicsScene indexes up to date on size change
mPixmap = QPixmap( size );
- mImage = QImage( size, QImage::Format_RGB32 ); // temporary image - build it here so it is available when switching from QPixmap to QImage rendering
+ mPixmap.fill(mBgColor.rgb());
+ //mImage = QImage( size, QImage::Format_RGB32 ); // temporary image - build it here so it is available when switching from QPixmap to QImage rendering
mCanvas->mapRenderer()->setOutputSize( size, mPixmap.logicalDpiX() );
}
@@ -59,6 +61,7 @@
void QgsMapCanvasMap::render()
{
+ /*
// Rendering to a QImage gives incorrectly filled polygons in some
// cases (as at Qt4.1.4), but it is the only renderer that supports
// anti-aliasing, so we provide the means to swap between QImage and
@@ -101,6 +104,7 @@
paint.end();
}
update();
+ */
}
QPaintDevice& QgsMapCanvasMap::paintDevice()
@@ -110,10 +114,12 @@
void QgsMapCanvasMap::updateContents()
{
+ /*
// make sure we're using current contents
if ( mUseQImageToRender )
mPixmap = QPixmap::fromImage( mImage );
// trigger update of this item
update();
+ */
}
Modified: branches/threading-branch/src/gui/qgsmapcanvasmap.h
===================================================================
--- branches/threading-branch/src/gui/qgsmapcanvasmap.h 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/gui/qgsmapcanvasmap.h 2010-06-13 22:06:25 UTC (rev 13728)
@@ -42,6 +42,7 @@
void useImageToRender( bool flag ) { mUseQImageToRender = flag; }
//! renders map using QgsMapRenderer to mPixmap
+ //! @deprecated does nothing
void render();
void setBackgroundColor( const QColor& color ) { mBgColor = color; }
@@ -60,8 +61,11 @@
//! Update contents - can be called while drawing to show the status.
//! Added in version 1.2
+ //! @deprecated does nothing
void updateContents();
+ void setMap(QImage img) { mPixmap = QPixmap::fromImage(img); }
+
private:
//! indicates whether antialiasing will be used for rendering
@@ -71,7 +75,7 @@
bool mUseQImageToRender;
QPixmap mPixmap;
- QImage mImage;
+ //QImage mImage;
//QgsMapRenderer* mRender;
QgsMapCanvas* mCanvas;
Modified: branches/threading-branch/src/gui/qgsmapoverviewcanvas.cpp
===================================================================
--- branches/threading-branch/src/gui/qgsmapoverviewcanvas.cpp 2010-06-13 20:33:14 UTC (rev 13727)
+++ branches/threading-branch/src/gui/qgsmapoverviewcanvas.cpp 2010-06-13 22:06:25 UTC (rev 13728)
@@ -251,8 +251,7 @@
painter.begin( &mPixmap );
// antialiasing
- if ( mAntiAliasing )
- painter.setRenderHint( QPainter::Antialiasing );
+ mMapRenderer->setAntialiasingEnabled( mAntiAliasing );
// render image
mMapRenderer->render( &painter );
More information about the QGIS-commit
mailing list