QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c ) { if ( s.sizeType == QgsDiagramSettings::MM ) { return QSizeF( size.width() * c.scaleFactor(), size.height() * c.scaleFactor() ); } else { return QSizeF( size.width() / c.mapToPixel().mapUnitsPerPixel(), size.height() / c.mapToPixel().mapUnitsPerPixel() ); } }
void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const QgsFields& fields ) { if ( !mSubRenderer ) { return; } // first call start render on the sub renderer mSubRenderer->startRender( context, fields ); mFeaturesCategories.clear(); mSymbolCategories.clear(); mFeatureDecorations.clear(); mFields = fields; // We compute coordinates of the extent which will serve as exterior ring // for the final polygon // It must be computed in the destination CRS if reprojection is enabled. const QgsMapToPixel& mtp( context.mapToPixel() ); if ( !context.painter() ) { return; } // convert viewport to dest CRS QRect e( context.painter()->viewport() ); // add some space to hide borders and tend to infinity e.adjust( -e.width()*5, -e.height()*5, e.width()*5, e.height()*5 ); QgsPolyline exteriorRing; exteriorRing << mtp.toMapCoordinates( e.topLeft() ); exteriorRing << mtp.toMapCoordinates( e.topRight() ); exteriorRing << mtp.toMapCoordinates( e.bottomRight() ); exteriorRing << mtp.toMapCoordinates( e.bottomLeft() ); exteriorRing << mtp.toMapCoordinates( e.topLeft() ); // copy the rendering context mContext = context; // If reprojection is enabled, we must reproject during renderFeature // and act as if there is no reprojection // If we don't do that, there is no need to have a simple rectangular extent // that covers the whole screen // (a rectangle in the destCRS cannot be expressed as valid coordinates in the sourceCRS in general) if ( context.coordinateTransform() ) { // disable projection mContext.setCoordinateTransform( 0 ); // recompute extent so that polygon clipping is correct QRect v( context.painter()->viewport() ); mContext.setExtent( QgsRectangle( mtp.toMapCoordinates( v.topLeft() ), mtp.toMapCoordinates( v.bottomRight() ) ) ); // do we have to recompute the MapToPixel ? } mExtentPolygon.clear(); mExtentPolygon.append( exteriorRing ); return; }
void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext &context, pal::LabelPosition *label ) const { #if 1 // XXX strk // features are pre-rotated but not scaled/translated, // so we only disable rotation here. Ideally, they'd be // also pre-scaled/translated, as suggested here: // https://issues.qgis.org/issues/11856 QgsMapToPixel xform = context.mapToPixel(); xform.setMapRotation( 0, 0, 0 ); #else const QgsMapToPixel &xform = context.mapToPixel(); #endif QgsDiagramLabelFeature *dlf = dynamic_cast<QgsDiagramLabelFeature *>( label->getFeaturePart()->feature() ); QgsFeature feature; feature.setFields( mFields ); feature.setValid( true ); feature.setId( label->getFeaturePart()->featureId() ); feature.setAttributes( dlf->attributes() ); context.expressionContext().setFeature( feature ); //calculate top-left point for diagram //first, calculate the centroid of the label (accounts for PAL creating //rotated labels when we do not want to draw the diagrams rotated) double centerX = 0; double centerY = 0; for ( int i = 0; i < 4; ++i ) { centerX += label->getX( i ); centerY += label->getY( i ); } QgsPointXY outPt( centerX / 4.0, centerY / 4.0 ); //then, calculate the top left point for the diagram with this center position QgsPointXY centerPt = xform.transform( outPt.x() - label->getWidth() / 2, outPt.y() - label->getHeight() / 2 ); mSettings.renderer()->renderDiagram( feature, context, centerPt.toQPointF(), mSettings.dataDefinedProperties() ); //insert into label search tree to manipulate position interactively mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, QString(), QFont(), true, false ); }
float QgsDiagram::sizePainterUnits( float l, const QgsDiagramSettings& s, const QgsRenderContext& c ) { if ( s.sizeType == QgsDiagramSettings::MM ) { return l * c.scaleFactor(); } else { return l / c.mapToPixel().mapUnitsPerPixel(); } }
void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c ) { if ( s.sizeType == QgsDiagramSettings::MM ) { pen.setWidthF( s.penWidth * c.scaleFactor() ); } else { pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() ); } }
void QgsDiagramRendererV2::convertSizeToMapUnits( QSizeF& size, const QgsRenderContext& context ) const { if ( !size.isValid() ) { return; } double pixelToMap = context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel(); size.rwidth() *= pixelToMap; size.rheight() *= pixelToMap; }
double QgsDiagramFactory::diagramSizeScaleFactor( const QgsRenderContext& context ) const { if ( mSizeUnit == MM ) { return context.scaleFactor(); } else if ( mSizeUnit == MapUnits ) { return 1 / context.mapToPixel().mapUnitsPerPixel(); //pixel based devices } return 1.0; }
int QgsPalLayerSettings::sizeToPixel( double size, const QgsRenderContext& c ) const { double pixelSize; if ( fontSizeInMapUnits ) { pixelSize = size / c.mapToPixel().mapUnitsPerPixel() * c.rasterScaleFactor(); } else //font size in points { // set font size from points to output size pixelSize = 0.3527 * size * c.scaleFactor() * c.rasterScaleFactor(); } return ( int )( pixelSize + 0.5 ); }
QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c ) { QFont f = s.font; if ( s.sizeType == QgsDiagramSettings::MM ) { f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() ); } else { f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() ); } return f; }
QgsConstWkbPtr QgsSymbolV2::_getLineString( QPolygonF& pts, QgsRenderContext& context, QgsConstWkbPtr wkbPtr, bool clipToExtent ) { QgsWKBTypes::Type wkbType = wkbPtr.readHeader(); unsigned int nPoints; wkbPtr >> nPoints; const QgsCoordinateTransform* ct = context.coordinateTransform(); const QgsMapToPixel& mtp = context.mapToPixel(); //apply clipping for large lines to achieve a better rendering performance if ( clipToExtent && nPoints > 1 ) { 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 ); wkbPtr -= 1 + 2 * sizeof( int ); wkbPtr = QgsClipper::clippedLineWKB( wkbPtr, clipRect, pts ); } else { pts.resize( nPoints ); int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double ); Q_ASSERT( skipZM >= 0 ); QPointF *ptr = pts.data(); for ( unsigned int i = 0; i < nPoints; ++i, ++ptr ) { wkbPtr >> ptr->rx() >> ptr->ry(); wkbPtr += skipZM; } } //transform the QPolygonF to screen coordinates if ( ct ) { ct->transformPolygon( pts ); } QPointF *ptr = pts.data(); for ( int i = 0; i < pts.size(); ++i, ++ptr ) { mtp.transformInPlace( ptr->rx(), ptr->ry() ); } return wkbPtr; }
void QgsDiagramRendererV2::convertSizeToMapUnits( QSizeF& size, const QgsRenderContext& context ) const { if ( !size.isValid() ) { return; } int dpi = dpiPaintDevice( context.constPainter() ); if ( dpi < 0 ) { return; } double pixelToMap = dpi / 25.4 * context.mapToPixel().mapUnitsPerPixel(); size.rwidth() *= pixelToMap; size.rheight() *= pixelToMap; }
bool QgsPalLayerSettings::checkMinimumSizeMM( const QgsRenderContext& ct, QgsGeometry* geom, double minSize ) const { if ( minSize <= 0 ) { return true; } if ( !geom ) { return false; } QGis::GeometryType featureType = geom->type(); if ( featureType == QGis::Point ) //minimum size does not apply to point features { return true; } double mapUnitsPerMM = ct.mapToPixel().mapUnitsPerPixel() * ct.scaleFactor(); if ( featureType == QGis::Line ) { double length = geom->length(); if ( length >= 0.0 ) { return ( length >= ( minSize * mapUnitsPerMM ) ); } } else if ( featureType == QGis::Polygon ) { double area = geom->area(); if ( area >= 0.0 ) { return ( sqrt( area ) >= ( minSize * mapUnitsPerMM ) ); } } return true; //should never be reached. Return true in this case to label such geometries anyway. }
double QgsMapTool::searchRadiusMU( const QgsRenderContext& context ) { return searchRadiusMM() * context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel(); }
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 QgsGraduatedSymbolRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature & f, QImage* img, bool selected, double opacity ) { QPainter *p = renderContext.painter(); QgsSymbol* theSymbol = symbolForFeature( &f ); if ( !theSymbol ) { if ( img && mGeometryType == QGis::Point ) { img->fill( 0 ); } else if ( mGeometryType != QGis::Point ) { p->setPen( Qt::NoPen ); p->setBrush( Qt::NoBrush ); } return; } //set the qpen and qpainter to the right values // Point if ( img && mGeometryType == QGis::Point ) { double fieldScale = 1.0; double rotation = 0.0; if ( theSymbol->scaleClassificationField() >= 0 ) { //first find out the value for the scale classification attribute const QgsAttributeMap& attrs = f.attributeMap(); fieldScale = sqrt( qAbs( attrs[theSymbol->scaleClassificationField()].toDouble() ) ); QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 ); } if ( theSymbol->rotationClassificationField() >= 0 ) { const QgsAttributeMap& attrs = f.attributeMap(); rotation = attrs[theSymbol->rotationClassificationField()].toDouble(); QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 ); } QString oldName; if ( theSymbol->symbolField() >= 0 ) { const QgsAttributeMap& attrs = f.attributeMap(); QString name = attrs[theSymbol->symbolField()].toString(); QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 ); oldName = theSymbol->pointSymbolName(); theSymbol->setNamedPointSymbol( name ); } double scale = renderContext.scaleFactor(); if ( theSymbol->pointSizeUnits() ) { scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel(); } *img = theSymbol->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, rotation, renderContext.rasterScaleFactor(), opacity ); if ( !oldName.isNull() ) { theSymbol->setNamedPointSymbol( oldName ); } } // Line, polygon if ( mGeometryType != QGis::Point ) { if ( !selected ) { QPen pen = theSymbol->pen(); pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); p->setPen( pen ); if ( mGeometryType == QGis::Polygon ) { QBrush brush = theSymbol->brush(); scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout p->setBrush( brush ); } } else { QPen pen = theSymbol->pen(); pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); if ( mGeometryType == QGis::Polygon ) { QBrush brush = theSymbol->brush(); scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout brush.setColor( mSelectionColor ); p->setBrush( brush ); } else //don't draw outlines in selection color for polys otherwise they appear merged { pen.setColor( mSelectionColor ); } p->setPen( pen ); } } }
void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext& context ) { QString labelText; if ( formatNumbers == true && ( f.attributeMap()[fieldIndex].type() == QVariant::Int || f.attributeMap()[fieldIndex].type() == QVariant::Double ) ) { QString numberFormat; double d = f.attributeMap()[fieldIndex].toDouble(); if ( d > 0 && plusSign == true ) { numberFormat.append( "+" ); } numberFormat.append( "%1" ); labelText = numberFormat.arg( d, 0, 'f', decimals ); } else { labelText = f.attributeMap()[fieldIndex].toString(); } double labelX, labelY; // will receive label size QFont labelFont = textFont; //data defined label size? QMap< DataDefinedProperties, int >::const_iterator it = dataDefinedProperties.find( QgsPalLayerSettings::Size ); if ( it != dataDefinedProperties.constEnd() ) { //find out size QVariant size = f.attributeMap().value( *it ); if ( size.isValid() ) { double sizeDouble = size.toDouble(); if ( sizeDouble <= 0 ) { return; } labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) ); } QFontMetricsF labelFontMetrics( labelFont ); calculateLabelSize( &labelFontMetrics, labelText, labelX, labelY ); } else { calculateLabelSize( fontMetrics, labelText, labelX, labelY ); } QgsGeometry* geom = f.geometry(); if ( ct ) // reproject the geometry if necessary geom->transform( *ct ); if ( !checkMinimumSizeMM( context, geom, minFeatureSize ) ) { return; } // CLIP the geometry if it is bigger than the extent QgsGeometry* geomClipped = NULL; GEOSGeometry* geos_geom; bool do_clip = !extentGeom->contains( geom ); if ( do_clip ) { geomClipped = geom->intersection( extentGeom ); // creates new geometry geos_geom = geomClipped->asGeos(); } else { geos_geom = geom->asGeos(); } if ( geos_geom == NULL ) return; // invalid geometry GEOSGeometry* geos_geom_clone = GEOSGeom_clone( geos_geom ); if ( do_clip ) delete geomClipped; //data defined position / alignment / rotation? bool dataDefinedPosition = false; bool dataDefinedRotation = false; double xPos = 0.0, yPos = 0.0, angle = 0.0; bool ddXPos, ddYPos; QMap< DataDefinedProperties, int >::const_iterator dPosXIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionX ); if ( dPosXIt != dataDefinedProperties.constEnd() ) { QMap< DataDefinedProperties, int >::const_iterator dPosYIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionY ); if ( dPosYIt != dataDefinedProperties.constEnd() ) { //data defined position. But field values could be NULL -> positions will be generated by PAL xPos = f.attributeMap().value( *dPosXIt ).toDouble( &ddXPos ); yPos = f.attributeMap().value( *dPosYIt ).toDouble( &ddYPos ); if ( ddXPos && ddYPos ) { dataDefinedPosition = true; //x/y shift in case of alignment double xdiff = 0; double ydiff = 0; //horizontal alignment QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali ); if ( haliIt != dataDefinedProperties.end() ) { QString haliString = f.attributeMap().value( *haliIt ).toString(); if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 ) { xdiff -= labelX / 2.0; } else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 ) { xdiff -= labelX; } } //vertical alignment QMap< DataDefinedProperties, int >::const_iterator valiIt = dataDefinedProperties.find( QgsPalLayerSettings::Vali ); if ( valiIt != dataDefinedProperties.constEnd() ) { QString valiString = f.attributeMap().value( *valiIt ).toString(); if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 ) { if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 ) { ydiff -= labelY; } else { QFontMetrics labelFontMetrics( labelFont ); double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height(); if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 ) { ydiff -= labelY * descentRatio; } else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 ) { ydiff -= labelY * descentRatio; ydiff -= labelY * 0.5 * ( 1 - descentRatio ); } } } } //data defined rotation? QMap< DataDefinedProperties, int >::const_iterator rotIt = dataDefinedProperties.find( QgsPalLayerSettings::Rotation ); if ( rotIt != dataDefinedProperties.constEnd() ) { dataDefinedRotation = true; angle = f.attributeMap().value( *rotIt ).toDouble() * M_PI / 180; //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center double xd = xdiff * cos( angle ) - ydiff * sin( angle ); double yd = xdiff * sin( angle ) + ydiff * cos( angle ); xdiff = xd; ydiff = yd; } //project xPos and yPos from layer to map CRS double z = 0; if ( ct ) { ct->transformInPlace( xPos, yPos, z ); } yPos += ydiff; xPos += xdiff; } } } QgsPalGeometry* lbl = new QgsPalGeometry( f.id(), labelText, geos_geom_clone ); // record the created geometry - it will be deleted at the end. geometries.append( lbl ); // register feature to the layer try { if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(), xPos, yPos, dataDefinedPosition, angle, dataDefinedRotation ) ) return; } catch ( std::exception &e ) { Q_UNUSED( e ); QgsDebugMsg( QString( "Ignoring feature %1 due PAL exception: " ).arg( f.id() ) + QString::fromLatin1( e.what() ) ); return; } // TODO: only for placement which needs character info pal::Feature* feat = palLayer->getFeature( lbl->strId() ); feat->setLabelInfo( lbl->info( fontMetrics, xform, rasterCompressFactor ) ); // TODO: allow layer-wide feature dist in PAL...? //data defined label-feature distance? double distance = dist; QMap< DataDefinedProperties, int >::const_iterator dDistIt = dataDefinedProperties.find( QgsPalLayerSettings::LabelDistance ); if ( dDistIt != dataDefinedProperties.constEnd() ) { distance = f.attributeMap().value( *dDistIt ).toDouble(); } if ( distance != 0 ) { if ( distInMapUnits ) //convert distance from mm/map units to pixels { distance /= context.mapToPixel().mapUnitsPerPixel(); } else //mm { distance *= vectorScaleFactor; } feat->setDistLabel( qAbs( ptOne.x() - ptZero.x() )* distance ); } //add parameters for data defined labeling to QgsPalGeometry QMap< DataDefinedProperties, int >::const_iterator dIt = dataDefinedProperties.constBegin(); for ( ; dIt != dataDefinedProperties.constEnd(); ++dIt ) { lbl->addDataDefinedValue( dIt.key(), f.attributeMap()[dIt.value()] ); } }
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; }
void QgsUniqueValueRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature& f, QImage* img, bool selected, double opacity ) { QPainter *p = renderContext.painter(); QgsSymbol* symbol = symbolForFeature( &f ); if ( !symbol ) //no matching symbol { if ( img && mGeometryType == QGis::Point ) { img->fill( 0 ); } else if ( mGeometryType != QGis::Point ) { p->setPen( Qt::NoPen ); p->setBrush( Qt::NoBrush ); } return; } // Point if ( img && mGeometryType == QGis::Point ) { double fieldScale = 1.0; double rotation = 0.0; if ( symbol->scaleClassificationField() >= 0 ) { //first find out the value for the scale classification attribute fieldScale = sqrt( qAbs( f.attribute( symbol->scaleClassificationField() ).toDouble() ) ); } if ( symbol->rotationClassificationField() >= 0 ) { rotation = f.attribute( symbol->rotationClassificationField() ).toDouble(); } QString oldName; if ( symbol->symbolField() >= 0 ) { QString name = f.attribute( symbol->symbolField() ).toString(); oldName = symbol->pointSymbolName(); symbol->setNamedPointSymbol( name ); } double scale = renderContext.scaleFactor(); if ( symbol->pointSizeUnits() ) { scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel(); } *img = symbol->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, rotation, renderContext.rasterScaleFactor(), opacity ); if ( !oldName.isNull() ) { symbol->setNamedPointSymbol( oldName ); } } // Line, polygon else if ( mGeometryType != QGis::Point ) { if ( !selected ) { QPen pen = symbol->pen(); pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); p->setPen( pen ); if ( mGeometryType == QGis::Polygon ) { QBrush brush = symbol->brush(); scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout p->setBrush( brush ); } } else { QPen pen = symbol->pen(); pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); if ( mGeometryType == QGis::Polygon ) { QBrush brush = symbol->brush(); scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout brush.setColor( mSelectionColor ); p->setBrush( brush ); } else //don't draw outlines of polygons in selection color otherwise they appear merged { pen.setColor( mSelectionColor ); } p->setPen( pen ); } } }
QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRenderContext& rendererContext ) : QgsMapLayerRenderer( layer->id() ) , mRasterViewPort( nullptr ) , mPipe( nullptr ) { mPainter = rendererContext.painter(); const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel(); mMapToPixel = &theQgsMapToPixel; QgsMapToPixel mapToPixel = theQgsMapToPixel; if ( mapToPixel.mapRotation() ) { // unset rotation for the sake of local computations. // Rotation will be handled by QPainter later // TODO: provide a method of QgsMapToPixel to fetch map center // in geographical units QgsPoint center = mapToPixel.toMapCoordinates( mapToPixel.mapWidth() / 2.0, mapToPixel.mapHeight() / 2.0 ); mapToPixel.setMapRotation( 0, center.x(), center.y() ); } QgsRectangle myProjectedViewExtent; QgsRectangle myProjectedLayerExtent; if ( rendererContext.coordinateTransform() ) { QgsDebugMsg( "coordinateTransform set -> project extents." ); try { myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() ); } catch ( QgsCsException &cs ) { QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) ); myProjectedViewExtent.setMinimal(); } try { myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( layer->extent() ); } catch ( QgsCsException &cs ) { QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) ); myProjectedLayerExtent.setMinimal(); } } else { QgsDebugMsg( "coordinateTransform not set" ); myProjectedViewExtent = rendererContext.extent(); myProjectedLayerExtent = layer->extent(); } // clip raster extent to view extent QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent ); if ( myRasterExtent.isEmpty() ) { QgsDebugMsg( "draw request outside view extent." ); // nothing to do return; } QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() ); QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() ); QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() ); QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() ); // // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings // relating to the size (in pixels and coordinate system units) of the raster part that is // in view in the map window. It also stores the origin. // //this is not a class level member because every time the user pans or zooms //the contents of the rasterViewPort will change mRasterViewPort = new QgsRasterViewPort(); mRasterViewPort->mDrawnExtent = myRasterExtent; if ( rendererContext.coordinateTransform() ) { mRasterViewPort->mSrcCRS = layer->crs(); mRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS(); mRasterViewPort->mSrcDatumTransform = rendererContext.coordinateTransform()->sourceDatumTransform(); mRasterViewPort->mDestDatumTransform = rendererContext.coordinateTransform()->destinationDatumTransform(); } else { mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid mRasterViewPort->mSrcDatumTransform = -1; mRasterViewPort->mDestDatumTransform = -1; } // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport) mRasterViewPort->mTopLeftPoint = mapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() ); mRasterViewPort->mBottomRightPoint = mapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() ); // align to output device grid, i.e. floor/ceil to integers // TODO: this should only be done if paint device is raster - screen, image // for other devices (pdf) it can have floating point origin // we could use floating point for raster devices as well, but respecting the // output device grid should make it more effective as the resampling is done in // the provider anyway mRasterViewPort->mTopLeftPoint.setX( floor( mRasterViewPort->mTopLeftPoint.x() ) ); mRasterViewPort->mTopLeftPoint.setY( floor( mRasterViewPort->mTopLeftPoint.y() ) ); mRasterViewPort->mBottomRightPoint.setX( ceil( mRasterViewPort->mBottomRightPoint.x() ) ); mRasterViewPort->mBottomRightPoint.setY( ceil( mRasterViewPort->mBottomRightPoint.y() ) ); // recalc myRasterExtent to aligned values myRasterExtent.set( mapToPixel.toMapCoordinatesF( mRasterViewPort->mTopLeftPoint.x(), mRasterViewPort->mBottomRightPoint.y() ), mapToPixel.toMapCoordinatesF( mRasterViewPort->mBottomRightPoint.x(), mRasterViewPort->mTopLeftPoint.y() ) ); //raster viewport top left / bottom right are already rounded to int mRasterViewPort->mWidth = static_cast<int>( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ); mRasterViewPort->mHeight = static_cast<int>( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ); //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue //mapToPixel.mapUnitsPerPixel() is less then 1, //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas() QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 ); QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( layer->width() ), 3 ); QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( layer->height() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 ); QgsDebugMsgLevel( QString( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 ); QgsDebugMsgLevel( QString( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 ); QgsDebugMsgLevel( QString( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 ); QgsDebugMsgLevel( QString( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 ); QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 ); QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 ); // /\/\/\ - added to handle zoomed-in rasters // TODO R->mLastViewPort = *mRasterViewPort; // TODO: is it necessary? Probably WMS only? layer->dataProvider()->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() ); // copy the whole raster pipe! mPipe = new QgsRasterPipe( *layer->pipe() ); }
void QgsLabel::renderLabel( QgsRenderContext &renderContext, QgsFeature &feature, bool selected, QgsLabelAttributes *classAttributes ) { Q_UNUSED( classAttributes ); if ( mLabelAttributes->selectedOnly() && !selected ) return; QPen pen; QFont font; QString value; QString text; /* Calc scale (not nice) */ QgsPoint point; point = renderContext.mapToPixel().transform( 0, 0 ); double x1 = point.x(); point = renderContext.mapToPixel().transform( 1000, 0 ); double x2 = point.x(); double scale = ( x2 - x1 ) * 0.001; /* Text */ value = fieldValue( Text, feature ); if ( value.isEmpty() ) { text = mLabelAttributes->text(); } else { text = value; } /* Font */ value = fieldValue( Family, feature ); if ( value.isEmpty() ) { font.setFamily( mLabelAttributes->family() ); } else { font.setFamily( value ); } double size; value = fieldValue( Size, feature ); if ( value.isEmpty() ) { size = mLabelAttributes->size(); } else { size = value.toDouble(); } int sizeType; value = fieldValue( SizeType, feature ); if ( value.isEmpty() ) sizeType = mLabelAttributes->sizeType(); else { value = value.toLower(); if ( value.compare( "mapunits" ) == 0 ) sizeType = QgsLabelAttributes::MapUnits; else sizeType = QgsLabelAttributes::PointUnits; } if ( sizeType == QgsLabelAttributes::MapUnits ) { size *= scale; } else //point units { double sizeMM = size * 0.3527; size = sizeMM * renderContext.scaleFactor(); } //Request font larger (multiplied by rasterScaleFactor) as a workaround for the Qt font bug //and scale the painter down by rasterScaleFactor when drawing the label size *= renderContext.rasterScaleFactor(); if (( int )size <= 0 ) // skip too small labels return; font.setPixelSize( size ); value = fieldValue( Color, feature ); if ( value.isEmpty() ) { pen.setColor( mLabelAttributes->color() ); } else { pen.setColor( QColor( value ) ); } value = fieldValue( Bold, feature ); if ( value.isEmpty() ) { font.setBold( mLabelAttributes->bold() ); } else { font.setBold(( bool ) value.toInt() ); } value = fieldValue( Italic, feature ); if ( value.isEmpty() ) { font.setItalic( mLabelAttributes->italic() ); } else { font.setItalic(( bool ) value.toInt() ); } value = fieldValue( Underline, feature ); if ( value.isEmpty() ) { font.setUnderline( mLabelAttributes->underline() ); } else { font.setUnderline(( bool ) value.toInt() ); } value = fieldValue( StrikeOut, feature ); if ( value.isEmpty() ) { font.setStrikeOut( mLabelAttributes->strikeOut() ); } else { font.setStrikeOut(( bool ) value.toInt() ); } // QgsPoint overridePoint; bool useOverridePoint = false; value = fieldValue( XCoordinate, feature ); if ( !value.isEmpty() ) { overridePoint.setX( value.toDouble() ); useOverridePoint = true; } value = fieldValue( YCoordinate, feature ); if ( !value.isEmpty() ) { overridePoint.setY( value.toDouble() ); useOverridePoint = true; } /* Alignment */ int alignment; QFontMetrics fm( font ); int width, height; if ( mLabelAttributes->multilineEnabled() ) { QStringList texts = text.split( "\n" ); width = 0; for ( int i = 0; i < texts.size(); i++ ) { int w = fm.width( texts[i] ); if ( w > width ) width = w; } height = fm.height() * texts.size(); } else { width = fm.width( text ); height = fm.height(); } int dx = 0; int dy = 0; value = fieldValue( Alignment, feature ); if ( value.isEmpty() ) { alignment = mLabelAttributes->alignment(); } else { value = value.toLower(); alignment = 0; if ( value.contains( "left" ) ) alignment |= Qt::AlignLeft; else if ( value.contains( "right" ) ) alignment |= Qt::AlignRight; else alignment |= Qt::AlignHCenter; if ( value.contains( "bottom" ) ) alignment |= Qt::AlignBottom; else if ( value.contains( "top" ) ) alignment |= Qt::AlignTop; else alignment |= Qt::AlignVCenter; } if ( alignment & Qt::AlignLeft ) { dx = 0; } else if ( alignment & Qt::AlignHCenter ) { dx = -width / 2; } else if ( alignment & Qt::AlignRight ) { dx = -width; } if ( alignment & Qt::AlignBottom ) { dy = 0; } else if ( alignment & Qt::AlignVCenter ) { dy = height / 2; } else if ( alignment & Qt::AlignTop ) { dy = height; } // Offset double xoffset, yoffset; value = fieldValue( XOffset, feature ); if ( value.isEmpty() ) { xoffset = mLabelAttributes->xOffset(); } else { xoffset = value.toDouble(); } value = fieldValue( YOffset, feature ); if ( value.isEmpty() ) { yoffset = mLabelAttributes->yOffset(); } else { yoffset = value.toDouble(); } // recalc offset to pixels if ( mLabelAttributes->offsetType() == QgsLabelAttributes::MapUnits ) { xoffset *= scale; yoffset *= scale; } else { xoffset = xoffset * 0.3527 * renderContext.scaleFactor(); yoffset = yoffset * 0.3527 * renderContext.scaleFactor(); } // Angle double ang; value = fieldValue( Angle, feature ); if ( value.isEmpty() ) { ang = mLabelAttributes->angle(); } else { ang = value.toDouble(); } // Work out a suitable position to put the label for the // feature. For multi-geometries, put the same label on each // part. if ( useOverridePoint ) { renderLabel( renderContext, overridePoint, text, font, pen, dx, dy, xoffset, yoffset, ang, width, height, alignment ); } else { std::vector<labelpoint> points; labelPoint( points, feature ); for ( uint i = 0; i < points.size(); ++i ) { renderLabel( renderContext, points[i].p, text, font, pen, dx, dy, xoffset, yoffset, mLabelAttributes->angleIsAuto() ? points[i].angle : ang, width, height, alignment ); } } }
void QgsFeatureRendererV2::renderFeatureWithSymbol( QgsFeature& feature, QgsSymbolV2* symbol, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { QgsSymbolV2::SymbolType symbolType = symbol->type(); const QgsGeometry* geom = feature.constGeometry(); if ( !geom || !geom->geometry() ) { return; } const QgsGeometry* segmentizedGeometry = geom; bool deleteSegmentizedGeometry = false; context.setGeometry( geom->geometry() ); //convert curve types to normal point/line/polygon ones switch ( QgsWKBTypes::flatType( geom->geometry()->wkbType() ) ) { case QgsWKBTypes::CurvePolygon: case QgsWKBTypes::CircularString: case QgsWKBTypes::CompoundCurve: case QgsWKBTypes::MultiSurface: case QgsWKBTypes::MultiCurve: { QgsAbstractGeometryV2* g = geom->geometry()->segmentize(); if ( !g ) { return; } segmentizedGeometry = new QgsGeometry( g ); deleteSegmentizedGeometry = true; break; } default: break; } switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) ) { case QgsWKBTypes::Point: { if ( symbolType != QgsSymbolV2::Marker ) { QgsDebugMsg( "point can be drawn only with marker symbol!" ); break; } QPointF pt; _getPoint( pt, context, segmentizedGeometry->asWkb() ); (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected ); if ( context.testFlag( QgsRenderContext::DrawSymbolBounds ) ) { //draw debugging rect context.painter()->setPen( Qt::red ); context.painter()->setBrush( QColor( 255, 0, 0, 100 ) ); context.painter()->drawRect((( QgsMarkerSymbolV2* )symbol )->bounds( pt, context ) ); } } break; case QgsWKBTypes::LineString: { if ( symbolType != QgsSymbolV2::Line ) { QgsDebugMsg( "linestring can be drawn only with line symbol!" ); break; } QPolygonF pts; _getLineString( pts, context, segmentizedGeometry->asWkb(), symbol->clipFeaturesToExtent() ); (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected ); } break; case QgsWKBTypes::Polygon: { if ( symbolType != QgsSymbolV2::Fill ) { QgsDebugMsg( "polygon can be drawn only with fill symbol!" ); break; } QPolygonF pts; QList<QPolygonF> holes; _getPolygon( pts, holes, context, segmentizedGeometry->asWkb(), symbol->clipFeaturesToExtent() ); (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), &feature, context, layer, selected ); } break; case QgsWKBTypes::MultiPoint: { if ( symbolType != QgsSymbolV2::Marker ) { QgsDebugMsg( "multi-point can be drawn only with marker symbol!" ); break; } QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) ); unsigned int num; wkbPtr >> num; const unsigned char* ptr = wkbPtr; QPointF pt; for ( unsigned int i = 0; i < num; ++i ) { ptr = QgsConstWkbPtr( _getPoint( pt, context, ptr ) ); (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected ); } } break; case QgsWKBTypes::MultiCurve: case QgsWKBTypes::MultiLineString: { if ( symbolType != QgsSymbolV2::Line ) { QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" ); break; } QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) ); unsigned int num; wkbPtr >> num; const unsigned char* ptr = wkbPtr; QPolygonF pts; const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() ); for ( unsigned int i = 0; i < num; ++i ) { if ( geomCollection ) { context.setGeometry( geomCollection->geometryN( i ) ); } ptr = QgsConstWkbPtr( _getLineString( pts, context, ptr, symbol->clipFeaturesToExtent() ) ); (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected ); } } break; case QgsWKBTypes::MultiSurface: case QgsWKBTypes::MultiPolygon: { if ( symbolType != QgsSymbolV2::Fill ) { QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" ); break; } QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb() + 1 + sizeof( int ) ); unsigned int num; wkbPtr >> num; const unsigned char* ptr = wkbPtr; QPolygonF pts; QList<QPolygonF> holes; const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() ); for ( unsigned int i = 0; i < num; ++i ) { if ( geomCollection ) { context.setGeometry( geomCollection->geometryN( i ) ); } ptr = _getPolygon( pts, holes, context, ptr, symbol->clipFeaturesToExtent() ); (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), &feature, context, layer, selected ); } break; } default: QgsDebugMsg( QString( "feature %1: unsupported wkb type 0x%2 for rendering" ).arg( feature.id() ).arg( geom->wkbType(), 0, 16 ) ); } if ( drawVertexMarker ) { const QgsCoordinateTransform* ct = context.coordinateTransform(); const QgsMapToPixel& mtp = context.mapToPixel(); QgsPointV2 vertexPoint; QgsVertexId vertexId; double x, y, z; QPointF mapPoint; while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) ) { //transform x = vertexPoint.x(); y = vertexPoint.y(); z = vertexPoint.z(); if ( ct ) { ct->transformInPlace( x, y, z ); } mapPoint.setX( x ); mapPoint.setY( y ); mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() ); renderVertexMarker( mapPoint, context ); } } if ( deleteSegmentizedGeometry ) { delete segmentizedGeometry; } }
void QgsLabel::renderLabel( QgsRenderContext &renderContext, QgsPoint point, QString text, QFont font, QPen pen, int dx, int dy, double xoffset, double yoffset, double ang, int width, int height, int alignment ) { QPainter *painter = renderContext.painter(); // Convert point to projected units if ( renderContext.coordinateTransform() ) { try { point = renderContext.coordinateTransform()->transform( point ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); // unused otherwise QgsDebugMsg( "Caught transform error. Skipping rendering this label" ); return; } } // and then to canvas units renderContext.mapToPixel().transform( &point ); double x = point.x(); double y = point.y(); double rad = ang * M_PI / 180; x = x + xoffset * cos( rad ) - yoffset * sin( rad ); y = y - xoffset * sin( rad ) - yoffset * cos( rad ); painter->save(); painter->setFont( font ); painter->translate( x, y ); //correct oversampled font size back by scaling painter down painter->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() ); painter->rotate( -ang ); // // Draw a buffer behind the text if one is desired // if ( mLabelAttributes->bufferSizeIsSet() && mLabelAttributes->bufferEnabled() ) { double myBufferSize = mLabelAttributes->bufferSize() * 0.3527 * renderContext.scaleFactor() * renderContext.rasterScaleFactor(); QPen bufferPen; if ( mLabelAttributes->bufferColorIsSet() ) { bufferPen.setColor( mLabelAttributes->bufferColor() ); } else //default to a white buffer { bufferPen.setColor( Qt::white ); } painter->setPen( bufferPen ); double bufferStepSize; //hack to distinguish pixel devices from logical devices if (( renderContext.scaleFactor() - 1 ) > 1.5 ) { bufferStepSize = 1; } else //draw more dense in case of logical devices { bufferStepSize = 1 / renderContext.rasterScaleFactor(); } for ( double i = dx - myBufferSize; i <= dx + myBufferSize; i += bufferStepSize ) { for ( double j = dy - myBufferSize; j <= dy + myBufferSize; j += bufferStepSize ) { if ( mLabelAttributes->multilineEnabled() ) painter->drawText( QRectF( i, j - height, width, height ), alignment, text ); else painter->drawText( QPointF( i, j ), text ); } } } painter->setPen( pen ); if ( mLabelAttributes->multilineEnabled() ) painter->drawText( dx, dy - height, width, height, alignment, text ); else painter->drawText( dx, dy, text ); painter->restore(); }
double QgsQuickIdentifyKit::searchRadiusMU( const QgsRenderContext &context ) const { return mSearchRadiusMm * context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel(); }