diff --git a/python/core/qgsmaprenderer.sip b/python/core/qgsmaprenderer.sip index c4aed0a191b..550d33be818 100644 --- a/python/core/qgsmaprenderer.sip +++ b/python/core/qgsmaprenderer.sip @@ -19,7 +19,7 @@ public: //! called when starting rendering of a layer virtual int prepareLayer(QgsVectorLayer* layer, int& attrIndex, QgsRenderContext& ctx ) = 0; //! called for every feature - virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat ) = 0; + virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() ) = 0; //! called when the map is drawn and labels should be placed virtual void drawLabeling( QgsRenderContext& context ) = 0; //! called when we're done with rendering diff --git a/src/core/qgsmaprenderer.h b/src/core/qgsmaprenderer.h index be1754c6bb2..806a7775207 100644 --- a/src/core/qgsmaprenderer.h +++ b/src/core/qgsmaprenderer.h @@ -53,7 +53,7 @@ class QgsLabelingEngineInterface //! called when starting rendering of a layer virtual int prepareLayer( QgsVectorLayer* layer, int& attrIndex, QgsRenderContext& ctx ) = 0; //! called for every feature - virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat ) = 0; + virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() ) = 0; //! called when the map is drawn and labels should be placed virtual void drawLabeling( QgsRenderContext& context ) = 0; //! called when we're done with rendering diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 4e7f08a1a3f..4a5a8a64275 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -741,7 +741,7 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab // labeling - register feature if ( labeling && mRendererV2->symbolForFeature( fet ) != NULL ) - rendererContext.labelingEngine()->registerFeature( this, fet ); + rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext ); if ( mEditable ) { @@ -805,7 +805,7 @@ void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bo features[sym].append( fet ); if ( labeling && mRendererV2->symbolForFeature( fet ) != NULL ) - rendererContext.labelingEngine()->registerFeature( this, fet ); + rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext ); if ( mEditable ) { @@ -1052,7 +1052,7 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext ) if ( labeling && mRenderer->willRenderFeature( &fet ) ) { - rendererContext.labelingEngine()->registerFeature( this, fet ); + rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext ); } ++featureCount; diff --git a/src/plugins/labeling/labelinggui.cpp b/src/plugins/labeling/labelinggui.cpp index e416f942cbc..2c7385859ea 100644 --- a/src/plugins/labeling/labelinggui.cpp +++ b/src/plugins/labeling/labelinggui.cpp @@ -117,6 +117,7 @@ LabelingGui::LabelingGui( PalLabeling* lbl, QgsVectorLayer* layer, QWidget* pare chkNoObstacle->setChecked( !lyr.obstacle ); chkLabelPerFeaturePart->setChecked( lyr.labelPerPart ); chkMergeLines->setChecked( lyr.mergeLines ); + mMinSizeSpinBox->setValue( lyr.minFeatureSize ); bool scaleBased = ( lyr.scaleMin != 0 && lyr.scaleMax != 0 ); chkScaleBasedVisibility->setChecked( scaleBased ); @@ -231,7 +232,7 @@ LayerSettings LabelingGui::layerSettings() { lyr.bufferSize = 0; } - + lyr.minFeatureSize = mMinSizeSpinBox->value(); return lyr; } diff --git a/src/plugins/labeling/labelingguibase.ui b/src/plugins/labeling/labelingguibase.ui index 339584af626..f6e4c7cecb8 100644 --- a/src/plugins/labeling/labelingguibase.ui +++ b/src/plugins/labeling/labelingguibase.ui @@ -6,7 +6,7 @@ 0 0 - 480 + 448 610 @@ -18,15 +18,15 @@ - - + + Label this layer - + @@ -56,7 +56,7 @@ - + Placement @@ -326,7 +326,7 @@ - + @@ -648,21 +648,39 @@ - + label every part of multi-part features - + merge connected lines to avoid duplicate labels - + + + + + + Suppress labeling of features smaller than + + + + + + + mm + + + + + + @@ -699,7 +717,7 @@ - + Qt::Vertical @@ -712,7 +730,7 @@ - + Qt::Horizontal diff --git a/src/plugins/labeling/pallabeling.cpp b/src/plugins/labeling/pallabeling.cpp index 69c8c54cdcf..935949b11a5 100644 --- a/src/plugins/labeling/pallabeling.cpp +++ b/src/plugins/labeling/pallabeling.cpp @@ -105,6 +105,7 @@ LayerSettings::LayerSettings() bufferColor = Qt::white; labelPerPart = false; mergeLines = false; + minFeatureSize = 0.0; } LayerSettings::LayerSettings( const LayerSettings& s ) @@ -125,6 +126,7 @@ LayerSettings::LayerSettings( const LayerSettings& s ) bufferColor = s.bufferColor; labelPerPart = s.labelPerPart; mergeLines = s.mergeLines; + minFeatureSize = s.minFeatureSize; fontMetrics = NULL; ct = NULL; @@ -178,6 +180,7 @@ void LayerSettings::readFromLayer( QgsVectorLayer* layer ) bufferColor = _readColor( layer, "labeling/bufferColor" ); labelPerPart = layer->customProperty( "labeling/labelPerPart" ).toBool(); mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool(); + minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble(); } void LayerSettings::writeToLayer( QgsVectorLayer* layer ) @@ -205,6 +208,51 @@ void LayerSettings::writeToLayer( QgsVectorLayer* layer ) _writeColor( layer, "labeling/bufferColor", bufferColor ); layer->setCustomProperty( "labeling/labelPerPart", labelPerPart ); layer->setCustomProperty( "labeling/mergeLines", mergeLines ); + layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize ); +} + +bool LayerSettings::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; + } + + GEOSGeometry* geosGeom = geom->asGeos(); + if ( !geosGeom ) + { + return true; + } + + double mapUnitsPerMM = ct.mapToPixel().mapUnitsPerPixel() * ct.scaleFactor(); + if ( featureType == QGis::Line ) + { + double length; + if ( GEOSLength( geosGeom, &length ) ) + { + return ( length >= ( minSize * mapUnitsPerMM ) ); + } + } + else if ( featureType == QGis::Polygon ) + { + double area; + if ( GEOSArea( geosGeom, &area ) ) + { + return ( sqrt( area ) >= ( minSize * mapUnitsPerMM ) ); + } + } + return true; //should never be reached. Return true in this case to label such geometries anyway. } void LayerSettings::calculateLabelSize( QString text, double& labelX, double& labelY ) @@ -219,7 +267,7 @@ void LayerSettings::calculateLabelSize( QString text, double& labelX, double& la } -void LayerSettings::registerFeature( QgsFeature& f ) +void LayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext& context ) { QString labelText = f.attributeMap()[fieldIndex].toString(); double labelX, labelY; // will receive label size @@ -229,6 +277,11 @@ void LayerSettings::registerFeature( QgsFeature& f ) if ( ct != NULL ) // reproject the geometry if necessary geom->transform( *ct ); + if ( !checkMinimumSizeMM( context, geom, minFeatureSize ) ) + { + return; + } + MyLabel* lbl = new MyLabel( f.id(), labelText, GEOSGeom_clone( geom->asGeos() ) ); // record the created geometry - it will be deleted at the end. @@ -375,9 +428,10 @@ int PalLabeling::prepareLayer( QgsVectorLayer* layer, int& attrIndex, QgsRenderC } -void PalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f ) +void PalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context ) { - mActiveLayers[layer].registerFeature( f ); + LayerSettings& lyr = mActiveLayers[layer]; + lyr.registerFeature( f, context ); } diff --git a/src/plugins/labeling/pallabeling.h b/src/plugins/labeling/pallabeling.h index bf86d74ecf4..c88bf476dde 100644 --- a/src/plugins/labeling/pallabeling.h +++ b/src/plugins/labeling/pallabeling.h @@ -66,12 +66,13 @@ class LayerSettings QColor bufferColor; bool labelPerPart; // whether to label every feature's part or only the biggest one bool mergeLines; + double minFeatureSize; // minimum feature size to be labelled (in mm) // called from register feature hook void calculateLabelSize( QString text, double& labelX, double& labelY ); // implementation of register feature hook - void registerFeature( QgsFeature& f ); + void registerFeature( QgsFeature& f, const QgsRenderContext& context ); void readFromLayer( QgsVectorLayer* layer ); void writeToLayer( QgsVectorLayer* layer ); @@ -85,6 +86,11 @@ class LayerSettings const QgsCoordinateTransform* ct; QgsPoint ptZero, ptOne; QList geometries; + + private: + /**Checks if a feature is larger than a minimum size (in mm) + @return true if above size, false if below*/ + bool checkMinimumSizeMM( const QgsRenderContext& ct, QgsGeometry* geom, double minSize ) const; }; class LabelCandidate @@ -128,7 +134,7 @@ class PalLabeling : public QgsLabelingEngineInterface //! hook called when drawing layer before issuing select() virtual int prepareLayer( QgsVectorLayer* layer, int& attrIndex, QgsRenderContext& ctx ); //! hook called when drawing for every feature in a layer - virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat ); + virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() ); //! called when the map is drawn and labels should be placed virtual void drawLabeling( QgsRenderContext& context ); //! called when we're done with rendering @@ -145,6 +151,7 @@ class PalLabeling : public QgsLabelingEngineInterface void initPal(); + protected: // temporary hashtable of layer settings, being filled during labeling, cleared once labeling's done QHash mActiveLayers;