dxf export: support rule based labeling (fixes #13757)

This commit is contained in:
Juergen E. Fischer 2016-04-11 12:07:17 +02:00
parent b7a4e20627
commit f19a35c34e
15 changed files with 268 additions and 170 deletions

View File

@ -35,7 +35,7 @@ class QgsLabelingEngineInterface
//! called when we're going to start with rendering
//! @deprecated since 2.4 - use override with QgsMapSettings
virtual void init( QgsMapRenderer* mp ) = 0 /Deprecated/;
virtual void init( QgsMapRenderer *mp ) = 0 /Deprecated/;
//! called when we're going to start with rendering
virtual void init( const QgsMapSettings& mapSettings ) = 0;
//! called to find out whether the layer is used for labeling
@ -48,17 +48,17 @@ class QgsLabelingEngineInterface
virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0;
//! returns PAL layer settings for a registered layer
//! @deprecated since 2.12 - if direct access to QgsPalLayerSettings is necessary, use QgsPalLayerSettings::fromLayer()
virtual QgsPalLayerSettings& layer( const QString& layerName ) = 0 /Deprecated/;
virtual QgsPalLayerSettings &layer( const QString &layerName ) = 0 /Deprecated/;
//! adds a diagram layer to the labeling engine
//! @note added in QGIS 2.12
virtual int prepareDiagramLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx );
virtual int prepareDiagramLayer( QgsVectorLayer *layer, QStringList &attrNames, QgsRenderContext &ctx );
//! adds a diagram layer to the labeling engine
//! @deprecated since 2.12 - use prepareDiagramLayer()
virtual int addDiagramLayer( QgsVectorLayer* layer, const QgsDiagramLayerSettings* s ) /Deprecated/;
virtual int addDiagramLayer( QgsVectorLayer *layer, const QgsDiagramLayerSettings *s ) /Deprecated/;
//! called for every feature
virtual void registerFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context, const QString& dxfLayer = QString::null ) = 0;
virtual void registerFeature( const QString &layerID, QgsFeature &feat, QgsRenderContext &context ) = 0;
//! called for every diagram feature
virtual void registerDiagramFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context );
virtual void registerDiagramFeature( const QString &layerID, QgsFeature &feat, QgsRenderContext &context );
//! called when the map is drawn and labels should be placed
virtual void drawLabeling( QgsRenderContext& context ) = 0;
//! called when we're done with rendering
@ -268,7 +268,7 @@ class QgsMapRenderer : QObject
//! Accessor for render context
QgsRenderContext* rendererContext();
//! Labeling engine (NULL if there's no custom engine)
//! Labeling engine (nullptr if there's no custom engine)
QgsLabelingEngineInterface* labelingEngine();
//! Set labeling engine. Previous engine (if any) is deleted.

View File

@ -551,7 +551,6 @@ class QgsPalLayerSettings
* @param f feature to label
* @param context render context. The QgsExpressionContext contained within the render context
* must have already had the feature and fields sets prior to calling this method.
* @param dxfLayer dxfLayer name
* @param labelFeature if using QgsLabelingEngineV2, this will receive the label feature. Not available
* in Python bindings.
* @param obstacleGeometry optional obstacle geometry, if a different geometry to the feature's geometry
@ -560,7 +559,7 @@ class QgsPalLayerSettings
* the feature's original geometry will be used as an obstacle for labels. Not available
* in Python bindings.
*/
void registerFeature( QgsFeature& f, QgsRenderContext& context, const QString& dxfLayer );
void registerFeature( QgsFeature& f, QgsRenderContext& context );
void readFromLayer( QgsVectorLayer* layer );
void writeToLayer( QgsVectorLayer* layer );
@ -867,9 +866,8 @@ class QgsPalLabeling : QgsLabelingEngineInterface
* @param feat feature to label
* @param context render context. The QgsExpressionContext contained within the render context
* must have already had the feature and fields sets prior to calling this method.
* @param dxfLayer dxfLayer name
*/
virtual void registerFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context, const QString& dxfLayer = QString::null );
virtual void registerFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context );
virtual void registerDiagramFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context );
//! called when the map is drawn and labels should be placed

View File

@ -37,6 +37,11 @@
#include "qgsvectorlayer.h"
#include "qgsmaplayerregistry.h"
#include "qgsunittypes.h"
#include "qgstextlabelfeature.h"
#include "pal/feature.h"
#include "pal/pointset.h"
#include "pal/labelposition.h"
#include <QIODevice>
@ -942,12 +947,32 @@ void QgsDxfExport::writeEntities()
attributes << layerAttr;
}
QgsDxfLabelProvider* lp = new QgsDxfLabelProvider( vl, this );
engine.addProvider( lp );
if ( !lp->prepare( ctx, attributes ) )
const QgsAbstractVectorLayerLabeling *labeling = vl->labeling();
QgsDxfLabelProvider *lp = nullptr;
QgsDxfRuleBasedLabelProvider *rblp = nullptr;
if ( dynamic_cast<const QgsRuleBasedLabeling*>( labeling ) )
{
engine.removeProvider( lp );
lp = nullptr;
const QgsRuleBasedLabeling *rbl = dynamic_cast<const QgsRuleBasedLabeling*>( labeling );
rblp = new QgsDxfRuleBasedLabelProvider( *rbl, vl, this );
rblp->reinit( vl );
engine.addProvider( rblp );
if ( !rblp->prepare( ctx, attributes ) )
{
engine.removeProvider( rblp );
rblp = nullptr;
}
}
else
{
lp = new QgsDxfLabelProvider( vl, this, nullptr );
engine.addProvider( lp );
if ( !lp->prepare( ctx, attributes ) )
{
engine.removeProvider( lp );
lp = nullptr;
}
}
if ( mSymbologyExport == QgsDxfExport::SymbolLayerSymbology &&
@ -1012,6 +1037,10 @@ void QgsDxfExport::writeEntities()
{
lp->registerDxfFeature( fet, ctx, lName );
}
else if ( rblp )
{
rblp->registerDxfFeature( fet, ctx, lName );
}
}
}
@ -4169,3 +4198,112 @@ QString QgsDxfExport::layerName( QgsVectorLayer *vl ) const
Q_ASSERT( vl );
return mLayerTitleAsName && !vl->title().isEmpty() ? vl->title() : vl->name();
}
void QgsDxfExport::drawLabel( QString layerId, QgsRenderContext& context, pal::LabelPosition* label, const QgsPalLayerSettings &settings )
{
Q_UNUSED( context );
QgsTextLabelFeature* lf = dynamic_cast<QgsTextLabelFeature*>( label->getFeaturePart()->feature() );
if ( !lf )
return;
//label text
QString txt = lf->text( label->getPartId() );
//angle
double angle = label->getAlpha() * 180 / M_PI;
QgsFeatureId fid = label->getFeaturePart()->featureId();
QString dxfLayer = mDxfLayerNames[layerId][fid];
//debug: show label rectangle
#if 0
QgsPolyline line;
for ( int i = 0; i < 4; ++i )
{
line.append( QgsPoint( label->getX( i ), label->getY( i ) ) );
}
writePolyline( line, dxfLayer, "CONTINUOUS", 1, 0.01, true );
#endif
QString wrapchr = settings.wrapChar.isEmpty() ? "\n" : settings.wrapChar;
//add the direction symbol if needed
if ( !txt.isEmpty() && settings.placement == QgsPalLayerSettings::Line && settings.addDirectionSymbol )
{
bool prependSymb = false;
QString symb = settings.rightDirectionSymbol;
if ( label->getReversed() )
{
prependSymb = true;
symb = settings.leftDirectionSymbol;
}
if ( settings.reverseDirectionSymbol )
{
if ( symb == settings.rightDirectionSymbol )
{
prependSymb = true;
symb = settings.leftDirectionSymbol;
}
else
{
prependSymb = false;
symb = settings.rightDirectionSymbol;
}
}
if ( settings.placeDirectionSymbol == QgsPalLayerSettings::SymbolAbove )
{
prependSymb = true;
symb = symb + wrapchr;
}
else if ( settings.placeDirectionSymbol == QgsPalLayerSettings::SymbolBelow )
{
prependSymb = false;
symb = wrapchr + symb;
}
if ( prependSymb )
{
txt.prepend( symb );
}
else
{
txt.append( symb );
}
}
txt = txt.replace( wrapchr, "\\P" );
if ( settings.textFont.underline() )
{
txt.prepend( "\\L" ).append( "\\l" );
}
if ( settings.textFont.overline() )
{
txt.prepend( "\\O" ).append( "\\o" );
}
if ( settings.textFont.strikeOut() )
{
txt.prepend( "\\K" ).append( "\\k" );
}
txt.prepend( QString( "\\f%1|i%2|b%3;\\H%4;\\W0.75;" )
.arg( settings.textFont.family() )
.arg( settings.textFont.italic() ? 1 : 0 )
.arg( settings.textFont.bold() ? 1 : 0 )
.arg( label->getHeight() / ( 1 + txt.count( "\\P" ) ) * 0.75 ) );
writeMText( dxfLayer, txt, QgsPoint( label->getX(), label->getY() ), label->getWidth() * 1.1, angle, settings.textColor );
}
void QgsDxfExport::registerDxfLayer( QString layerId, QgsFeatureId fid, QString layerName )
{
if ( !mDxfLayerNames.contains( layerId ) )
mDxfLayerNames[ layerId ] = QMap<QgsFeatureId, QString>();
mDxfLayerNames[layerId][fid] = layerName;
}

View File

@ -20,6 +20,7 @@
#include "qgsgeometry.h"
#include "qgssymbolv2.h"
#include <QColor>
#include <QList>
#include <QTextStream>
@ -28,6 +29,12 @@ class QgsMapLayer;
class QgsPoint;
class QgsSymbolLayerV2;
class QIODevice;
class QgsPalLayerSettings;
namespace pal
{
class LabelPosition;
};
class CORE_EXPORT QgsDxfExport
{
@ -283,6 +290,9 @@ class CORE_EXPORT QgsDxfExport
//! return list of available DXF encodings
static QStringList encodings();
void drawLabel( QString layerId, QgsRenderContext& context, pal::LabelPosition* label, const QgsPalLayerSettings &settings );
void registerDxfLayer( QString layerId, QgsFeatureId fid, QString layer );
private:
QList< QPair<QgsVectorLayer*, int> > mLayers;
@ -350,6 +360,9 @@ class CORE_EXPORT QgsDxfExport
QHash<QString, int> mBlockHandles;
QString mBlockHandle;
//! DXF layer name for each label feature
QMap< QString, QMap<QgsFeatureId, QString> > mDxfLayerNames;
};
#endif // QGSDXFEXPORT_H

View File

@ -17,131 +17,57 @@
#include "qgsdxfpallabeling.h"
#include "qgsdxfexport.h"
#include "qgstextlabelfeature.h"
#include "qgspallabeling.h"
#include "qgsmapsettings.h"
#include "pal/feature.h"
#include "pal/pointset.h"
#include "pal/labelposition.h"
#include "qgslogger.h"
QgsDxfLabelProvider::QgsDxfLabelProvider( QgsVectorLayer* layer , QgsDxfExport* dxf )
: QgsVectorLayerLabelProvider( layer, false )
QgsDxfLabelProvider::QgsDxfLabelProvider( QgsVectorLayer* layer, QgsDxfExport* dxf, const QgsPalLayerSettings *settings )
: QgsVectorLayerLabelProvider( layer, false, settings )
, mDxfExport( dxf )
{
}
void QgsDxfLabelProvider::drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const
{
Q_UNUSED( context );
//debug: print label infos
if ( mDxfExport )
{
QgsTextLabelFeature* lf = dynamic_cast<QgsTextLabelFeature*>( label->getFeaturePart()->feature() );
if ( !lf )
return;
const QgsPalLayerSettings& tmpLyr = mSettings;
//label text
QString txt = lf->text( label->getPartId() );
//angle
double angle = label->getAlpha() * 180 / M_PI;
QgsFeatureId fid = label->getFeaturePart()->featureId();
QString dxfLayer = mDxfLayerNames[fid];
//debug: show label rectangle
#if 0
QgsPolyline line;
for ( int i = 0; i < 4; ++i )
{
line.append( QgsPoint( label->getX( i ), label->getY( i ) ) );
}
mDxfExport->writePolyline( line, dxfLayer, "CONTINUOUS", 1, 0.01, true );
#endif
QString wrapchr = tmpLyr.wrapChar.isEmpty() ? "\n" : tmpLyr.wrapChar;
//add the direction symbol if needed
if ( !txt.isEmpty() && tmpLyr.placement == QgsPalLayerSettings::Line && tmpLyr.addDirectionSymbol )
{
bool prependSymb = false;
QString symb = tmpLyr.rightDirectionSymbol;
if ( label->getReversed() )
{
prependSymb = true;
symb = tmpLyr.leftDirectionSymbol;
}
if ( tmpLyr.reverseDirectionSymbol )
{
if ( symb == tmpLyr.rightDirectionSymbol )
{
prependSymb = true;
symb = tmpLyr.leftDirectionSymbol;
}
else
{
prependSymb = false;
symb = tmpLyr.rightDirectionSymbol;
}
}
if ( tmpLyr.placeDirectionSymbol == QgsPalLayerSettings::SymbolAbove )
{
prependSymb = true;
symb = symb + wrapchr;
}
else if ( tmpLyr.placeDirectionSymbol == QgsPalLayerSettings::SymbolBelow )
{
prependSymb = false;
symb = wrapchr + symb;
}
if ( prependSymb )
{
txt.prepend( symb );
}
else
{
txt.append( symb );
}
}
txt = txt.replace( wrapchr, "\\P" );
if ( tmpLyr.textFont.underline() )
{
txt.prepend( "\\L" ).append( "\\l" );
}
if ( tmpLyr.textFont.overline() )
{
txt.prepend( "\\O" ).append( "\\o" );
}
if ( tmpLyr.textFont.strikeOut() )
{
txt.prepend( "\\K" ).append( "\\k" );
}
txt.prepend( QString( "\\f%1|i%2|b%3;\\H%4;\\W0.75;" )
.arg( tmpLyr.textFont.family() )
.arg( tmpLyr.textFont.italic() ? 1 : 0 )
.arg( tmpLyr.textFont.bold() ? 1 : 0 )
.arg( label->getHeight() / ( 1 + txt.count( "\\P" ) ) * 0.75 ) );
mDxfExport->writeMText( dxfLayer, txt, QgsPoint( label->getX(), label->getY() ), label->getWidth() * 1.1, angle, tmpLyr.textColor );
}
Q_ASSERT( mDxfExport );
mDxfExport->drawLabel( layerId(), context, label, mSettings );
}
void QgsDxfLabelProvider::registerDxfFeature( QgsFeature& feature, QgsRenderContext& context, const QString& dxfLayerName )
{
registerFeature( feature, context );
mDxfLayerNames[feature.id()] = dxfLayerName;
mDxfExport->registerDxfLayer( layerId(), feature.id(), dxfLayerName );
}
QgsDxfRuleBasedLabelProvider::QgsDxfRuleBasedLabelProvider( const QgsRuleBasedLabeling &rules, QgsVectorLayer* layer, QgsDxfExport* dxf )
: QgsRuleBasedLabelProvider( rules, layer, false )
, mDxfExport( dxf )
{
}
void QgsDxfRuleBasedLabelProvider::reinit( QgsVectorLayer* layer )
{
QgsDebugMsg( "Entering." );
mRules.rootRule()->createSubProviders( layer, mSubProviders, this );
}
QgsVectorLayerLabelProvider *QgsDxfRuleBasedLabelProvider::createProvider( QgsVectorLayer *layer, bool withFeatureLoop, const QgsPalLayerSettings *settings )
{
QgsDebugMsg( "Entering." );
Q_UNUSED( withFeatureLoop );
return new QgsDxfLabelProvider( layer, mDxfExport, settings );
}
void QgsDxfRuleBasedLabelProvider::drawLabel( QgsRenderContext &context, pal::LabelPosition *label ) const
{
QgsDebugMsg( "Entering." );
Q_ASSERT( mDxfExport );
mDxfExport->drawLabel( layerId(), context, label, mSettings );
}
void QgsDxfRuleBasedLabelProvider::registerDxfFeature( QgsFeature &feature, QgsRenderContext &context, const QString &dxfLayerName )
{
registerFeature( feature, context );
mDxfExport->registerDxfLayer( layerId(), feature.id(), dxfLayerName );
}

View File

@ -21,8 +21,11 @@
#include "qgsmaprenderer.h"
#include "qgsrendercontext.h"
#include "qgsvectorlayerlabelprovider.h"
#include "qgsrulebasedlabeling.h"
class QgsDxfExport;
class QgsPalLayerSettings;
class QgsRuleBasedLabeling;
/** Implements a derived label provider internally used for DXF export
@ -34,10 +37,10 @@ class QgsDxfLabelProvider : public QgsVectorLayerLabelProvider
{
public:
//! construct the provider
explicit QgsDxfLabelProvider( QgsVectorLayer* layer, QgsDxfExport* dxf );
explicit QgsDxfLabelProvider( QgsVectorLayer* layer, QgsDxfExport* dxf, const QgsPalLayerSettings *settings );
//! re-implementation that writes to DXF file instead of drawing with QPainter
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
//! registration method that keeps track of DXF layer names of individual features
void registerDxfFeature( QgsFeature& feature, QgsRenderContext &context, const QString& dxfLayerName );
@ -45,8 +48,29 @@ class QgsDxfLabelProvider : public QgsVectorLayerLabelProvider
protected:
//! pointer to parent DXF export where this instance is used
QgsDxfExport* mDxfExport;
//! DXF layer name for each label feature
QMap<QgsFeatureId, QString> mDxfLayerNames;
};
class QgsDxfRuleBasedLabelProvider : public QgsRuleBasedLabelProvider
{
public:
//! construct the provider
explicit QgsDxfRuleBasedLabelProvider( const QgsRuleBasedLabeling &rules, QgsVectorLayer* layer, QgsDxfExport* dxf );
void reinit( QgsVectorLayer* layer );
//! re-implementation that writes to DXF file instead of drawing with QPainter
void drawLabel( QgsRenderContext &context, pal::LabelPosition *label ) const override;
//! registration method that keeps track of DXF layer names of individual features
void registerDxfFeature( QgsFeature& feature, QgsRenderContext &context, const QString& dxfLayerName );
virtual QgsVectorLayerLabelProvider *createProvider( QgsVectorLayer *layer, bool withFeatureLoop, const QgsPalLayerSettings *settings ) override;
protected:
//! pointer to parent DXF export where this instance is used
QgsDxfExport* mDxfExport;
};
#endif // QGSDXFPALLABELING_H

View File

@ -13,7 +13,6 @@
* *
***************************************************************************/
#include "qgslabelfeature.h"
#include "feature.h"

View File

@ -46,9 +46,10 @@ class QgsDiagramLayerSettings;
class CORE_EXPORT QgsLabelPosition
{
public:
QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, const QString& labeltext, const QFont& labelfont, bool upside_down, bool diagram = false, bool pinned = false ):
featureId( id ), rotation( r ), cornerPoints( corners ), labelRect( rect ), width( w ), height( h ), layerID( layer ), labelText( labeltext ), labelFont( labelfont ), upsideDown( upside_down ), isDiagram( diagram ), isPinned( pinned ) {}
QgsLabelPosition(): featureId( -1 ), rotation( 0 ), labelRect( QgsRectangle() ), width( 0 ), height( 0 ), layerID( "" ), labelText( "" ), labelFont( QFont() ), upsideDown( false ), isDiagram( false ), isPinned( false ) {}
QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, const QString& labeltext, const QFont& labelfont, bool upside_down, bool diagram = false, bool pinned = false )
: featureId( id ), rotation( r ), cornerPoints( corners ), labelRect( rect ), width( w ), height( h ), layerID( layer ), labelText( labeltext ), labelFont( labelfont ), upsideDown( upside_down ), isDiagram( diagram ), isPinned( pinned ) {}
QgsLabelPosition()
: featureId( -1 ), rotation( 0 ), labelRect( QgsRectangle() ), width( 0 ), height( 0 ), layerID( "" ), labelText( "" ), labelFont( QFont() ), upsideDown( false ), isDiagram( false ), isPinned( false ) {}
int featureId;
double rotation;
QVector< QgsPoint > cornerPoints;
@ -72,7 +73,7 @@ class CORE_EXPORT QgsLabelingEngineInterface
//! called when we're going to start with rendering
//! @deprecated since 2.4 - use override with QgsMapSettings
Q_DECL_DEPRECATED virtual void init( QgsMapRenderer* mp ) = 0;
Q_DECL_DEPRECATED virtual void init( QgsMapRenderer *mp ) = 0;
//! called when we're going to start with rendering
virtual void init( const QgsMapSettings& mapSettings ) = 0;
//! called to find out whether the layer is used for labeling
@ -85,19 +86,19 @@ class CORE_EXPORT QgsLabelingEngineInterface
virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0;
//! returns PAL layer settings for a registered layer
//! @deprecated since 2.12 - if direct access to QgsPalLayerSettings is necessary, use QgsPalLayerSettings::fromLayer()
Q_DECL_DEPRECATED virtual QgsPalLayerSettings& layer( const QString& layerName ) = 0;
Q_DECL_DEPRECATED virtual QgsPalLayerSettings &layer( const QString &layerName ) = 0;
//! adds a diagram layer to the labeling engine
//! @note added in QGIS 2.12
virtual int prepareDiagramLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx )
virtual int prepareDiagramLayer( QgsVectorLayer *layer, QStringList &attrNames, QgsRenderContext &ctx )
{ Q_UNUSED( layer ); Q_UNUSED( attrNames ); Q_UNUSED( ctx ); return 0; }
//! adds a diagram layer to the labeling engine
//! @deprecated since 2.12 - use prepareDiagramLayer()
Q_DECL_DEPRECATED virtual int addDiagramLayer( QgsVectorLayer* layer, const QgsDiagramLayerSettings* s )
Q_DECL_DEPRECATED virtual int addDiagramLayer( QgsVectorLayer *layer, const QgsDiagramLayerSettings *s )
{ Q_UNUSED( layer ); Q_UNUSED( s ); return 0; }
//! called for every feature
virtual void registerFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context, const QString& dxfLayer = QString::null ) = 0;
virtual void registerFeature( const QString &layerID, QgsFeature &feat, QgsRenderContext &context ) = 0;
//! called for every diagram feature
virtual void registerDiagramFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context )
virtual void registerDiagramFeature( const QString &layerID, QgsFeature &feat, QgsRenderContext &context )
{ Q_UNUSED( layerID ); Q_UNUSED( feat ); Q_UNUSED( context ); }
//! called when the map is drawn and labels should be placed
virtual void drawLabeling( QgsRenderContext& context ) = 0;

View File

@ -1939,13 +1939,11 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString t
#endif
}
void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &context, const QString& dxfLayer, QgsLabelFeature** labelFeature , QgsGeometry* obstacleGeometry )
void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &context, QgsLabelFeature** labelFeature , QgsGeometry* obstacleGeometry )
{
// either used in QgsPalLabeling (palLayer is set) or in QgsLabelingEngineV2 (labelFeature is set)
Q_ASSERT( labelFeature );
Q_UNUSED( dxfLayer ); // now handled in QgsDxfLabelProvider
QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
mCurFeat = &f;
@ -1960,7 +1958,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
{
if ( isObstacle )
{
registerObstacleFeature( f, context, QString(), labelFeature, obstacleGeometry );
registerObstacleFeature( f, context, labelFeature, obstacleGeometry );
}
return;
}
@ -2812,10 +2810,8 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
lf->setDataDefinedValues( dataDefinedValues );
}
void QgsPalLayerSettings::registerObstacleFeature( QgsFeature& f, QgsRenderContext &context, const QString& dxfLayer, QgsLabelFeature** obstacleFeature, QgsGeometry* obstacleGeometry )
void QgsPalLayerSettings::registerObstacleFeature( QgsFeature& f, QgsRenderContext &context, QgsLabelFeature** obstacleFeature, QgsGeometry* obstacleGeometry )
{
Q_UNUSED( dxfLayer ); // now handled in QgsDxfLabelProvider
mCurFeat = &f;
const QgsGeometry* geom = nullptr;
@ -3809,9 +3805,8 @@ int QgsPalLabeling::addDiagramLayer( QgsVectorLayer* layer, const QgsDiagramLaye
return 0;
}
void QgsPalLabeling::registerFeature( const QString& layerID, QgsFeature& f, QgsRenderContext &context, const QString& dxfLayer )
void QgsPalLabeling::registerFeature( const QString& layerID, QgsFeature& f, QgsRenderContext &context )
{
Q_UNUSED( dxfLayer ); // now handled by QgsDxfLabelProvider
if ( QgsVectorLayerLabelProvider* provider = mLabelProviders.value( layerID, nullptr ) )
provider->registerFeature( f, context );
}

View File

@ -533,7 +533,6 @@ class CORE_EXPORT QgsPalLayerSettings
* @param f feature to label
* @param context render context. The QgsExpressionContext contained within the render context
* must have already had the feature and fields sets prior to calling this method.
* @param dxfLayer dxfLayer name
* @param labelFeature if using QgsLabelingEngineV2, this will receive the label feature. Not available
* in Python bindings.
* @param obstacleGeometry optional obstacle geometry, if a different geometry to the feature's geometry
@ -542,7 +541,7 @@ class CORE_EXPORT QgsPalLayerSettings
* the feature's original geometry will be used as an obstacle for labels. Not available
* in Python bindings.
*/
void registerFeature( QgsFeature& f, QgsRenderContext& context, const QString& dxfLayer, QgsLabelFeature** labelFeature = nullptr, QgsGeometry* obstacleGeometry = nullptr );
void registerFeature( QgsFeature& f, QgsRenderContext& context, QgsLabelFeature** labelFeature = nullptr, QgsGeometry* obstacleGeometry = nullptr );
void readFromLayer( QgsVectorLayer* layer );
void writeToLayer( QgsVectorLayer* layer );
@ -712,7 +711,7 @@ class CORE_EXPORT QgsPalLayerSettings
/** Registers a feature as an obstacle only (no label rendered)
*/
void registerObstacleFeature( QgsFeature &f, QgsRenderContext &context, const QString& dxfLayer, QgsLabelFeature** obstacleFeature, QgsGeometry* obstacleGeometry = nullptr );
void registerObstacleFeature( QgsFeature &f, QgsRenderContext &context, QgsLabelFeature** obstacleFeature, QgsGeometry* obstacleGeometry = nullptr );
QMap<DataDefinedProperties, QVariant> dataDefinedValues;
QgsExpression* expression;
@ -949,9 +948,8 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
* @param feat feature to label
* @param context render context. The QgsExpressionContext contained within the render context
* must have already had the feature and fields sets prior to calling this method.
* @param dxfLayer dxfLayer name
*/
virtual void registerFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context, const QString& dxfLayer = QString::null ) override;
virtual void registerFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context ) override;
virtual void registerDiagramFeature( const QString& layerID, QgsFeature& feat, QgsRenderContext& context ) override;
//! called when the map is drawn and labels should be placed

View File

@ -15,12 +15,11 @@
#include "qgsrulebasedlabeling.h"
QgsRuleBasedLabelProvider::QgsRuleBasedLabelProvider( const QgsRuleBasedLabeling& rules, QgsVectorLayer* layer, bool withFeatureLoop )
: QgsVectorLayerLabelProvider( layer, withFeatureLoop )
, mRules( rules )
{
mRules.rootRule()->createSubProviders( layer, mSubProviders );
mRules.rootRule()->createSubProviders( layer, mSubProviders, this );
}
QgsRuleBasedLabelProvider::~QgsRuleBasedLabelProvider()
@ -28,6 +27,10 @@ QgsRuleBasedLabelProvider::~QgsRuleBasedLabelProvider()
// sub-providers owned by labeling engine
}
QgsVectorLayerLabelProvider *QgsRuleBasedLabelProvider::createProvider( QgsVectorLayer *layer, bool withFeatureLoop, const QgsPalLayerSettings *settings )
{
return new QgsVectorLayerLabelProvider( layer, withFeatureLoop, settings );
}
bool QgsRuleBasedLabelProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
{
@ -213,19 +216,20 @@ QDomElement QgsRuleBasedLabeling::Rule::save( QDomDocument& doc ) const
return ruleElem;
}
void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer* layer, QgsRuleBasedLabeling::RuleToProviderMap& subProviders )
void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer* layer, QgsRuleBasedLabeling::RuleToProviderMap& subProviders, QgsRuleBasedLabelProvider *provider )
{
if ( mSettings )
{
// add provider!
QgsVectorLayerLabelProvider* p = new QgsVectorLayerLabelProvider( layer, false, mSettings );
QgsVectorLayerLabelProvider *p = provider->createProvider( layer, false, mSettings );
delete subProviders.value( this, nullptr );
subProviders[this] = p;
}
// call recursively
Q_FOREACH ( Rule* rule, mChildren )
{
rule->createSubProviders( layer, subProviders );
rule->createSubProviders( layer, subProviders, provider );
}
}
@ -262,6 +266,8 @@ QgsRuleBasedLabeling::Rule::RegisterResult QgsRuleBasedLabeling::Rule::registerF
bool registered = false;
Q_ASSERT( !mSettings == subProviders.contains( this ) );
// do we have active subprovider for the rule?
if ( subProviders.contains( this ) && mIsActive )
{

View File

@ -19,6 +19,7 @@
#include <QMap>
#include "qgsvectorlayerlabeling.h"
#include "qgsvectorlayerlabelprovider.h"
class QDomDocument;
class QDomElement;
@ -28,6 +29,7 @@ class QgsFeature;
class QgsPalLayerSettings;
class QgsRenderContext;
class QgsGeometry;
class QgsRuleBasedLabelProvider;
/**
* @class QgsRuleBasedLabeling
@ -42,7 +44,6 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
typedef QList<Rule*> RuleList;
typedef QMap<Rule*, QgsVectorLayerLabelProvider*> RuleToProviderMap;
/**
* @class QgsRuleBasedLabeling::Rule
* @note not available in Python bindings
@ -214,7 +215,7 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
// evaluation
//! add providers
void createSubProviders( QgsVectorLayer* layer, RuleToProviderMap& subProviders );
void createSubProviders( QgsVectorLayer* layer, RuleToProviderMap& subProviders, QgsRuleBasedLabelProvider *provider );
//! call prepare() on sub-providers and populate attributeNames
void prepare( const QgsRenderContext& context, QStringList& attributeNames, RuleToProviderMap& subProviders );
@ -285,15 +286,13 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
virtual QString type() const override;
virtual QDomElement save( QDomDocument& doc ) const override;
virtual QgsVectorLayerLabelProvider* provider( QgsVectorLayer* layer ) const override;
virtual QgsVectorLayerLabelProvider *provider( QgsVectorLayer* layer ) const override;
protected:
Rule* mRootRule;
};
#include "qgsvectorlayerlabelprovider.h"
/**
* @class QgsRuleBasedLabelProvider
* @note not available in Python bindings
@ -312,6 +311,7 @@ class CORE_EXPORT QgsRuleBasedLabelProvider : public QgsVectorLayerLabelProvider
virtual void registerFeature( QgsFeature& feature, QgsRenderContext& context, QgsGeometry* obstacleGeometry = nullptr ) override;
// new methods
virtual QgsVectorLayerLabelProvider *createProvider( QgsVectorLayer *layer, bool withFeatureLoop, const QgsPalLayerSettings *settings );
virtual QList<QgsAbstractLabelProvider*> subProviders() override;

View File

@ -316,7 +316,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( QgsRenderCon
void QgsVectorLayerLabelProvider::registerFeature( QgsFeature& feature, QgsRenderContext& context, QgsGeometry* obstacleGeometry )
{
QgsLabelFeature* label = nullptr;
mSettings.registerFeature( feature, context, QString(), &label, obstacleGeometry );
mSettings.registerFeature( feature, context, &label, obstacleGeometry );
if ( label )
mLabels << label;
}

View File

@ -116,5 +116,4 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
QList<QgsLabelFeature*> mLabels;
};
#endif // QGSVECTORLAYERLABELPROVIDER_H

View File

@ -259,7 +259,7 @@ void TestQgsLabelingEngineV2::testRuleBased()
delete rl2;
/*
#if 0
QPainter p( &img );
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
context.setPainter( &p );
@ -267,7 +267,8 @@ void TestQgsLabelingEngineV2::testRuleBased()
QgsLabelingEngineV2 engine;
engine.setMapSettings( mapSettings );
engine.addProvider( new QgsRuleBasedLabelProvider( , vl ) );
engine.run( context );*/
engine.run( context );
#endif
}
void TestQgsLabelingEngineV2::zOrder()