Пример #1
0
QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( const QgsLegendSettings &settings, QgsLayerTreeModelLegendNode::ItemContext *ctx )
{
  // setup temporary render context
  QgsRenderContext context;
  context.setScaleFactor( settings.dpi() / 25.4 );
  context.setRendererScale( settings.mapScale() );
  context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
  context.setForceVectorOutput( true );

  if ( ctx && ctx->painter )
  {
    context.setPainter( ctx->painter );
    ctx->painter->save();
    ctx->painter->setRenderHint( QPainter::Antialiasing );
    ctx->painter->translate( ctx->point );
    ctx->painter->scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
  }

  QgsDataDefinedSizeLegend ddsLegend( *mSettings );
  ddsLegend.setFont( settings.style( QgsLegendStyle::SymbolLabel ).font() );
  ddsLegend.setTextColor( settings.fontColor() );

  QSize contentSize;
  int labelXOffset;
  ddsLegend.drawCollapsedLegend( context, &contentSize, &labelXOffset );

  if ( ctx && ctx->painter )
    ctx->painter->restore();

  ItemMetrics im;
  im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
  im.labelSize = QSizeF( labelXOffset / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
  return im;
}
static QgsRenderContext _createRenderContext( double mupp, double dpi, double scale )
{
  QgsRenderContext context;
  context.setScaleFactor( dpi / 25.4 );
  context.setRendererScale( scale );
  context.setMapToPixel( QgsMapToPixel( mupp ) );
  return context;
}
inline
QgsRenderContext * QgsSymbolV2LegendNode::createTemporaryRenderContext() const
{
    double scale = 0.0;
    double mupp = 0.0;
    int dpi = 0;
    if ( model() )
        model()->legendMapViewData( &mupp, &dpi, &scale );
    bool validData = mupp != 0 && dpi != 0 && scale != 0;

    // setup temporary render context
    QScopedPointer<QgsRenderContext> context( new QgsRenderContext );
    context->setScaleFactor( dpi / 25.4 );
    context->setRendererScale( scale );
    context->setMapToPixel( QgsMapToPixel( mupp ) );
    return validData ? context.take() : 0;
}
Пример #4
0
QgsRenderContext *QgsLayerTreeModelLegendNode::createTemporaryRenderContext() const
{
  double scale = 0.0;
  double mupp = 0.0;
  int dpi = 0;
  if ( model() )
    model()->legendMapViewData( &mupp, &dpi, &scale );

  if ( qgsDoubleNear( mupp, 0.0 ) || dpi == 0 || qgsDoubleNear( scale, 0.0 ) )
    return nullptr;

  // setup temporary render context
  std::unique_ptr<QgsRenderContext> context = qgis::make_unique<QgsRenderContext>( );
  context->setScaleFactor( dpi / 25.4 );
  context->setRendererScale( scale );
  context->setMapToPixel( QgsMapToPixel( mupp ) );
  return context.release();
}
Пример #5
0
void QgsSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const
{
  const QgsSymbol *s = mItem.symbol();
  if ( !s )
  {
    return;
  }

  QgsRenderContext ctx;
  ctx.setScaleFactor( settings.dpi() / 25.4 );
  ctx.setRendererScale( settings.mapScale() );
  ctx.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * ctx.scaleFactor() ) ) );
  ctx.setForceVectorOutput( true );

  // ensure that a minimal expression context is available
  QgsExpressionContext expContext = context.expressionContext();
  expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
  ctx.setExpressionContext( expContext );

  const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), minimumIconSize(), 0, &ctx );
  QImage img( pix.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied ) );

  int opacity = 255;
  if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
    opacity = ( 255 * vectorLayer->opacity() );

  if ( opacity != 255 )
  {
    QPainter painter;
    painter.begin( &img );
    painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
    painter.fillRect( pix.rect(), QColor( 0, 0, 0, opacity ) );
    painter.end();
  }

  QByteArray byteArray;
  QBuffer buffer( &byteArray );
  img.save( &buffer, "PNG" );
  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
  json[ "icon" ] = base64;
}
QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, ItemContext* ctx, double itemHeight ) const
{
    QgsSymbolV2* s = mItem.symbol();
    if ( !s )
    {
        return QSizeF();
    }

    // setup temporary render context
    QgsRenderContext context;
    context.setScaleFactor( settings.dpi() / 25.4 );
    context.setRendererScale( settings.mapScale() );
    context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
    context.setForceVectorOutput( true );
    context.setPainter( ctx ? ctx->painter : 0 );

    //Consider symbol size for point markers
    double height = settings.symbolSize().height();
    double width = settings.symbolSize().width();
    double size = 0;
    //Center small marker symbols
    double widthOffset = 0;
    double heightOffset = 0;

    if ( QgsMarkerSymbolV2* markerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( s ) )
    {
        // allow marker symbol to occupy bigger area if necessary
        size = markerSymbol->size() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, s->outputUnit(), s->mapUnitScale() ) / context.scaleFactor();
        height = size;
        width = size;
        if ( width < settings.symbolSize().width() )
        {
            widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
        }
        if ( height < settings.symbolSize().height() )
        {
            heightOffset = ( settings.symbolSize().height() - height ) / 2.0;
        }
    }

    if ( ctx )
    {
        double currentXPosition = ctx->point.x();
        double currentYCoord = ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2;
        QPainter* p = ctx->painter;

        //setup painter scaling to dots so that raster symbology is drawn to scale
        double dotsPerMM = context.scaleFactor();

        int opacity = 255;
        if ( QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( layerNode()->layer() ) )
            opacity = 255 - ( 255 * vectorLayer->layerTransparency() / 100 );

        p->save();
        p->setRenderHint( QPainter::Antialiasing );
        p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
        p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
        if ( opacity != 255 && settings.useAdvancedEffects() )
        {
            //semi transparent layer, so need to draw symbol to an image (to flatten it first)
            //create image which is same size as legend rect, in case symbol bleeds outside its alloted space
            QSize tempImageSize( width * dotsPerMM, height * dotsPerMM );
            QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
            tempImage.fill( Qt::transparent );
            QPainter imagePainter( &tempImage );
            context.setPainter( &imagePainter );
            s->drawPreviewIcon( &imagePainter, tempImageSize, &context );
            context.setPainter( ctx->painter );
            //reduce opacity of image
            imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
            imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
            imagePainter.end();
            //draw rendered symbol image
            p->drawImage( 0, 0, tempImage );
        }
        else
        {
            s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
        }
        p->restore();
    }

    return QSizeF( qMax( width + 2 * widthOffset, ( double ) settings.symbolSize().width() ),
                   qMax( height + 2 * heightOffset, ( double ) settings.symbolSize().height() ) );
}
Пример #7
0
QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
{
  QgsSymbol *s = mItem.symbol();
  if ( !s )
  {
    return QSizeF();
  }

  // setup temporary render context
  QgsRenderContext context;
  context.setScaleFactor( settings.dpi() / 25.4 );
  context.setRendererScale( settings.mapScale() );
  context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
  context.setForceVectorOutput( true );
  context.setPainter( ctx ? ctx->painter : nullptr );

  if ( ctx && ctx->context )
  {
    context.setExpressionContext( ctx->context->expressionContext() );
  }
  else
  {
    // setup a minimal expression context
    QgsExpressionContext expContext;
    expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
    context.setExpressionContext( expContext );
  }

  //Consider symbol size for point markers
  double height = settings.symbolSize().height();
  double width = settings.symbolSize().width();

  //Center small marker symbols
  double widthOffset = 0;
  double heightOffset = 0;

  if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
  {
    // allow marker symbol to occupy bigger area if necessary
    double size = markerSymbol->size( context ) / context.scaleFactor();
    height = size;
    width = size;
    if ( width < settings.symbolSize().width() )
    {
      widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
    }
    if ( height < settings.symbolSize().height() )
    {
      heightOffset = ( settings.symbolSize().height() - height ) / 2.0;
    }
  }

  if ( ctx && ctx->painter )
  {
    double currentXPosition = ctx->point.x();
    double currentYCoord = ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2;
    QPainter *p = ctx->painter;

    //setup painter scaling to dots so that raster symbology is drawn to scale
    double dotsPerMM = context.scaleFactor();

    int opacity = 255;
    if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
      opacity = ( 255 * vectorLayer->opacity() );

    p->save();
    p->setRenderHint( QPainter::Antialiasing );
    p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
    p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
    if ( opacity != 255 && settings.useAdvancedEffects() )
    {
      //semi transparent layer, so need to draw symbol to an image (to flatten it first)
      //create image which is same size as legend rect, in case symbol bleeds outside its alloted space
      QSize tempImageSize( width * dotsPerMM, height * dotsPerMM );
      QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
      tempImage.fill( Qt::transparent );
      QPainter imagePainter( &tempImage );
      context.setPainter( &imagePainter );
      s->drawPreviewIcon( &imagePainter, tempImageSize, &context );
      context.setPainter( ctx->painter );
      //reduce opacity of image
      imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
      imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
      imagePainter.end();
      //draw rendered symbol image
      p->drawImage( 0, 0, tempImage );
    }
    else
    {
      s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
    }

    if ( !mTextOnSymbolLabel.isEmpty() )
    {
      QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( context ) );
      qreal yBaselineVCenter = ( height * dotsPerMM + fm.ascent() - fm.descent() ) / 2;
      QgsTextRenderer::drawText( QPointF( width * dotsPerMM / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
                                 QStringList() << mTextOnSymbolLabel, context, mTextOnSymbolTextFormat );
    }

    p->restore();
  }

  return QSizeF( std::max( width + 2 * widthOffset, static_cast< double >( settings.symbolSize().width() ) ),
                 std::max( height + 2 * heightOffset, static_cast< double >( settings.symbolSize().height() ) ) );
}
Пример #8
0
QVariant QgsSymbolV2LegendNode::data( int role ) const
{
  if ( role == Qt::DisplayRole )
  {
    return mLabel;
  }
  else if ( role == Qt::EditRole )
  {
    return mUserLabel.isEmpty() ? mItem.label() : mUserLabel;
  }
  else if ( role == Qt::DecorationRole )
  {
    QSize iconSize( 16, 16 ); // TODO: configurable
    const int indentSize = 20;
    if ( mPixmap.isNull() )
    {
      QPixmap pix;
      if ( mItem.symbol() )
      {
        double scale = 0.0;
        double mupp = 0.0;
        int dpi = 0;
        if ( model() )
          model()->legendMapViewData( &mupp, &dpi, &scale );
        bool validData = mupp != 0 && dpi != 0 && scale != 0;

        // setup temporary render context
        QgsRenderContext context;
        context.setScaleFactor( dpi / 25.4 );
        context.setRendererScale( scale );
        context.setMapToPixel( QgsMapToPixel( mupp ) ); // hope it's ok to leave out other params

        pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mItem.symbol(), iconSize, validData ? &context : 0 );
      }
      else
      {
        pix = QPixmap( iconSize );
        pix.fill( Qt::transparent );
      }

      if ( mItem.level() == 0 )
        mPixmap = pix;
      else
      {
        // ident the symbol icon to make it look like a tree structure
        QPixmap pix2( pix.width() + mItem.level() * indentSize, pix.height() );
        pix2.fill( Qt::transparent );
        QPainter p( &pix2 );
        p.drawPixmap( mItem.level() * indentSize, 0, pix );
        p.end();
        mPixmap = pix2;
      }
    }
    return mPixmap;
  }
  else if ( role == Qt::CheckStateRole )
  {
    if ( !mItem.isCheckable() )
      return QVariant();

    QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( mLayerNode->layer() );
    if ( !vlayer || !vlayer->rendererV2() )
      return QVariant();

    return vlayer->rendererV2()->legendSymbolItemChecked( mItem.ruleKey() ) ? Qt::Checked : Qt::Unchecked;
  }
  else if ( role == RuleKeyRole )
  {
    return mItem.ruleKey();
  }
  else if ( role == SymbolV2LegacyRuleKeyRole )
  {
    return QVariant::fromValue<void*>( mItem.legacyRuleKey() );
  }

  return QVariant();
}
Пример #9
0
QgsMapToPixel QgsMapToPixel::fromScale( double scale, QgsUnitTypes::DistanceUnit mapUnits, double dpi )
{
  double metersPerPixel = 25.4 / dpi / 1000.0;
  double mapUnitsPerPixel = metersPerPixel * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::DistanceMeters, mapUnits );
  return QgsMapToPixel( mapUnitsPerPixel * scale );
}