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; }
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; } }
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; }
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(); }
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() ) ); }
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; }
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(); }
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 ); } }
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 ); } }
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; } }
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(); }
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(); } }
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 ); } }
double QgsMapTool::searchRadiusMU( const QgsRenderContext& context ) { return searchRadiusMM() * context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel(); }
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; }
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; }