25 #include <QtConcurrentRun> 
   43 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) 
   48   QPaintDevice *paintDevice = painter->device();
 
   49   const 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 ( LayerRenderJob &job : mLayerJobs )
 
  166     job.context()->setRenderingStopped( 
true );
 
  167     if ( job.renderer && job.renderer->feedback() )
 
  168       job.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   const bool hasSecondPass = ! mSecondPassLayerJobs.empty();
 
  289   QElapsedTimer renderTime;
 
  292   for ( LayerRenderJob &job : mLayerJobs )
 
  294     if ( job.context()->renderingStopped() )
 
  297     if ( ! hasSecondPass && job.context()->useAdvancedEffects() )
 
  301       mPainter->setCompositionMode( job.blendMode );
 
  306       QElapsedTimer layerTime;
 
  312         job.imageInitialized = 
true;
 
  315       job.completed = job.renderer->render();
 
  317       job.renderingTime += layerTime.elapsed();
 
  320     if ( ! hasSecondPass && job.img )
 
  323       mPainter->setOpacity( job.opacity );
 
  324       mPainter->drawImage( 0, 0, *job.img );
 
  325       mPainter->setOpacity( 1.0 );
 
  334     if ( !mLabelJob.cached )
 
  336       QElapsedTimer labelTime;
 
  342         mLabelJob.img->fill( 0 );
 
  343         painter.begin( mLabelJob.img );
 
  344         mLabelJob.context.setPainter( &painter );
 
  345         drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
 
  350         drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), mPainter );
 
  353       mLabelJob.complete = 
true;
 
  354       mLabelJob.renderingTime = labelTime.elapsed();
 
  355       mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
 
  359   if ( ! hasSecondPass )
 
  361     if ( mLabelJob.img && mLabelJob.complete )
 
  363       mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
 
  364       mPainter->setOpacity( 1.0 );
 
  365       mPainter->drawImage( 0, 0, *mLabelJob.img );
 
  370     for ( LayerRenderJob &job : mSecondPassLayerJobs )
 
  372       if ( job.context()->renderingStopped() )
 
  377         QElapsedTimer layerTime;
 
  383           job.imageInitialized = 
true;
 
  386         job.completed = job.renderer->render();
 
  388         job.renderingTime += layerTime.elapsed();
 
  396     mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
 
  397     mPainter->setOpacity( 1.0 );
 
  398     mPainter->drawImage( 0, 0, finalImage );
 
  401   QgsDebugMsgLevel( QStringLiteral( 
"Rendering completed in (seconds): %1" ).arg( renderTime.elapsed() / 1000.0 ), 2 );
 
@ 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.
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 logRenderingTime(const std::vector< LayerRenderJob > &jobs, const std::vector< LayerRenderJob > &secondPassJobs, const LabelRenderJob &labelJob)
static void composeSecondPass(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob)
Compose second pass images into first pass images.
static QImage composeImage(const QgsMapSettings &settings, const std::vector< LayerRenderJob > &jobs, const LabelRenderJob &labelJob, const QgsMapRendererCache *cache=nullptr)
void cleanupSecondPassJobs(std::vector< LayerRenderJob > &jobs)
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
std::vector< LayerRenderJob > prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
void cleanupJobs(std::vector< LayerRenderJob > &jobs)
QElapsedTimer mRenderingStart
void finished()
emitted when asynchronous rendering is finished (or canceled).
void start()
Start the rendering job and immediately return.
std::vector< LayerRenderJob > prepareSecondPassJobs(std::vector< LayerRenderJob > &firstPassJobs, LabelRenderJob &labelJob)
Prepares jobs for a second pass, if selective masks exist (from labels or symbol layers).
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...
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.
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 testFlag(Qgis::MapSettingsFlag flag) const
Check whether a particular flag is enabled.
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)