25 #include <QtConcurrentRun>
43 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
48 QPaintDevice *paintDevice = painter->device();
49 QString errMsg = QStringLiteral(
"pre-set DPI not equal to painter's DPI (%1 vs %2)" )
50 .arg( paintDevice->logicalDpiX() )
53 "Job::startRender()", errMsg.toLatin1().data() );
66 , mRenderSynchronously( false )
74 Q_ASSERT( !mFutureWatcher.isRunning() );
78 void QgsMapRendererCustomPainterJob::startPrivate()
92 QgsDebugMsgLevel( QStringLiteral(
"Preparing list of layer jobs for rendering" ), 5 );
93 QElapsedTimer prepareTime;
98 mLabelingEngineV2.reset();
103 mLabelingEngineV2->setMapSettings(
mSettings );
107 mLayerJobs =
prepareJobs( mPainter, mLabelingEngineV2.get() );
108 mLabelJob =
prepareLabelingJob( mPainter, mLabelingEngineV2.get(), canUseLabelCache );
111 QgsDebugMsgLevel( QStringLiteral(
"Rendering prepared in (seconds): %1" ).arg( prepareTime.elapsed() / 1000.0 ), 4 );
113 if ( mRenderSynchronously )
124 connect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
126 mFuture = QtConcurrent::run( staticRender,
this );
127 mFutureWatcher.setFuture( mFuture );
140 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
146 mFutureWatcher.waitForFinished();
148 QgsDebugMsgLevel( QStringLiteral(
"QPAINER cancel waited %1 ms" ).arg( t.elapsed() / 1000.0 ), 5 );
159 QgsDebugMsg( QStringLiteral(
"QPAINTER not running!" ) );
163 mLabelJob.context.setRenderingStopped(
true );
164 for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
166 it->context.setRenderingStopped(
true );
167 if ( it->renderer && it->renderer->feedback() )
168 it->renderer->feedback()->cancel();
177 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
182 mFutureWatcher.waitForFinished();
184 QgsDebugMsgLevel( QStringLiteral(
"waitForFinished: %1 ms" ).arg( t.elapsed() / 1000.0 ), 4 );
196 return mLabelJob.cached;
201 if ( mLabelingEngineV2 )
202 return mLabelingEngineV2->takeResults();
211 connect( &mFutureWatcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit );
218 mRenderSynchronously =
true;
221 mRenderSynchronously =
false;
226 mRenderSynchronously =
true;
239 mRenderSynchronously =
false;
240 mPrepareOnly =
false;
244 void QgsMapRendererCustomPainterJob::futureFinished()
274 catch ( std::exception &e )
277 QgsDebugMsg(
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
281 QgsDebugMsg( QStringLiteral(
"Caught unhandled unknown exception" ) );
285 void QgsMapRendererCustomPainterJob::doRender()
287 bool hasSecondPass = ! mSecondPassLayerJobs.isEmpty();
289 QElapsedTimer renderTime;
292 for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
294 LayerRenderJob &job = *it;
296 if ( job.context.renderingStopped() )
299 if ( ! hasSecondPass && job.context.useAdvancedEffects() )
303 mPainter->setCompositionMode( job.blendMode );
308 QElapsedTimer layerTime;
314 job.imageInitialized =
true;
317 job.completed = job.renderer->render();
319 job.renderingTime += layerTime.elapsed();
322 if ( ! hasSecondPass && job.img )
325 mPainter->setOpacity( job.opacity );
326 mPainter->drawImage( 0, 0, *job.img );
327 mPainter->setOpacity( 1.0 );
336 if ( !mLabelJob.cached )
338 QElapsedTimer labelTime;
344 mLabelJob.img->fill( 0 );
345 painter.begin( mLabelJob.img );
346 mLabelJob.context.setPainter( &painter );
347 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
352 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), mPainter );
355 mLabelJob.complete =
true;
356 mLabelJob.renderingTime = labelTime.elapsed();
357 mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
361 if ( ! hasSecondPass )
363 if ( mLabelJob.img && mLabelJob.complete )
365 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
366 mPainter->setOpacity( 1.0 );
367 mPainter->drawImage( 0, 0, *mLabelJob.img );
372 for ( LayerRenderJob &job : mSecondPassLayerJobs )
374 if ( job.context.renderingStopped() )
379 QElapsedTimer layerTime;
385 job.imageInitialized =
true;
388 job.completed = job.renderer->render();
390 job.renderingTime += layerTime.elapsed();
398 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
399 mPainter->setOpacity( 1.0 );
400 mPainter->drawImage( 0, 0, finalImage );
403 QgsDebugMsgLevel( QStringLiteral(
"Rendering completed in (seconds): %1" ).arg( renderTime.elapsed() / 1000.0 ), 2 );
Default QgsLabelingEngine implementation, which completes the whole labeling operation (including lab...
Defines a QGIS exception class.
Class that stores computed placement from labeling engine.
Abstract base class for map renderer jobs which use custom painters.
void preparePainter(QPainter *painter, const QColor &backgroundColor=Qt::transparent)
Prepares the given painter ready for a map render.
QgsMapRendererAbstractCustomPainterJob(const QgsMapSettings &settings)
Constructor for QgsMapRendererAbstractCustomPainterJob, using the given map settings.
Job implementation that renders everything sequentially using a custom painter.
QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)
~QgsMapRendererCustomPainterJob() override
void renderSynchronously()
Render the map synchronously in this thread.
void cancel() override
Stop the rendering job - does not return until the job has terminated.
void waitForFinishedWithEventLoop(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Wait for the job to be finished - and keep the thread's event loop running while waiting.
void renderPrepared()
Render a pre-prepared job.
QgsLabelingResults * takeLabelingResults() override
Gets pointer to internal labeling engine (in order to get access to the results).
void cancelWithoutBlocking() override
Triggers cancellation of the rendering job without blocking.
void prepare()
Prepares the job for rendering synchronously in a background thread.
void waitForFinished() override
Block until the job has finished.
bool isActive() const override
Tell whether the rendering job is currently running in background.
bool usedCachedLabels() const override
Returns true if the render job was able to use a cached labeling solution.
Abstract base class for map rendering implementations.
void cleanupSecondPassJobs(LayerRenderJobs &jobs)
LayerRenderJobs prepareSecondPassJobs(LayerRenderJobs &firstPassJobs, LabelRenderJob &labelJob)
Prepares jobs for a second pass, if selective masks exist (from labels or symbol layers).
void logRenderingTime(const LayerRenderJobs &jobs, const LayerRenderJobs &secondPassJobs, const LabelRenderJob &labelJob)
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
LayerRenderJobs prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
static void composeSecondPass(LayerRenderJobs &secondPassJobs, LabelRenderJob &labelJob)
Compose second pass images into first pass images.
QElapsedTimer mRenderingStart
void finished()
emitted when asynchronous rendering is finished (or canceled).
static QImage composeImage(const QgsMapSettings &settings, const LayerRenderJobs &jobs, const LabelRenderJob &labelJob, const QgsMapRendererCache *cache=nullptr)
void start()
Start the rendering job and immediately return.
LabelRenderJob prepareLabelingJob(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache=true)
Prepares a labeling job.
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
void cleanupJobs(LayerRenderJobs &jobs)
bool prepareLabelCache() const
Prepares the cache for storing the result of labeling.
The QgsMapSettings class contains configuration for rendering of the map.
QSize deviceOutputSize() const
Returns the device output size of the map render.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
@ Antialiasing
Enable anti-aliasing for map rendering.
@ DrawLabeling
Enable drawing of labels on top of the map.
QColor backgroundColor() const
Returns the background color of the map.
float devicePixelRatio() const
Returns the device pixel ratio.
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugMsgLevel(str, level)