17#include "moc_qgsmaprenderercustompainterjob.cpp" 
   27#include <QtConcurrentRun> 
   49  QPaintDevice *paintDevice = painter->device();
 
   50  const QString errMsg = QStringLiteral( 
"pre-set DPI not equal to painter's DPI (%1 vs %2)" )
 
   51                         .arg( paintDevice->logicalDpiX() )
 
   54              "Job::startRender()", errMsg.toLatin1().data() );
 
 
   67  , mRenderSynchronously( false )
 
 
   75  Q_ASSERT( !mFutureWatcher.isRunning() );
 
 
   79void QgsMapRendererCustomPainterJob::startPrivate()
 
   93  QgsDebugMsgLevel( QStringLiteral( 
"Preparing list of layer jobs for rendering" ), 5 );
 
   94  QElapsedTimer prepareTime;
 
   99  mLabelingEngineV2.reset();
 
  104    mLabelingEngineV2->setMapSettings( 
mSettings );
 
  108  mLayerJobs = 
prepareJobs( mPainter, mLabelingEngineV2.get() );
 
  109  mLabelJob = 
prepareLabelingJob( mPainter, mLabelingEngineV2.get(), canUseLabelCache );
 
  112  QgsDebugMsgLevel( QStringLiteral( 
"Rendering prepared in (seconds): %1" ).arg( prepareTime.elapsed() / 1000.0 ), 4 );
 
  114  if ( mRenderSynchronously )
 
  125  connect( &mFutureWatcher, &QFutureWatcher<void>::finished, 
this, &QgsMapRendererCustomPainterJob::futureFinished );
 
  127  mFuture = QtConcurrent::run( staticRender, 
this );
 
  128  mFutureWatcher.setFuture( mFuture );
 
  141  disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished, 
this, &QgsMapRendererCustomPainterJob::futureFinished );
 
  147  mFutureWatcher.waitForFinished();
 
  149  QgsDebugMsgLevel( QStringLiteral( 
"QPAINER cancel waited %1 ms" ).arg( t.elapsed() / 1000.0 ), 5 );
 
 
  164  mLabelJob.context.setRenderingStopped( 
true );
 
  165  for ( LayerRenderJob &job : mLayerJobs )
 
  167    job.context()->setRenderingStopped( 
true );
 
  168    if ( job.renderer && job.renderer->feedback() )
 
  169      job.renderer->feedback()->cancel();
 
 
  178  disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished, 
this, &QgsMapRendererCustomPainterJob::futureFinished );
 
  183  mFutureWatcher.waitForFinished();
 
  185  QgsDebugMsgLevel( QStringLiteral( 
"waitForFinished: %1 ms" ).arg( t.elapsed() / 1000.0 ), 4 );
 
 
  197  return mLabelJob.cached;
 
 
  202  if ( mLabelingEngineV2 )
 
  203    return mLabelingEngineV2->takeResults();
 
 
  212  connect( &mFutureWatcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit );
 
 
  219  mRenderSynchronously = 
true;
 
  222  mRenderSynchronously = 
false;
 
 
  227  mRenderSynchronously = 
true;
 
 
  240  mRenderSynchronously = 
false;
 
  241  mPrepareOnly = 
false;
 
 
  245void QgsMapRendererCustomPainterJob::futureFinished()
 
  275  catch ( std::exception &e )
 
  278    QgsDebugError( 
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
 
  282    QgsDebugError( QStringLiteral( 
"Caught unhandled unknown exception" ) );
 
  286void QgsMapRendererCustomPainterJob::doRender()
 
  288  const bool hasSecondPass = ! mSecondPassLayerJobs.empty();
 
  290  QElapsedTimer renderTime;
 
  294  std::unique_ptr<QgsElevationMap> mainElevationMap;
 
  295  if ( mapShadingRenderer.
isActive() )
 
  298  for ( LayerRenderJob &job : mLayerJobs )
 
  300    if ( job.context()->renderingStopped() )
 
  311      mPainter->setCompositionMode( job.blendMode );
 
  316      QElapsedTimer layerTime;
 
  319      if ( job.previewRenderImage && !job.previewRenderImageInitialized )
 
  321        job.previewRenderImage->fill( 0 );
 
  322        job.previewRenderImageInitialized = 
true;
 
  328        job.imageInitialized = 
true;
 
  331      job.completed = job.renderer->render();
 
  335        job.renderer->renderContext()->painter()->end();
 
  338      job.renderingTime += layerTime.elapsed();
 
  341    if ( ! hasSecondPass && job.img )
 
  344      mPainter->setOpacity( job.opacity );
 
  345      mPainter->drawImage( 0, 0, *job.img );
 
  346      mPainter->setOpacity( 1.0 );
 
  349    if ( mainElevationMap && job.context()->elevationMap() )
 
  351      const QgsElevationMap &layerElevationMap = *job.context()->elevationMap();
 
  352      if ( layerElevationMap.
isValid() )
 
  362  if ( mapShadingRenderer.
isActive() &&  mainElevationMap )
 
  364    QImage image( mainElevationMap->rawElevationImage().size(), QImage::Format_RGB32 );
 
  366    image.fill( Qt::white );
 
  369    mPainter->setCompositionMode( QPainter::CompositionMode_Multiply );
 
  370    mPainter->drawImage( 0, 0, image );
 
  376    if ( !mLabelJob.cached )
 
  378      QElapsedTimer labelTime;
 
  384        mLabelJob.img->fill( 0 );
 
  385        painter.begin( mLabelJob.img );
 
  386        mLabelJob.context.setPainter( &painter );
 
  387        drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
 
  390      else if ( mLabelJob.picture )
 
  393        painter.begin( mLabelJob.picture.get() );
 
  394        mLabelJob.context.setPainter( &painter );
 
  395        drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
 
  400        drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), mPainter );
 
  403      mLabelJob.complete = 
true;
 
  404      mLabelJob.renderingTime = labelTime.elapsed();
 
  409  if ( ! hasSecondPass )
 
  411    if ( mLabelJob.img && mLabelJob.complete )
 
  413      mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
 
  414      mPainter->setOpacity( 1.0 );
 
  415      mPainter->drawImage( 0, 0, *mLabelJob.img );
 
  422    for ( LayerRenderJob &job : mSecondPassLayerJobs )
 
  424      if ( job.context()->renderingStopped() )
 
  429        QElapsedTimer layerTime;
 
  432        if ( job.previewRenderImage && !job.previewRenderImageInitialized )
 
  434          job.previewRenderImage->fill( 0 );
 
  435          job.previewRenderImageInitialized = 
true;
 
  441          job.imageInitialized = 
true;
 
  444        job.completed = job.renderer->render();
 
  448          job.renderer->renderContext()->painter()->end();
 
  451        job.renderingTime += layerTime.elapsed();
 
  462      mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
 
  463      mPainter->setOpacity( 1.0 );
 
  464      mPainter->drawImage( 0, 0, finalImage );
 
  469      for ( LayerRenderJob &job : mLayerJobs )
 
  477          mPainter->drawImage( 0, 0, *job.img );
 
  480      if ( mLabelJob.picture )
 
  487  QgsDebugMsgLevel( QStringLiteral( 
"Rendering completed in (seconds): %1" ).arg( renderTime.elapsed() / 1000.0 ), 2 );
 
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
 
@ UseAdvancedEffects
Enable layer opacity and blending effects.
 
@ ForceVectorOutput
Vector graphics should not be cached and drawn as raster images.
 
@ ForceRasterMasks
Force symbol masking to be applied using a raster method. This is considerably faster when compared t...
 
@ 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.
 
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
 
Default QgsLabelingEngine implementation, which completes the whole labeling operation (including lab...
 
Stores a digital elevation model in a raster image which may get updated as a part of the map layer r...
 
void combine(const QgsElevationMap &otherElevationMap, Qgis::ElevationMapCombineMethod method)
Combines this elevation map with otherElevationMap.
 
bool isValid() const
Returns whether the elevation map is valid.
 
Renders elevation shading on an image with different methods (eye dome lighting, hillshading,...
 
Qgis::ElevationMapCombineMethod combinedElevationMethod() const
Returns the method used when conbining different elevation sources.
 
bool isActive() const
Returns whether this shading renderer is active.
 
void renderShading(const QgsElevationMap &elevation, QImage &image, const QgsRenderContext &context) const
Render shading on image condidering the elevation map elevation and the renderer context context If e...
 
Defines a QGIS exception class.
 
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)
 
QList< QPointer< QgsMapLayer > > participatingLabelLayers(QgsLabelingEngine *engine)
Returns a list of the layers participating in the map labeling.
 
static QImage composeImage(const QgsMapSettings &settings, const std::vector< LayerRenderJob > &jobs, const LabelRenderJob &labelJob, const QgsMapRendererCache *cache=nullptr)
 
void cleanupSecondPassJobs(std::vector< LayerRenderJob > &jobs)
 
void initSecondPassJobs(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob) const
Initialize secondPassJobs according to what have been rendered (mask clipping path e....
 
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
 
void layerRendered(const QString &layerId)
Emitted when a layer has completed rendering.
 
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 renderingLayersFinished()
Emitted when the layers are rendered.
 
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.
 
void layerRenderingStarted(const QString &layerId)
Emitted just before rendering starts for a particular layer.
 
static void composeSecondPass(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob, bool forceVector=false)
Compose second pass images into first pass images.
 
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.
 
Contains configuration for rendering maps.
 
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.
 
const QgsElevationShadingRenderer & elevationShadingRenderer() const
Returns the shading renderer used to render shading on the entire map.
 
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.
 
static void drawPicture(QPainter *painter, const QPointF &point, const QPicture &picture)
Draws a picture onto a painter, correctly applying workarounds to avoid issues with incorrect scaling...
 
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
 
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)
 
#define QgsDebugError(str)