Example #1
0
QSizeF QgsHistogramDiagram::diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
  QSizeF size;
  if ( feature.attributes().isEmpty() )
  {
    return size; //zero size if no attributes
  }

  if ( qgsDoubleNear( is.upperValue, is.lowerValue ) )
    return size; // invalid value range => zero size

  double maxValue = 0;

  QgsExpressionContext expressionContext = c.expressionContext();
  expressionContext.setFeature( feature );
  if ( !feature.fields().isEmpty() )
    expressionContext.setFields( feature.fields() );

  Q_FOREACH ( const QString& cat, s.categoryAttributes )
  {
    QgsExpression* expression = getExpression( cat, expressionContext );
    maxValue = qMax( expression->evaluate( &expressionContext ).toDouble(), maxValue );
  }

  // Scale, if extension is smaller than the specified minimum
  if ( maxValue < s.minimumSize )
  {
    maxValue = s.minimumSize;
  }

  switch ( s.diagramOrientation )
  {
    case QgsDiagramSettings::Up:
    case QgsDiagramSettings::Down:
      mScaleFactor = (( is.upperSize.width() - is.lowerSize.height() ) / ( is.upperValue - is.lowerValue ) );
      size.scale( s.barWidth * s.categoryAttributes.size(), maxValue * mScaleFactor, Qt::IgnoreAspectRatio );
      break;

    case QgsDiagramSettings::Right:
    case QgsDiagramSettings::Left:
      mScaleFactor = (( is.upperSize.width() - is.lowerSize.width() ) / ( is.upperValue - is.lowerValue ) );
      size.scale( maxValue * mScaleFactor, s.barWidth * s.categoryAttributes.size(), Qt::IgnoreAspectRatio );
      break;
  }

  return size;
}
QVariant QgsCategorizedSymbolRendererV2::valueForFeature( QgsFeature& feature, QgsRenderContext &context ) const
{
  QgsAttributes attrs = feature.attributes();
  QVariant value;
  if ( mAttrNum == -1 )
  {
    Q_ASSERT( mExpression.data() );

    value = mExpression->evaluate( &context.expressionContext() );
  }
  else
  {
    value = attrs.value( mAttrNum );
  }

  return value;
}
Example #3
0
QgsRenderContext QgsLayoutUtils::createRenderContextForMap( QgsLayoutItemMap *map, QPainter *painter, double dpi )
{
  if ( !map )
  {
    QgsRenderContext context;
    context.setPainter( painter );
    if ( dpi < 0 && painter && painter->device() )
    {
      context.setScaleFactor( painter->device()->logicalDpiX() / 25.4 );
    }
    else if ( dpi > 0 )
    {
      context.setScaleFactor( dpi / 25.4 );
    }
    else
    {
      context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
    }
    return context;
  }
  else
  {
    // default to 88 dpi if no painter specified
    if ( dpi < 0 )
    {
      dpi = ( painter && painter->device() ) ? painter->device()->logicalDpiX() : 88;
    }
#if 0
    double dotsPerMM = dpi / 25.4;
// TODO
    // get map settings from reference map
    QgsRectangle extent = *( map->currentMapExtent() );
    QSizeF mapSizeMM = map->rect().size();
    QgsMapSettings ms = map->mapSettings( extent, mapSizeMM * dotsPerMM, dpi );
#endif
    QgsRenderContext context; // = QgsRenderContext::fromMapSettings( ms );
    if ( painter )
      context.setPainter( painter );

    context.setFlags( map->layout()->context().renderContextFlags() );
    return context;
  }
}
Example #4
0
void QgsHeatmapRenderer::startRender( QgsRenderContext& context, const QgsFields& fields )
{
  Q_UNUSED( fields );
  if ( !context.painter() )
  {
    return;
  }

  // find out classification attribute index from name
  mWeightAttrNum = fields.fieldNameIndex( mWeightExpressionString );
  if ( mWeightAttrNum == -1 )
  {
    mWeightExpression.reset( new QgsExpression( mWeightExpressionString ) );
    mWeightExpression->prepare( fields );
  }

  initializeValues( context );
}
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;
}
Example #6
0
void QgsFormAnnotation::renderAnnotation( QgsRenderContext &context, QSizeF size ) const
{
  if ( !mDesignerWidget )
    return;

  // scale painter back to 96 dpi, so that forms look good even in layout prints
  context.painter()->save();
  const double scaleFactor = context.painter()->device()->logicalDpiX() / 96.0;
  context.painter()->scale( scaleFactor, scaleFactor );
  size /= scaleFactor;

  mDesignerWidget->setFixedSize( size.toSize() );
  context.painter()->setBrush( Qt::NoBrush );
  context.painter()->setPen( Qt::NoPen );
  mDesignerWidget->render( context.painter(), QPoint( 0, 0 ) );

  context.painter()->restore();
}
void QgsHeatmapRenderer::renderImage( QgsRenderContext& context )
{
  if ( !context.painter() || !mGradientRamp )
  {
    return;
  }

  QImage image( context.painter()->device()->width() / mRenderQuality,
                context.painter()->device()->height() / mRenderQuality,
                QImage::Format_ARGB32 );
  image.fill( Qt::transparent );

  double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;

  int idx = 0;
  double pixVal = 0;
  QColor pixColor;
  for ( int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
  {
    QRgb* scanLine = ( QRgb* )image.scanLine( heightIndex );
    for ( int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
    {
      //scale result to fit in the range [0, 1]
      pixVal = mValues.at( idx ) > 0 ? qMin(( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;

      //convert value to color from ramp
      pixColor = mGradientRamp->color( mInvertRamp ? 1 - pixVal : pixVal );

      scanLine[widthIndex] = pixColor.rgba();
      idx++;
    }
  }

  if ( mRenderQuality > 1 )
  {
    QImage resized = image.scaled( context.painter()->device()->width(),
                                   context.painter()->device()->height() );
    context.painter()->drawImage( 0, 0, resized );
  }
  else
  {
    context.painter()->drawImage( 0, 0, image );
  }
}
bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  if ( !context.painter() )
  {
    return false;
  }

  // store this feature as a feature to render with decoration if needed
  if ( selected || drawVertexMarker )
  {
    mFeatureDecorations.append( FeatureDecoration( feature, selected, drawVertexMarker, layer ) );
  }

  // Features are grouped by category of symbols (returned by symbol(s)ForFeature)
  // This way, users can have multiple inverted polygon fills for a layer,
  // for instance, with rule based renderer and different symbols
  // that have transparency.
  //
  // In order to assign a unique category to a set of symbols
  // during each rendering session (between startRender() and stopRender()),
  // we build an unique id as a QByteArray that is the concatenation
  // of each symbol's memory address.
  // The only assumption made here is that symbol(s)ForFeature will
  // always return the same address for the same symbol(s) shared amongst
  // different features.
  // This QByteArray can then be used as a key for a QMap where the list of
  // features for this category is stored
  QByteArray catId;
  if ( capabilities() & MoreSymbolsPerFeature )
  {
    QgsSymbolV2List syms( mSubRenderer->symbolsForFeature( feature, context ) );
    Q_FOREACH ( QgsSymbolV2* sym, syms )
    {
      // append the memory address
      catId.append( reinterpret_cast<const char*>( &sym ), sizeof( sym ) );
    }
void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
  double currentScale = context.rendererScale();
  // filter out rules which are not compatible with this scale

  mCurrentRules.clear();
  for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
  {
    Rule& rule = *it;
    if ( rule.isScaleOK( currentScale ) )
      mCurrentRules.append( &rule );
  }

  QgsFieldMap pendingFields = vlayer->pendingFields();

  for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
  {
    Rule* rule = *it;
    QgsExpression* exp = rule->filter();
    if ( exp )
      exp->prepare( pendingFields );
    rule->symbol()->startRender( context );
  }
}
void QgsNumericScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBarSettings &settings, const ScaleBarContext &scaleContext ) const
{
  if ( !context.painter() )
  {
    return;
  }

  QPainter *painter = context.painter();

  painter->save();
  if ( context.flags() & QgsRenderContext::Antialiasing )
    painter->setRenderHint( QPainter::Antialiasing, true );

  double margin = context.convertToPainterUnits( settings.boxContentSpace(), QgsUnitTypes::RenderMillimeters );
  //map scalebar alignment to Qt::AlignmentFlag type
  QgsTextRenderer::HAlignment hAlign = QgsTextRenderer::AlignLeft;
  switch ( settings.alignment() )
  {
    case QgsScaleBarSettings::AlignLeft:
      hAlign = QgsTextRenderer::AlignLeft;
      break;
    case QgsScaleBarSettings::AlignMiddle:
      hAlign = QgsTextRenderer::AlignCenter;
      break;
    case QgsScaleBarSettings::AlignRight:
      hAlign = QgsTextRenderer::AlignRight;
      break;
  }

  //text destination is item's rect, excluding the margin
  QRectF painterRect( margin, margin, context.convertToPainterUnits( scaleContext.size.width(), QgsUnitTypes::RenderMillimeters ) - 2 * margin,
                      context.convertToPainterUnits( scaleContext.size.height(), QgsUnitTypes::RenderMillimeters ) - 2 * margin );
  QgsTextRenderer::drawText( painterRect, 0, hAlign, QStringList() << scaleText( scaleContext.scale ), context, settings.textFormat() );

  painter->restore();
}
Example #11
0
void QgsComposerShape::drawShapeUsingSymbol( QPainter* p )
{
  p->save();
  p->setRenderHint( QPainter::Antialiasing );

  QgsRenderContext context;
  context.setPainter( p );
  context.setScaleFactor( 1.0 );
  if ( mComposition->plotStyle() ==  QgsComposition::Preview )
  {
    //Limit resolution of symbol fill if composition is not being exported
    //otherwise zooming into composition slows down renders
    context.setRasterScaleFactor( qMin( horizontalViewScaleFactor(), 3.0 ) );
  }
  else
  {
    context.setRasterScaleFactor( mComposition->printResolution() / 25.4 );
  }

  //generate polygon to draw
  QList<QPolygonF> rings; //empty list
  QPolygonF shapePolygon;

  //shapes with curves must be enlarged before conversion to QPolygonF, or
  //the curves are approximated too much and appear jaggy
  QTransform t = QTransform::fromScale( 100, 100 );
  //inverse transform used to scale created polygons back to expected size
  QTransform ti = t.inverted();

  switch ( mShape )
  {
    case Ellipse:
    {
      //create an ellipse
      QPainterPath ellipsePath;
      ellipsePath.addEllipse( QRectF( 0, 0 , rect().width(), rect().height() ) );
      QPolygonF ellipsePoly = ellipsePath.toFillPolygon( t );
      shapePolygon = ti.map( ellipsePoly );
      break;
    }
    case Rectangle:
    {
      //if corner radius set, then draw a rounded rectangle
      if ( mCornerRadius > 0 )
      {
        QPainterPath roundedRectPath;
        roundedRectPath.addRoundedRect( QRectF( 0, 0 , rect().width(), rect().height() ), mCornerRadius, mCornerRadius );
        QPolygonF roundedPoly = roundedRectPath.toFillPolygon( t );
        shapePolygon = ti.map( roundedPoly );
      }
      else
      {
        shapePolygon = QPolygonF( QRectF( 0, 0, rect().width(), rect().height() ) );
      }
      break;
    }
    case Triangle:
    {
      shapePolygon << QPointF( 0, rect().height() );
      shapePolygon << QPointF( rect().width() , rect().height() );
      shapePolygon << QPointF( rect().width() / 2.0, 0 );
      shapePolygon << QPointF( 0, rect().height() );
      break;
    }
  }

  mShapeStyleSymbol->startRender( context );

  //need to render using atlas feature properties?
  if ( mComposition->atlasComposition().enabled() && mComposition->atlasMode() != QgsComposition::AtlasOff )
  {
    //using an atlas, so render using current atlas feature
    //since there may be data defined symbols using atlas feature properties
    mShapeStyleSymbol->renderPolygon( shapePolygon, &rings, mComposition->atlasComposition().currentFeature(), context );
  }
  else
  {
    mShapeStyleSymbol->renderPolygon( shapePolygon, &rings, 0, context );
  }

  mShapeStyleSymbol->stopRender( context );
  p->restore();
}
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() ) );
}
Example #13
0
void QgsDecorationNorthArrow::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{

  //Large IF statement controlled by enable checkbox
  if ( enabled() )
  {
    QSize size( 64, 64 );
    QSvgRenderer svg;

    const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( QStringLiteral( ":/images/north_arrows/default.svg" ), size.width(), mColor, mOutlineColor, 1.0, 1.0 );
    svg.load( svgContent );

    if ( svg.isValid() )
    {
      double centerXDouble = size.width() / 2.0;
      double centerYDouble = size.width() / 2.0;

      //save the current canvas rotation
      context.painter()->save();
      //
      //work out how to shift the image so that it rotates
      //           properly about its center
      //(x cos a + y sin a - x, -x sin a + y cos a - y)
      //

      // could move this call to somewhere else so that it is only
      // called when the projection or map extent changes
      if ( mAutomatic )
      {
        mRotationInt = QgsBearingUtils:: bearingTrueNorth( mapSettings.destinationCrs(), context.extent().center() );
        mRotationInt += mapSettings.rotation();
      }

      double myRadiansDouble = mRotationInt * M_PI / 180.0;
      int xShift = static_cast<int>( (
                                       ( centerXDouble * cos( myRadiansDouble ) ) +
                                       ( centerYDouble * sin( myRadiansDouble ) )
                                     ) - centerXDouble );
      int yShift = static_cast<int>( (
                                       ( -centerXDouble * sin( myRadiansDouble ) ) +
                                       ( centerYDouble * cos( myRadiansDouble ) )
                                     ) - centerYDouble );

      // need width/height of paint device
      int myHeight = context.painter()->device()->height();
      int myWidth = context.painter()->device()->width();

      //QgsDebugMsg("Rendering north arrow at " + mPlacementLabels.at(mPlacementIndex));

      // Set  margin according to selected units
      int myXOffset = 0;
      int myYOffset = 0;
      switch ( mMarginUnit )
      {
        case QgsUnitTypes::RenderMillimeters:
        {
          int myPixelsInchX = context.painter()->device()->logicalDpiX();
          int myPixelsInchY = context.painter()->device()->logicalDpiY();
          myXOffset = myPixelsInchX * INCHES_TO_MM * mMarginHorizontal;
          myYOffset = myPixelsInchY * INCHES_TO_MM * mMarginVertical;
          break;
        }

        case QgsUnitTypes::RenderPixels:
          myXOffset = mMarginHorizontal - 5; // Minus 5 to shift tight into corner
          myYOffset = mMarginVertical - 5;
          break;

        case QgsUnitTypes::RenderPercentage:
          myXOffset = ( ( myWidth - size.width() ) / 100. ) * mMarginHorizontal;
          myYOffset = ( ( myHeight - size.width() ) / 100. ) * mMarginVertical;
          break;

        default:  // Use default of top left
          break;
      }
      //Determine placement of label from form combo box
      switch ( mPlacement )
      {
        case BottomLeft:
          context.painter()->translate( myXOffset, myHeight - myYOffset - size.width() );
          break;
        case TopLeft:
          context.painter()->translate( myXOffset, myYOffset );
          break;
        case TopRight:
          context.painter()->translate( myWidth - myXOffset - size.width(), myYOffset );
          break;
        case BottomRight:
          context.painter()->translate( myWidth - myXOffset - size.width(),
                                        myHeight - myYOffset - size.width() );
          break;
        default:
        {
          //QgsDebugMsg("Unable to determine where to put north arrow so defaulting to top left");
        }
      }

      //rotate the canvas by the north arrow rotation amount
      context.painter()->rotate( mRotationInt );
      //Now we can actually do the drawing, and draw a smooth north arrow even when rotated

      context.painter()->translate( xShift, yShift );
      svg.render( context.painter(), QRectF( 0, 0, size.width(), size.height() ) );

      //unrotate the canvas again
      context.painter()->restore();
    }
    else
    {
      QFont myQFont( QStringLiteral( "time" ), 12, QFont::Bold );
      context.painter()->setFont( myQFont );
      context.painter()->setPen( Qt::black );
      context.painter()->drawText( 10, 20, tr( "North arrow pixmap not found" ) );
    }
  }

}
void QgsAttributeTableFilterModel::generateListOfVisibleFeatures()
{
  if ( !layer() )
    return;

  bool filter = false;
  QgsRectangle rect = mCanvas->mapSettings().mapToLayerCoordinates( layer(), mCanvas->extent() );
  QgsRenderContext renderContext;
  renderContext.expressionContext() << QgsExpressionContextUtils::globalScope()
  << QgsExpressionContextUtils::projectScope()
  << QgsExpressionContextUtils::layerScope( layer() );
  QgsFeatureRendererV2* renderer = layer()->rendererV2();

  mFilteredFeatures.clear();

  if ( !renderer )
  {
    QgsDebugMsg( "Cannot get renderer" );
    return;
  }

  const QgsMapSettings& ms = mCanvas->mapSettings();
  if ( layer()->hasScaleBasedVisibility() &&
       ( layer()->minimumScale() > ms.scale() ||
         layer()->maximumScale() <= ms.scale() ) )
  {
    QgsDebugMsg( "Out of scale limits" );
  }
  else
  {
    if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
    {
      // setup scale
      // mapRenderer()->renderContext()->scale is not automaticaly updated when
      // render extent changes (because it's scale is used to identify if changed
      // since last render) -> use local context
      renderContext.setExtent( ms.visibleExtent() );
      renderContext.setMapToPixel( ms.mapToPixel() );
      renderContext.setRendererScale( ms.scale() );
    }

    filter = renderer && renderer->capabilities() & QgsFeatureRendererV2::Filter;
  }

  renderer->startRender( renderContext, layer()->fields() );

  QgsFeatureRequest r( masterModel()->request() );
  if ( !r.filterRect().isNull() )
  {
    r.setFilterRect( r.filterRect().intersect( &rect ) );
  }
  else
  {
    r.setFilterRect( rect );
  }
  QgsFeatureIterator features = masterModel()->layerCache()->getFeatures( r );

  QgsFeature f;

  while ( features.nextFeature( f ) )
  {
    renderContext.expressionContext().setFeature( f );
    if ( !filter || renderer->willRenderFeature( f, renderContext ) )
    {
      mFilteredFeatures << f.id();
    }
#if 0
    if ( t.elapsed() > 5000 )
    {
      bool cancel = false;
      emit progress( i, cancel );
      if ( cancel )
        break;

      t.restart();
    }
#endif
  }

  features.close();

  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
  {
    renderer->stopRender( renderContext );
  }
}
void QgsPointDisplacementRenderer::drawGroup( const DisplacementGroup& group, QgsRenderContext& context )
{
  const QgsFeature& feature = group.begin().value().first;
  bool selected = mSelectedFeatures.contains( feature.id() ); // maybe we should highlight individual features instead of the whole group?



  //get list of labels and symbols
  QStringList labelAttributeList;
  QList<QgsMarkerSymbolV2*> symbolList;

  QgsMultiPointV2* groupMultiPoint = new QgsMultiPointV2();
  for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt )
  {
    labelAttributeList << ( mDrawLabels ? getLabel( attIt.value().first ) : QString() );
    symbolList << dynamic_cast<QgsMarkerSymbolV2*>( attIt.value().second );
    groupMultiPoint->addGeometry( attIt.value().first.constGeometry()->geometry()->clone() );
  }

  //calculate centroid of all points, this will be center of group
  QgsGeometry groupGeom( groupMultiPoint );
  QgsGeometry* centroid = groupGeom.centroid();
  QPointF pt;
  _getPoint( pt, context, centroid->asWkb() );
  delete centroid;

  //calculate max diagonal size from all symbols in group
  double diagonal = 0;
  Q_FOREACH ( QgsMarkerSymbolV2* symbol, symbolList )
  {
    if ( symbol )
    {
      diagonal = qMax( diagonal, QgsSymbolLayerV2Utils::convertToPainterUnits( context,
                       M_SQRT2 * symbol->size(),
                       symbol->outputUnit(), symbol->mapUnitScale() ) );
    }
  }

  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  double circleRadius = -1.0;
  calculateSymbolAndLabelPositions( symbolContext, pt, symbolList.size(), diagonal, symbolPositions, labelPositions, circleRadius );

  //draw Circle
  if ( circleRadius > 0 )
    drawCircle( circleRadius, symbolContext, pt, symbolList.size() );

  //draw mid point
  if ( labelAttributeList.size() > 1 )
  {
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( pt, &feature, context, -1, selected );
    }
    else
    {
      context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( feature, context, symbolList, symbolPositions, selected );
  //and also the labels
  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
}
void QgsPointDisplacementRenderer::drawGroup( const DisplacementGroup& group, QgsRenderContext& context )
{
  const QgsFeature& feature = group.begin().value().first;
  bool selected = mSelectedFeatures.contains( feature.id() ); // maybe we should highlight individual features instead of the whole group?

  QPointF pt;
  _getPoint( pt, context, feature.constGeometry()->asWkb() );

  //get list of labels and symbols
  QStringList labelAttributeList;
  QList<QgsMarkerSymbolV2*> symbolList;

  for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt )
  {
    labelAttributeList << ( mDrawLabels ? getLabel( attIt.value().first ) : QString() );
    symbolList << dynamic_cast<QgsMarkerSymbolV2*>( attIt.value().second );
  }

  //draw symbol
  double diagonal = 0;
  double currentWidthFactor; //scale symbol size to map unit and output resolution

  QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin();
  for ( ; it != symbolList.constEnd(); ++it )
  {
    if ( *it )
    {
      currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit(), ( *it )->mapUnitScale() );
      double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor;
      if ( currentDiagonal > diagonal )
      {
        diagonal = currentDiagonal;
      }
    }
  }


  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );
  double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition );
  double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits;

  //draw Circle
  drawCircle( radius, symbolContext, pt, symbolList.size() );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions );

  //draw mid point
  if ( labelAttributeList.size() > 1 )
  {
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( pt, &feature, context, -1, selected );
    }
    else
    {
      context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( feature, context, symbolList, symbolPositions, selected );
  //and also the labels
  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
}
bool QgsPointDistanceRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  Q_UNUSED( drawVertexMarker );
  Q_UNUSED( context );
  Q_UNUSED( layer );

  //check if there is already a point at that position
  if ( !feature.hasGeometry() )
    return false;

  QgsMarkerSymbol* symbol = firstSymbolForFeature( feature, context );

  //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it
  if ( !symbol )
    return false;

  //point position in screen coords
  QgsGeometry geom = feature.geometry();
  QgsWkbTypes::Type geomType = geom.wkbType();
  if ( QgsWkbTypes::flatType( geomType ) != QgsWkbTypes::Point )
  {
    //can only render point type
    return false;
  }

  QString label;
  if ( mDrawLabels )
  {
    label = getLabel( feature );
  }

  QgsCoordinateTransform xform = context.coordinateTransform();
  QgsFeature transformedFeature = feature;
  if ( xform.isValid() )
  {
    geom.transform( xform );
    transformedFeature.setGeometry( geom );
  }

  double searchDistance = mTolerance * QgsSymbolLayerUtils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale );
  QgsPoint point = transformedFeature.geometry().asPoint();
  QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( point, searchDistance ) );
  if ( intersectList.empty() )
  {
    mSpatialIndex->insertFeature( transformedFeature );
    // create new group
    ClusteredGroup newGroup;
    newGroup << GroupedFeature( transformedFeature, symbol, selected, label );
    mClusteredGroups.push_back( newGroup );
    // add to group index
    mGroupIndex.insert( transformedFeature.id(), mClusteredGroups.count() - 1 );
    mGroupLocations.insert( transformedFeature.id(), point );
  }
  else
  {
    // find group with closest location to this point (may be more than one within search tolerance)
    QgsFeatureId minDistFeatureId = intersectList.at( 0 );
    double minDist = mGroupLocations.value( minDistFeatureId ).distance( point );
    for ( int i = 1; i < intersectList.count(); ++i )
    {
      QgsFeatureId candidateId = intersectList.at( i );
      double newDist = mGroupLocations.value( candidateId ).distance( point );
      if ( newDist < minDist )
      {
        minDist = newDist;
        minDistFeatureId = candidateId;
      }
    }

    int groupIdx = mGroupIndex[ minDistFeatureId ];
    ClusteredGroup& group = mClusteredGroups[groupIdx];

    // calculate new centroid of group
    QgsPoint oldCenter = mGroupLocations.value( minDistFeatureId );
    mGroupLocations[ minDistFeatureId ] = QgsPoint(( oldCenter.x() * group.size() + point.x() ) / ( group.size() + 1.0 ),
                                          ( oldCenter.y() * group.size() + point.y() ) / ( group.size() + 1.0 ) );

    // add to a group
    group << GroupedFeature( transformedFeature, symbol, selected, label );
    // add to group index
    mGroupIndex.insert( transformedFeature.id(), groupIdx );
  }

  return true;
}
Example #18
0
void QgsComposerShape::drawShapeUsingSymbol( QPainter* p )
{
  p->save();
  p->setRenderHint( QPainter::Antialiasing );

  //setup painter scaling to dots so that raster symbology is drawn to scale
  double dotsPerMM = p->device()->logicalDpiX() / 25.4;

  //setup render context
  QgsMapSettings ms = mComposition->mapSettings();
  //context units should be in dots
  ms.setOutputDpi( p->device()->logicalDpiX() );
  QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
  context.setPainter( p );
  context.setForceVectorOutput( true );
  QgsExpressionContext* expressionContext = createExpressionContext();
  context.setExpressionContext( *expressionContext );
  delete expressionContext;

  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots

  //generate polygon to draw
  QList<QPolygonF> rings; //empty list
  QPolygonF shapePolygon;

  //shapes with curves must be enlarged before conversion to QPolygonF, or
  //the curves are approximated too much and appear jaggy
  QTransform t = QTransform::fromScale( 100, 100 );
  //inverse transform used to scale created polygons back to expected size
  QTransform ti = t.inverted();

  switch ( mShape )
  {
    case Ellipse:
    {
      //create an ellipse
      QPainterPath ellipsePath;
      ellipsePath.addEllipse( QRectF( 0, 0, rect().width() * dotsPerMM, rect().height() * dotsPerMM ) );
      QPolygonF ellipsePoly = ellipsePath.toFillPolygon( t );
      shapePolygon = ti.map( ellipsePoly );
      break;
    }
    case Rectangle:
    {
      //if corner radius set, then draw a rounded rectangle
      if ( mCornerRadius > 0 )
      {
        QPainterPath roundedRectPath;
        roundedRectPath.addRoundedRect( QRectF( 0, 0, rect().width() * dotsPerMM, rect().height() * dotsPerMM ), mCornerRadius * dotsPerMM, mCornerRadius * dotsPerMM );
        QPolygonF roundedPoly = roundedRectPath.toFillPolygon( t );
        shapePolygon = ti.map( roundedPoly );
      }
      else
      {
        shapePolygon = QPolygonF( QRectF( 0, 0, rect().width() * dotsPerMM, rect().height() * dotsPerMM ) );
      }
      break;
    }
    case Triangle:
    {
      shapePolygon << QPointF( 0, rect().height() * dotsPerMM );
      shapePolygon << QPointF( rect().width() * dotsPerMM, rect().height() * dotsPerMM );
      shapePolygon << QPointF( rect().width() / 2.0 * dotsPerMM, 0 );
      shapePolygon << QPointF( 0, rect().height() * dotsPerMM );
      break;
    }
  }

  mShapeStyleSymbol->startRender( context );
  mShapeStyleSymbol->renderPolygon( shapePolygon, &rings, nullptr, context );
  mShapeStyleSymbol->stopRender( context );

  p->restore();
}
Example #19
0
void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
  QPainter* p = c.painter();
  if ( !p )
  {
    return;
  }

  //get sum of values
  QList<double> values;
  double currentVal = 0;
  double valSum = 0;
  int valCount = 0;

  QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
  for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
  {
    currentVal = att[*catIt].toDouble();
    values.push_back( currentVal );
    valSum += currentVal;
    if ( currentVal ) valCount++;
  }

  //draw the slices
  double totalAngle = 0;
  double currentAngle;

  //convert from mm / map units to painter units
  QSizeF spu = sizePainterUnits( s.size, s, c );
  double w = spu.width();
  double h = spu.height();

  double baseX = position.x();
  double baseY = position.y() - h;

  mPen.setColor( s.penColor );
  setPenWidth( mPen, s, c );
  p->setPen( mPen );

  // there are some values > 0 available
  if ( valSum > 0 )
  {
    QList<double>::const_iterator valIt = values.constBegin();
    QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
    for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
    {
      currentAngle =  *valIt / valSum * 360 * 16;
      mCategoryBrush.setColor( *colIt );
      p->setBrush( mCategoryBrush );
      // if only 1 value is > 0, draw a circle
      if ( valCount == 1 )
      {
        p->drawEllipse( baseX, baseY, w, h );
      }
      else
      {
        p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
      }
      totalAngle += currentAngle;
    }
  }
  else // valSum > 0
  {
    // draw empty circle if no values are defined at all
    mCategoryBrush.setColor( Qt::transparent );
    p->setBrush( mCategoryBrush );
    p->drawEllipse( baseX, baseY, w, h );
  }
}
Example #20
0
void QgsGCPCanvasItem::paint( QPainter* p )
{
  QgsRenderContext context;
  if ( !setRenderContextVariables( p, context ) )
  {
    return;
  }

  p->setRenderHint( QPainter::Antialiasing );

  bool enabled = true;
  QgsPoint worldCoords;
  int id = -1;

  if ( mDataPoint )
  {
    enabled = mDataPoint->isEnabled();
    worldCoords = mDataPoint->mapCoords();
    id = mDataPoint->id();
  }

  p->setOpacity( enabled ? 1.0 : 0.3 );

  // draw the point
  p->setPen( Qt::black );
  p->setBrush( mPointBrush );
  p->drawEllipse( -2, -2, 5, 5 );

  QSettings s;
  bool showIDs = s.value( "/Plugin-GeoReferencer/Config/ShowId" ).toBool();
  bool showCoords = s.value( "/Plugin-GeoReferencer/Config/ShowCoords" ).toBool();

  QString msg;
  if ( showIDs && showCoords )
  {
    msg = QString( "%1\nX %2\nY %3" ).arg( QString::number( id ) ).arg( QString::number( worldCoords.x(), 'f' ) ).arg( QString::number( worldCoords.y(), 'f' ) );
  }
  else if ( showIDs )
  {
    msg = msg = QString::number( id );
  }
  else if ( showCoords )
  {
    msg = QString( "X %1\nY %2" ).arg( QString::number( worldCoords.x(), 'f' ) ).arg( QString::number( worldCoords.y(), 'f' ) );
  }

  if ( !msg.isEmpty() )
  {
    p->setBrush( mLabelBrush );
    QFont textFont( "helvetica" );
    textFont.setPixelSize( fontSizePainterUnits( 12, context ) );
    p->setFont( textFont );
    QRectF textBounds = p->boundingRect( 3 * context.scaleFactor(), 3 * context.scaleFactor(), 5 * context.scaleFactor(), 5 * context.scaleFactor(), Qt::AlignLeft, msg );
    mTextBoxRect = QRectF( textBounds.x() - context.scaleFactor() * 1, textBounds.y() - context.scaleFactor() * 1, \
                           textBounds.width() + 2 * context.scaleFactor(), textBounds.height() + 2 * context.scaleFactor() );
    p->drawRect( mTextBoxRect );
    p->drawText( textBounds, Qt::AlignLeft, msg );
  }

  if ( data( 0 ) != "composer" ) //draw residuals only on screen
  {
    drawResidualArrow( p, context );
  }
}
Example #21
0
void QgsHistogramDiagram::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, QPointF position )
{
  QPainter* p = c.painter();
  if ( !p )
  {
    return;
  }

  QList<double> values;
  double maxValue = 0;

  QgsExpressionContext expressionContext = c.expressionContext();
  expressionContext.setFeature( feature );
  if ( !feature.fields().isEmpty() )
    expressionContext.setFields( feature.fields() );

  Q_FOREACH ( const QString& cat, s.categoryAttributes )
  {
    QgsExpression* expression = getExpression( cat, expressionContext );
    double currentVal = expression->evaluate( &expressionContext ).toDouble();
    values.push_back( currentVal );
    maxValue = qMax( currentVal, maxValue );
  }

  double scaledMaxVal = sizePainterUnits( maxValue * mScaleFactor, s, c );

  double currentOffset = 0;
  double scaledWidth = sizePainterUnits( s.barWidth, s, c );

  double baseX = position.x();
  double baseY = position.y();

  mPen.setColor( s.penColor );
  setPenWidth( mPen, s, c );
  p->setPen( mPen );

  QList<double>::const_iterator valIt = values.constBegin();
  QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
  for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
  {
    double length = sizePainterUnits( *valIt * mScaleFactor, s, c );

    mCategoryBrush.setColor( *colIt );
    p->setBrush( mCategoryBrush );

    switch ( s.diagramOrientation )
    {
      case QgsDiagramSettings::Up:
        p->drawRect( baseX + currentOffset, baseY, scaledWidth, length * -1 );
        break;

      case QgsDiagramSettings::Down:
        p->drawRect( baseX + currentOffset, baseY - scaledMaxVal, scaledWidth, length );
        break;

      case QgsDiagramSettings::Right:
        p->drawRect( baseX, baseY - currentOffset, length, scaledWidth * -1 );
        break;

      case QgsDiagramSettings::Left:
        p->drawRect( baseX + scaledMaxVal, baseY - currentOffset, 0 - length, scaledWidth * -1 );
        break;
    }

    currentOffset += scaledWidth;
  }
}
Example #22
0
void QgsMapToolSelectUtils::setSelectFeatures( QgsMapCanvas* canvas,
	QgsGeometry* selectGeometry,
	bool doContains,
	bool doDifference,
	bool singleSelect )
{
	if ( selectGeometry->type() != QGis::Polygon )
	{
		return;
	}
	QgsVectorLayer* vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( canvas );
	if ( vlayer == nullptr )
	{
		return;
	}

	// toLayerCoordinates will throw an exception for any 'invalid' points in
	// the rubber band.
	// For example, if you project a world map onto a globe using EPSG 2163
	// and then click somewhere off the globe, an exception will be thrown.
	//QgsGeometry selectGeomTrans( *selectGeometry );

	//if ( canvas->mapSettings().hasCrsTransformEnabled() )
	//{
	//	try
	//	{
	//		QgsCoordinateTransform ct( canvas->mapSettings().destinationCrs(), vlayer->crs() );
	//		selectGeomTrans.transform( ct );
	//	}
	//	catch ( QgsCsException &cse )
	//	{
	//		Q_UNUSED( cse );
	//		// catch exception for 'invalid' point and leave existing selection unchanged
	//		QgsLogger::warning( "Caught CRS exception " + QString( __FILE__ ) + ": " + QString::number( __LINE__ ) );
	//		LOG_INFO( "CRS Exception\nSelection extends beyond layer's coordinate system" );
	//		return;
	//	}
	//}
	QgsGeometry selectGeomTrans;
	try{
		selectGeomTrans = toLayerCoordinates( canvas, selectGeometry, vlayer );
	}
	catch ( QgsCsException & )
	{
		return;
	}

	QApplication::setOverrideCursor( Qt::WaitCursor );

	QgsDebugMsg( "Selection layer: " + vlayer->name() );
	QgsDebugMsg( "Selection polygon: " + selectGeomTrans.exportToWkt() );
	QgsDebugMsg( "doContains: " + QString( doContains ? "T" : "F" ) );
	QgsDebugMsg( "doDifference: " + QString( doDifference ? "T" : "F" ) );

	QgsRenderContext context = QgsRenderContext::fromMapSettings( canvas->mapSettings() );
	QgsFeatureRendererV2* r = vlayer->rendererV2();
	if ( r )
		r->startRender( context, vlayer->pendingFields() );

	QgsFeatureRequest request;
	request.setFilterRect( selectGeomTrans.boundingBox() );
	request.setFlags( QgsFeatureRequest::ExactIntersect );
	if ( r )
		request.setSubsetOfAttributes( r->usedAttributes(), vlayer->pendingFields() );
	else
		request.setSubsetOfAttributes( QgsAttributeList() );

	QgsFeatureIterator fit = vlayer->getFeatures( request );

	QgsFeatureIds newSelectedFeatures;
	QgsFeature f;
	QgsFeatureId closestFeatureId = 0;
	bool foundSingleFeature = false;
	double closestFeatureDist = std::numeric_limits<double>::max();
	while ( fit.nextFeature( f ) )
	{
#if (VERSION_INT >= 21601)
		context.expressionContext().setFeature( f );		//taken from QGIS 2.16.1
		// make sure to only use features that are visible
		if ( r && !r->willRenderFeature( f, context ) )
#else
		if ( r && !r->willRenderFeature( f ) )
#endif
			continue;

		QgsGeometry* g = f.geometry();
		if ( doContains )
		{
			if ( !selectGeomTrans.contains( g ) )
				continue;
		}
		else
		{
			if ( !selectGeomTrans.intersects( g ) )
				continue;
		}
		if ( singleSelect )
		{
			foundSingleFeature = true;
			double distance = g->distance( selectGeomTrans );
			if ( distance <= closestFeatureDist )
			{
				closestFeatureDist = distance;
				closestFeatureId = f.id();
			}
		}
		else
		{
			newSelectedFeatures.insert( f.id() );
		}
	}
	if ( singleSelect && foundSingleFeature )
	{
		newSelectedFeatures.insert( closestFeatureId );
	}

	if ( r )
		r->stopRender( context );

	QgsDebugMsg( "Number of new selected features: " + QString::number( newSelectedFeatures.size() ) );

	if ( doDifference )
	{
		QgsFeatureIds layerSelectedFeatures = vlayer->selectedFeaturesIds();

		QgsFeatureIds selectedFeatures;
		QgsFeatureIds deselectedFeatures;

		QgsFeatureIds::const_iterator i = newSelectedFeatures.constEnd();
		while ( i != newSelectedFeatures.constBegin() )
		{
			--i;
			if ( layerSelectedFeatures.contains( *i ) )
			{
				deselectedFeatures.insert( *i );
			}
			else
			{
				selectedFeatures.insert( *i );
			}
		}

		vlayer->modifySelection( selectedFeatures, deselectedFeatures );
	}
	else
	{
		SelectFeatures( vlayer, newSelectedFeatures );		//		vlayer->setSelectedFeatures( newSelectedFeatures );
	}

	QApplication::restoreOverrideCursor();
}
Example #23
0
QgsConstWkbPtr QgsSymbolV2::_getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, QgsConstWkbPtr wkbPtr, bool clipToExtent )
{
  QgsWKBTypes::Type wkbType = wkbPtr.readHeader();
  QgsDebugMsg( QString( "wkbType=%1" ).arg( wkbType ) );
  unsigned int numRings;
  wkbPtr >> numRings;

  if ( numRings == 0 )  // sanity check for zero rings in polygon
    return wkbPtr;

  holes.clear();

  const QgsCoordinateTransform* ct = context.coordinateTransform();
  const QgsMapToPixel& mtp = context.mapToPixel();
  const QgsRectangle& e = context.extent();
  double cw = e.width() / 10;
  double ch = e.height() / 10;
  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );

  int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double );
  Q_ASSERT( skipZM >= 0 );

  for ( unsigned int idx = 0; idx < numRings; idx++ )
  {
    unsigned int nPoints;
    wkbPtr >> nPoints;

    QPolygonF poly( nPoints );

    QPointF *ptr = poly.data();
    for ( unsigned int jdx = 0; jdx < nPoints; ++jdx, ++ptr )
    {
      wkbPtr >> ptr->rx() >> ptr->ry();
      wkbPtr += skipZM;
    }

    if ( nPoints < 1 )
      continue;

    //clip close to view extent, if needed
    QRectF ptsRect = poly.boundingRect();
    if ( clipToExtent && !context.extent().contains( ptsRect ) )
    {
      QgsClipper::trimPolygon( poly, clipRect );
    }

    //transform the QPolygonF to screen coordinates
    if ( ct )
    {
      ct->transformPolygon( poly );
    }

    ptr = poly.data();
    for ( int i = 0; i < poly.size(); ++i, ++ptr )
    {
      mtp.transformInPlace( ptr->rx(), ptr->ry() );
    }

    if ( idx == 0 )
      pts = poly;
    else
      holes.append( poly );
  }

  return wkbPtr;
}
void QgsDecorationNorthArrow::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{
  if ( !enabled() )
    return;

  double maxLength = mSize * mapSettings.outputDpi() / 25.4;
  QSvgRenderer svg;

  const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( svgPath(), maxLength, mColor, mOutlineColor, 1.0, 1.0 );
  svg.load( svgContent );

  if ( svg.isValid() )
  {
    QSize size( maxLength, maxLength );
    QRectF viewBox = svg.viewBoxF();
    if ( viewBox.height() > viewBox.width() )
    {
      size.setWidth( maxLength * viewBox.width() / viewBox.height() );
    }
    else
    {
      size.setHeight( maxLength * viewBox.height() / viewBox.width() );
    }

    double centerXDouble = size.width() / 2.0;
    double centerYDouble = size.height() / 2.0;

    //save the current canvas rotation
    context.painter()->save();
    //
    //work out how to shift the image so that it rotates
    //           properly about its center
    //(x cos a + y sin a - x, -x sin a + y cos a - y)
    //
    // could move this call to somewhere else so that it is only
    // called when the projection or map extent changes
    if ( mAutomatic )
    {
      try
      {
        mRotationInt = QgsBearingUtils:: bearingTrueNorth( mapSettings.destinationCrs(), mapSettings.transformContext(), context.extent().center() );
      }
      catch ( QgsException & )
      {
        mRotationInt = 0.0;
      }
      mRotationInt += mapSettings.rotation();
    }

    double radiansDouble = mRotationInt * M_PI / 180.0;
    int xShift = static_cast<int>( (
                                     ( centerXDouble * std::cos( radiansDouble ) ) +
                                     ( centerYDouble * std::sin( radiansDouble ) )
                                   ) - centerXDouble );
    int yShift = static_cast<int>( (
                                     ( -centerXDouble * std::sin( radiansDouble ) ) +
                                     ( centerYDouble * std::cos( radiansDouble ) )
                                   ) - centerYDouble );
    // need width/height of paint device
    int deviceHeight = context.painter()->device()->height();
    int deviceWidth = context.painter()->device()->width();

    // Set  margin according to selected units
    int xOffset = 0;
    int yOffset = 0;
    switch ( mMarginUnit )
    {
      case QgsUnitTypes::RenderMillimeters:
      {
        int pixelsInchX = context.painter()->device()->logicalDpiX();
        int pixelsInchY = context.painter()->device()->logicalDpiY();
        xOffset = pixelsInchX * INCHES_TO_MM * mMarginHorizontal;
        yOffset = pixelsInchY * INCHES_TO_MM * mMarginVertical;
        break;
      }

      case QgsUnitTypes::RenderPixels:
        xOffset = mMarginHorizontal - 5; // Minus 5 to shift tight into corner
        yOffset = mMarginVertical - 5;
        break;

      case QgsUnitTypes::RenderPercentage:
        xOffset = ( ( deviceWidth - size.width() ) / 100. ) * mMarginHorizontal;
        yOffset = ( ( deviceHeight - size.width() ) / 100. ) * mMarginVertical;
        break;
      case QgsUnitTypes::RenderMapUnits:
      case QgsUnitTypes::RenderPoints:
      case QgsUnitTypes::RenderInches:
      case QgsUnitTypes::RenderUnknownUnit:
      case QgsUnitTypes::RenderMetersInMapUnits:
        break;
    }
    //Determine placement of label from form combo box
    switch ( mPlacement )
    {
      case BottomLeft:
        context.painter()->translate( xOffset, deviceHeight - yOffset - maxLength + ( maxLength - size.height() ) / 2 );
        break;
      case TopLeft:
        context.painter()->translate( xOffset, yOffset );
        break;
      case TopRight:
        context.painter()->translate( deviceWidth - xOffset - maxLength + ( maxLength - size.width() ) / 2, yOffset );
        break;
      case BottomRight:
        context.painter()->translate( deviceWidth - xOffset - maxLength + ( maxLength - size.width() ) / 2,
                                      deviceHeight - yOffset - maxLength + ( maxLength - size.height() ) / 2 );
        break;
    }

    //rotate the canvas by the north arrow rotation amount
    context.painter()->rotate( mRotationInt );
    //Now we can actually do the drawing, and draw a smooth north arrow even when rotated
    context.painter()->translate( xShift, yShift );
    svg.render( context.painter(), QRectF( 0, 0, size.width(), size.height() ) );

    //unrotate the canvas again
    context.painter()->restore();
  }
}
Example #25
0
void QgsDecorationGrid::render( QPainter * p )
{
  if ( ! mEnabled )
    return;

  // p->setPen( mGridPen );

  QList< QPair< qreal, QLineF > > verticalLines;
  yGridLines( verticalLines );
  QList< QPair< qreal, QLineF > > horizontalLines;
  xGridLines( horizontalLines );
  //QgsDebugMsg( QString("grid has %1 vertical and %2 horizontal lines").arg( verticalLines.size() ).arg( horizontalLines.size() ) );

  QList< QPair< qreal, QLineF > >::const_iterator vIt = verticalLines.constBegin();
  QList< QPair< qreal, QLineF > >::const_iterator hIt = horizontalLines.constBegin();

  //simpler approach: draw vertical lines first, then horizontal ones
  if ( mGridStyle == QgsDecorationGrid::Line )
  {
    if ( ! mLineSymbol )
      return;

    QgsRenderContext context = QgsRenderContext::fromMapSettings( QgisApp::instance()->mapCanvas()->mapSettings() );
    context.setPainter( p );
    mLineSymbol->startRender( context, nullptr );

    for ( ; vIt != verticalLines.constEnd(); ++vIt )
    {
      // p->drawLine( vIt->second );
      // need to convert QLineF to QPolygonF ...
      QVector<QPointF> poly;
      poly << vIt->second.p1() << vIt->second.p2();
      mLineSymbol->renderPolyline( QPolygonF( poly ), nullptr, context );
    }

    for ( ; hIt != horizontalLines.constEnd(); ++hIt )
    {
      // p->drawLine( hIt->second );
      // need to convert QLineF to QPolygonF ...
      QVector<QPointF> poly;
      poly << hIt->second.p1() << hIt->second.p2();
      mLineSymbol->renderPolyline( QPolygonF( poly ), nullptr, context );
    }

    mLineSymbol->stopRender( context );
  }
#if 0
  else if ( mGridStyle == QgsDecorationGrid::Cross )
  {
    QPointF intersectionPoint, crossEnd1, crossEnd2;
    for ( ; vIt != verticalLines.constEnd(); ++vIt )
    {
      //start mark
      crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
      p->drawLine( vIt->second.p1(), crossEnd1 );

      //test for intersection with every horizontal line
      hIt = horizontalLines.constBegin();
      for ( ; hIt != horizontalLines.constEnd(); ++hIt )
      {
        if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
        {
          crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength );
          crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength );
          p->drawLine( crossEnd1, crossEnd2 );
        }
      }
      //end mark
      QPointF crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
      p->drawLine( vIt->second.p2(), crossEnd2 );
    }

    hIt = horizontalLines.constBegin();
    for ( ; hIt != horizontalLines.constEnd(); ++hIt )
    {
      //start mark
      crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
      p->drawLine( hIt->second.p1(), crossEnd1 );

      vIt = verticalLines.constBegin();
      for ( ; vIt != verticalLines.constEnd(); ++vIt )
      {
        if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
        {
          crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength );
          crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength );
          p->drawLine( crossEnd1, crossEnd2 );
        }
      }
      //end mark
      crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
      p->drawLine( hIt->second.p2(), crossEnd1 );
    }
  }
#endif
  else //marker
  {
    if ( ! mMarkerSymbol )
      return;

    QgsRenderContext context = QgsRenderContext::fromMapSettings( QgisApp::instance()->mapCanvas()->mapSettings() );
    context.setPainter( p );
    mMarkerSymbol->startRender( context, nullptr );

    QPointF intersectionPoint;
    for ( ; vIt != verticalLines.constEnd(); ++vIt )
    {
      //test for intersection with every horizontal line
      hIt = horizontalLines.constBegin();
      for ( ; hIt != horizontalLines.constEnd(); ++hIt )
      {
        if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
        {
          mMarkerSymbol->renderPoint( intersectionPoint, nullptr, context );
        }
      }
    }
    mMarkerSymbol->stopRender( context );
  }

  // p->setClipRect( thisPaintRect, Qt::NoClip );

  if ( mShowGridAnnotation )
  {
    drawCoordinateAnnotations( p, horizontalLines, verticalLines );
  }
}
Example #26
0
double QgsMapTool::searchRadiusMU( const QgsRenderContext& context )
{
  return searchRadiusMM() * context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel();
}
Example #27
0
double QgsGCPCanvasItem::fontSizePainterUnits( double points, const QgsRenderContext& c )
{
  return points * 0.3527 * c.scaleFactor();
}
bool QgsHeatmapRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  Q_UNUSED( layer );
  Q_UNUSED( selected );
  Q_UNUSED( drawVertexMarker );

  if ( !context.painter() )
  {
    return false;
  }

  if ( !feature.constGeometry() || feature.constGeometry()->type() != QGis::Point )
  {
    //can only render point type
    return false;
  }

  double weight = 1.0;
  if ( !mWeightExpressionString.isEmpty() )
  {
    QVariant value;
    if ( mWeightAttrNum == -1 )
    {
      Q_ASSERT( mWeightExpression.data() );
      value = mWeightExpression->evaluate( &feature );
    }
    else
    {
      QgsAttributes attrs = feature.attributes();
      value = attrs.value( mWeightAttrNum );
    }
    bool ok = false;
    double evalWeight = value.toDouble( &ok );
    if ( ok )
    {
      weight = evalWeight;
    }
  }

  int width = context.painter()->device()->width() / mRenderQuality;
  int height = context.painter()->device()->height() / mRenderQuality;

  //transform geometry if required
  QgsGeometry* transformedGeom = 0;
  const QgsCoordinateTransform* xform = context.coordinateTransform();
  if ( xform )
  {
    transformedGeom = new QgsGeometry( *feature.constGeometry() );
    transformedGeom->transform( *xform );
  }

  //convert point to multipoint
  QgsMultiPoint multiPoint = convertToMultipoint( transformedGeom ? transformedGeom : feature.constGeometry() );

  delete transformedGeom;
  transformedGeom = 0;

  //loop through all points in multipoint
  for ( QgsMultiPoint::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt )
  {
    QgsPoint pixel = context.mapToPixel().transform( *pointIt );
    int pointX = pixel.x() / mRenderQuality;
    int pointY = pixel.y() / mRenderQuality;
    for ( int x = qMax( pointX - mRadiusPixels, 0 ); x < qMin( pointX + mRadiusPixels, width ); ++x )
    {
      for ( int y = qMax( pointY - mRadiusPixels, 0 ); y < qMin( pointY + mRadiusPixels, height ); ++y )
      {
        int index = y * width + x;
        if ( index >= mValues.count( ) )
        {
          continue;
        }
        double distanceSquared = pow( pointX - x, 2.0 ) + pow( pointY - y, 2.0 );
        if ( distanceSquared > mRadiusSquared )
        {
          continue;
        }

        double score = weight * quarticKernel( sqrt( distanceSquared ), mRadiusPixels );
        double value = mValues[ index ] + score;
        if ( value > mCalculatedMaxValue )
        {
          mCalculatedMaxValue = value;
        }
        mValues[ index ] = value;
      }
    }
  }

  mFeaturesRendered++;
#if 0
  //TODO - enable progressive rendering
  if ( mFeaturesRendered % 200  == 0 )
  {
    renderImage( context );
  }
#endif
  return true;
}
bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
  Q_UNUSED( drawVertexMarker );
  //point position in screen coords
  QgsGeometry* geom = feature.geometry();
  QGis::WkbType geomType = geom->wkbType();
  if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D )
  {
    //can only render point type
    return false;
  }
  QPointF pt;
  _getPoint( pt, context, geom->asWkb() );


  //get list of labels and symbols
  QStringList labelAttributeList;
  QList<QgsMarkerSymbolV2*> symbolList;

  if ( mDisplacementIds.contains( feature.id() ) )
  {
    //create the symbol for the whole display group if the id is the first entry in a display group
    QList<QMap<QgsFeatureId, QgsFeature> >::iterator it = mDisplacementGroups.begin();
    for ( ; it != mDisplacementGroups.end(); ++it )
    {
      //create the symbol for the whole display group if the id is the first entry in a display group
      if ( feature.id() == it->begin().key() )
      {
        QMap<QgsFeatureId, QgsFeature>::iterator attIt = it->begin();
        for ( ; attIt != it->end(); ++attIt )
        {
          if ( mDrawLabels )
          {
            labelAttributeList << getLabel( attIt.value() );
          }
          else
          {
            labelAttributeList << QString();
          }
          symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, attIt.value() ) );
        }
      }
    }
  }
  else //only one feature
  {
    symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, feature ) );
    if ( mDrawLabels )
    {
      labelAttributeList << getLabel( feature );
    }
    else
    {
      labelAttributeList << QString();
    }
  }

  if ( symbolList.isEmpty() && labelAttributeList.isEmpty() )
  {
    return true; //display all point symbols for one posi
  }


  //draw symbol
  double diagonal = 0;
  double currentWidthFactor; //scale symbol size to map unit and output resolution

  QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin();
  for ( ; it != symbolList.constEnd(); ++it )
  {
    if ( *it )
    {
      currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit() );
      double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor;
      if ( currentDiagonal > diagonal )
      {
        diagonal = currentDiagonal;
      }
    }
  }


  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );
  double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition );
  double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits;

  //draw Circle
  drawCircle( radius, symbolContext, pt, symbolList.size() );

  QList<QPointF> symbolPositions;
  QList<QPointF> labelPositions;
  calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions );

  //draw mid point
  if ( labelAttributeList.size() > 1 )
  {
    if ( mCenterSymbol )
    {
      mCenterSymbol->renderPoint( pt, &feature, context, layer, selected );
    }
    else
    {
      context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
    }
  }

  //draw symbols on the circle
  drawSymbols( feature, context, symbolList, symbolPositions, selected );
  //and also the labels
  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
  return true;
}
Example #30
0
QgsRenderContext QgsRenderContext::fromMapSettings( const QgsMapSettings& mapSettings )
{
  QgsRenderContext ctx;
  ctx.setMapToPixel( mapSettings.mapToPixel() );
  ctx.setExtent( mapSettings.visibleExtent() );
  ctx.setFlag( DrawEditingInfo, mapSettings.testFlag( QgsMapSettings::DrawEditingInfo ) );
  ctx.setFlag( ForceVectorOutput, mapSettings.testFlag( QgsMapSettings::ForceVectorOutput ) );
  ctx.setFlag( UseAdvancedEffects, mapSettings.testFlag( QgsMapSettings::UseAdvancedEffects ) );
  ctx.setFlag( UseRenderingOptimization, mapSettings.testFlag( QgsMapSettings::UseRenderingOptimization ) );
  ctx.setCoordinateTransform( nullptr );
  ctx.setSelectionColor( mapSettings.selectionColor() );
  ctx.setFlag( DrawSelection, mapSettings.testFlag( QgsMapSettings::DrawSelection ) );
  ctx.setFlag( DrawSymbolBounds, mapSettings.testFlag( QgsMapSettings::DrawSymbolBounds ) );
  ctx.setRasterScaleFactor( 1.0 );
  ctx.setScaleFactor( mapSettings.outputDpi() / 25.4 ); // = pixels per mm
  ctx.setRendererScale( mapSettings.scale() );
  ctx.setExpressionContext( mapSettings.expressionContext() );

  //this flag is only for stopping during the current rendering progress,
  //so must be false at every new render operation
  ctx.setRenderingStopped( false );

  return ctx;
}