Exemplo n.º 1
0
LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabeling* labelingEngine )
{
  LayerRenderJobs layerJobs;

  // render all layers in the stack, starting at the base
  QListIterator<QString> li( mSettings.layers() );
  li.toBack();

  if ( mCache )
  {
    bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() );
    QgsDebugMsg( QString( "CACHE VALID: %1" ).arg( cacheValid ) );
    Q_UNUSED( cacheValid );
  }

  mGeometryCaches.clear();

  while ( li.hasPrevious() )
  {
    QString layerId = li.previous();

    QgsDebugMsg( "Rendering at layer item " + layerId );

    QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );

    if ( !ml )
    {
      mErrors.append( Error( layerId, "Layer not found in registry." ) );
      continue;
    }

    QgsDebugMsg( QString( "layer %1:  minscale:%2  maxscale:%3  scaledepvis:%4  extent:%5  blendmode:%6" )
                 .arg( ml->name() )
                 .arg( ml->minimumScale() )
                 .arg( ml->maximumScale() )
                 .arg( ml->hasScaleBasedVisibility() )
                 .arg( ml->extent().toString() )
                 .arg( ml->blendMode() )
               );

    if ( ml->hasScaleBasedVisibility() && ( mSettings.scale() < ml->minimumScale() || mSettings.scale() > ml->maximumScale() ) ) //|| mOverview )
    {
      QgsDebugMsg( "Layer not rendered because it is not within the defined visibility scale range" );
      continue;
    }

    QgsRectangle r1 = mSettings.visibleExtent(), r2;
    const QgsCoordinateTransform* ct = 0;

    if ( mSettings.hasCrsTransformEnabled() )
    {
      ct = mSettings.layerTransfrom( ml );
      if ( ct )
      {
        reprojectToLayerExtent( ct, ml->crs().geographicFlag(), r1, r2 );
      }
      QgsDebugMsg( "extent: " + r1.toString() );
      if ( !r1.isFinite() || !r2.isFinite() )
      {
        mErrors.append( Error( layerId, "There was a problem transforming layer's' extent. Layer skipped." ) );
        continue;
      }
    }

    // Force render of layers that are being edited
    // or if there's a labeling engine that needs the layer to register features
    if ( mCache && ml->type() == QgsMapLayer::VectorLayer )
    {
      QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
      if ( vl->isEditable() || ( labelingEngine && labelingEngine->willUseLayer( vl ) ) )
        mCache->clearCacheImage( ml->id() );
    }

    layerJobs.append( LayerRenderJob() );
    LayerRenderJob& job = layerJobs.last();
    job.cached = false;
    job.img = 0;
    job.blendMode = ml->blendMode();
    job.layerId = ml->id();

    job.context = QgsRenderContext::fromMapSettings( mSettings );
    job.context.setPainter( painter );
    job.context.setLabelingEngine( labelingEngine );
    job.context.setCoordinateTransform( ct );
    job.context.setExtent( r1 );

    // if we can use the cache, let's do it and avoid rendering!
    if ( mCache && !mCache->cacheImage( ml->id() ).isNull() )
    {
      job.cached = true;
      job.img = new QImage( mCache->cacheImage( ml->id() ) );
      job.renderer = 0;
      job.context.setPainter( 0 );
      continue;
    }

    // If we are drawing with an alternative blending mode then we need to render to a separate image
    // before compositing this on the map. This effectively flattens the layer and prevents
    // blending occuring between objects on the layer
    if ( mCache || !painter || needTemporaryImage( ml ) )
    {
      // Flattened image for drawing when a blending mode is set
      QImage * mypFlattenedImage = 0;
      mypFlattenedImage = new QImage( mSettings.outputSize().width(),
                                      mSettings.outputSize().height(),
                                      mSettings.outputImageFormat() );
      if ( mypFlattenedImage->isNull() )
      {
        mErrors.append( Error( layerId, "Insufficient memory for image " + QString::number( mSettings.outputSize().width() ) + "x" + QString::number( mSettings.outputSize().height() ) ) );
        delete mypFlattenedImage;
        layerJobs.removeLast();
        continue;
      }
      mypFlattenedImage->fill( 0 );

      job.img = mypFlattenedImage;
      QPainter* mypPainter = new QPainter( job.img );
      mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
      job.context.setPainter( mypPainter );
    }

    job.renderer = ml->createMapRenderer( job.context );

    if ( mRequestedGeomCacheForLayers.contains( ml->id() ) )
    {
      if ( QgsVectorLayerRenderer* vlr = dynamic_cast<QgsVectorLayerRenderer*>( job.renderer ) )
      {
        vlr->setGeometryCachePointer( &mGeometryCaches[ ml->id()] );
      }
    }

  } // while (li.hasPrevious())

  return layerJobs;
}
Exemplo n.º 2
0
LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEngine *labelingEngine2 )
{
  LayerRenderJobs layerJobs;

  // render all layers in the stack, starting at the base
  QListIterator<QgsMapLayer *> li( mSettings.layers() );
  li.toBack();

  if ( mCache )
  {
    bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() );
    Q_UNUSED( cacheValid );
    QgsDebugMsgLevel( QString( "CACHE VALID: %1" ).arg( cacheValid ), 4 );
  }

  bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) );

  while ( li.hasPrevious() )
  {
    QgsMapLayer *ml = li.previous();

    QgsDebugMsgLevel( QString( "layer %1:  minscale:%2  maxscale:%3  scaledepvis:%4  blendmode:%5" )
                      .arg( ml->name() )
                      .arg( ml->minimumScale() )
                      .arg( ml->maximumScale() )
                      .arg( ml->hasScaleBasedVisibility() )
                      .arg( ml->blendMode() )
                      , 3 );

    if ( !ml->isInScaleRange( mSettings.scale() ) ) //|| mOverview )
    {
      QgsDebugMsgLevel( "Layer not rendered because it is not within the defined visibility scale range", 3 );
      continue;
    }

    QgsRectangle r1 = mSettings.visibleExtent(), r2;
    QgsCoordinateTransform ct;

    ct = mSettings.layerTransform( ml );
    if ( ct.isValid() )
    {
      reprojectToLayerExtent( ml, ct, r1, r2 );
    }
    QgsDebugMsgLevel( "extent: " + r1.toString(), 3 );
    if ( !r1.isFinite() || !r2.isFinite() )
    {
      mErrors.append( Error( ml->id(), tr( "There was a problem transforming the layer's extent. Layer skipped." ) ) );
      continue;
    }

    // Force render of layers that are being edited
    // or if there's a labeling engine that needs the layer to register features
    if ( mCache && ml->type() == QgsMapLayer::VectorLayer )
    {
      QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
      bool requiresLabeling = false;
      requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw;
      if ( vl->isEditable() || requiresLabeling )
      {
        mCache->clearCacheImage( ml->id() );
      }
    }

    layerJobs.append( LayerRenderJob() );
    LayerRenderJob &job = layerJobs.last();
    job.cached = false;
    job.img = nullptr;
    job.layer = ml;
    job.renderingTime = -1;

    job.context = QgsRenderContext::fromMapSettings( mSettings );
    job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) );
    job.context.setPainter( painter );
    job.context.setLabelingEngine( labelingEngine2 );
    job.context.setCoordinateTransform( ct );
    job.context.setExtent( r1 );

    if ( mFeatureFilterProvider )
      job.context.setFeatureFilterProvider( mFeatureFilterProvider );

    QgsMapLayerStyleOverride styleOverride( ml );
    if ( mSettings.layerStyleOverrides().contains( ml->id() ) )
      styleOverride.setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) );

    job.blendMode = ml->blendMode();
    job.opacity = 1.0;
    if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ) )
    {
      job.opacity = vl->opacity();
    }

    // if we can use the cache, let's do it and avoid rendering!
    if ( mCache && mCache->hasCacheImage( ml->id() ) )
    {
      job.cached = true;
      job.imageInitialized = true;
      job.img = new QImage( mCache->cacheImage( ml->id() ) );
      job.renderer = nullptr;
      job.context.setPainter( nullptr );
      continue;
    }

    // If we are drawing with an alternative blending mode then we need to render to a separate image
    // before compositing this on the map. This effectively flattens the layer and prevents
    // blending occurring between objects on the layer
    if ( mCache || !painter || needTemporaryImage( ml ) )
    {
      // Flattened image for drawing when a blending mode is set
      QImage *mypFlattenedImage = nullptr;
      mypFlattenedImage = new QImage( mSettings.outputSize().width(),
                                      mSettings.outputSize().height(),
                                      mSettings.outputImageFormat() );
      if ( mypFlattenedImage->isNull() )
      {
        mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) );
        delete mypFlattenedImage;
        layerJobs.removeLast();
        continue;
      }

      job.img = mypFlattenedImage;
      QPainter *mypPainter = new QPainter( job.img );
      mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
      job.context.setPainter( mypPainter );
    }

    QTime layerTime;
    layerTime.start();
    job.renderer = ml->createMapRenderer( job.context );
    job.renderingTime = layerTime.elapsed(); // include job preparation time in layer rendering time
  } // while (li.hasPrevious())

  return layerJobs;
}