25 #include <QtConcurrentRun> 45 QPaintDevice *paintDevice = painter->device();
46 QString errMsg = QStringLiteral(
"pre-set DPI not equal to painter's DPI (%1 vs %2)" )
47 .arg( paintDevice->logicalDpiX() )
50 "Job::startRender()", errMsg.toLatin1().data() );
63 , mRenderSynchronously( false )
71 Q_ASSERT( !mFutureWatcher.isRunning() );
89 QgsDebugMsgLevel( QStringLiteral(
"Preparing list of layer jobs for rendering" ), 5 );
90 QElapsedTimer prepareTime;
95 mLabelingEngineV2.reset();
100 mLabelingEngineV2->setMapSettings(
mSettings );
104 mLayerJobs =
prepareJobs( mPainter, mLabelingEngineV2.get() );
105 mLabelJob =
prepareLabelingJob( mPainter, mLabelingEngineV2.get(), canUseLabelCache );
108 QgsDebugMsgLevel( QStringLiteral(
"Rendering prepared in (seconds): %1" ).arg( prepareTime.elapsed() / 1000.0 ), 4 );
110 if ( mRenderSynchronously )
121 connect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
123 mFuture = QtConcurrent::run( staticRender,
this );
124 mFutureWatcher.setFuture( mFuture );
137 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
143 mFutureWatcher.waitForFinished();
145 QgsDebugMsgLevel( QStringLiteral(
"QPAINER cancel waited %1 ms" ).arg( t.elapsed() / 1000.0 ), 5 );
156 QgsDebugMsg( QStringLiteral(
"QPAINTER not running!" ) );
160 mLabelJob.context.setRenderingStopped(
true );
161 for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
163 it->context.setRenderingStopped(
true );
164 if ( it->renderer && it->renderer->feedback() )
165 it->renderer->feedback()->cancel();
174 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
179 mFutureWatcher.waitForFinished();
181 QgsDebugMsgLevel( QStringLiteral(
"waitForFinished: %1 ms" ).arg( t.elapsed() / 1000.0 ), 4 );
193 return mLabelJob.cached;
198 if ( mLabelingEngineV2 )
199 return mLabelingEngineV2->takeResults();
208 connect( &mFutureWatcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit );
215 mRenderSynchronously =
true;
218 mRenderSynchronously =
false;
223 mRenderSynchronously =
true;
236 mRenderSynchronously =
false;
237 mPrepareOnly =
false;
241 void QgsMapRendererCustomPainterJob::futureFinished()
271 catch ( std::exception &e )
274 QgsDebugMsg(
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
278 QgsDebugMsg( QStringLiteral(
"Caught unhandled unknown exception" ) );
282 void QgsMapRendererCustomPainterJob::doRender()
284 bool hasSecondPass = ! mSecondPassLayerJobs.isEmpty();
286 QElapsedTimer renderTime;
289 for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
291 LayerRenderJob &job = *it;
293 if ( job.context.renderingStopped() )
296 if ( ! hasSecondPass && job.context.useAdvancedEffects() )
300 mPainter->setCompositionMode( job.blendMode );
305 QElapsedTimer layerTime;
311 job.imageInitialized =
true;
314 job.renderer->render();
316 job.renderingTime += layerTime.elapsed();
319 if ( ! hasSecondPass && job.img )
322 mPainter->setOpacity( job.opacity );
323 mPainter->drawImage( 0, 0, *job.img );
324 mPainter->setOpacity( 1.0 );
333 if ( !mLabelJob.cached )
335 QElapsedTimer labelTime;
341 mLabelJob.img->fill( 0 );
342 painter.begin( mLabelJob.img );
343 mLabelJob.context.setPainter( &painter );
344 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
349 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), mPainter );
352 mLabelJob.complete =
true;
353 mLabelJob.renderingTime = labelTime.elapsed();
354 mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
358 if ( ! hasSecondPass )
360 if ( mLabelJob.img && mLabelJob.complete )
362 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
363 mPainter->setOpacity( 1.0 );
364 mPainter->drawImage( 0, 0, *mLabelJob.img );
369 for ( LayerRenderJob &job : mSecondPassLayerJobs )
371 if ( job.context.renderingStopped() )
376 QElapsedTimer layerTime;
382 job.imageInitialized =
true;
385 job.renderer->render();
387 job.renderingTime += layerTime.elapsed();
395 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
396 mPainter->setOpacity( 1.0 );
397 mPainter->drawImage( 0, 0, finalImage );
400 QgsDebugMsgLevel( QStringLiteral(
"Rendering completed in (seconds): %1" ).arg( renderTime.elapsed() / 1000.0 ), 2 );
QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)
void finished()
emitted when asynchronous rendering is finished (or canceled).
Job implementation that renders everything sequentially using a custom painter.
QElapsedTimer mRenderingStart
Abstract base class for map rendering implementations.
void cleanupJobs(LayerRenderJobs &jobs)
QSize deviceOutputSize() const
Returns the device output size of the map canvas This is equivalent to the output size multiplicated ...
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
void cleanupSecondPassJobs(LayerRenderJobs &jobs)
void preparePainter(QPainter *painter, const QColor &backgroundColor=Qt::transparent)
Prepares the given painter ready for a map render.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QColor backgroundColor() const
Gets the background color of the map.
void logRenderingTime(const LayerRenderJobs &jobs, const LayerRenderJobs &secondPassJobs, const LabelRenderJob &labelJob)
Default QgsLabelingEngine implementation, which completes the whole labeling operation (including lab...
void cancel() override
Stop the rendering job - does not return until the job has terminated.
void prepare()
Prepares the job for rendering synchronously in a background thread.
void waitForFinishedWithEventLoop(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Wait for the job to be finished - and keep the thread's event loop running while waiting.
Enable drawing of labels on top of the map.
The QgsMapSettings class contains configuration for rendering of the map.
static QImage composeImage(const QgsMapSettings &settings, const LayerRenderJobs &jobs, const LabelRenderJob &labelJob)
LabelRenderJob prepareLabelingJob(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache=true)
Prepares a labeling job.
bool prepareLabelCache() const
Prepares the cache for storing the result of labeling.
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
void start() override
Start the rendering job and immediately return.
void renderPrepared()
Render a pre-prepared job.
#define QgsDebugMsgLevel(str, level)
Abstract base class for map renderer jobs which use custom painters.
Enable anti-aliasing for map rendering.
bool usedCachedLabels() const override
Returns true if the render job was able to use a cached labeling solution.
float devicePixelRatio() const
Returns device pixel ratio Common values are 1 for normal-dpi displays and 2 for high-dpi "retina" di...
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
void cancelWithoutBlocking() override
Triggers cancellation of the rendering job without blocking.
double outputDpi() const
Returns DPI used for conversion between real world units (e.g.
LayerRenderJobs prepareSecondPassJobs(LayerRenderJobs &firstPassJobs, LabelRenderJob &labelJob)
Prepares jobs for a second pass, if selective masks exist (from labels or symbol layers).
~QgsMapRendererCustomPainterJob() override
static void composeSecondPass(LayerRenderJobs &secondPassJobs, LabelRenderJob &labelJob)
Compose second pass images into first pass images.
Class that stores computed placement from labeling engine.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
QgsLabelingResults * takeLabelingResults() override
Gets pointer to internal labeling engine (in order to get access to the results). ...
QgsMapRendererAbstractCustomPainterJob(const QgsMapSettings &settings)
Constructor for QgsMapRendererAbstractCustomPainterJob, using the given map settings.
void waitForFinished() override
Block until the job has finished.
Defines a QGIS exception class.
void renderSynchronously()
Render the map synchronously in this thread.
bool isActive() const override
Tell whether the rendering job is currently running in background.