More labeling engine refactoring

- QgsPalLabeling now internally uses new engine
- label/diagram providers can hook into rendering loop to avoid extra feature loops
- map rendering uses the new engine instead of QgsPalLabeling

This code has been funded by Tuscany Region (Italy) - SITA (CIG: 63526840AE) and commissioned to Gis3W s.a.s.
This commit is contained in:
Martin Dobias 2015-09-18 20:24:43 +08:00
parent 8100495df6
commit d0fcc9557f
16 changed files with 511 additions and 1265 deletions

View File

@ -47,9 +47,14 @@ class QgsLabelingEngineInterface
//! called when starting rendering of a layer //! called when starting rendering of a layer
virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0; virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0;
//! returns PAL layer settings for a registered layer //! returns PAL layer settings for a registered layer
virtual QgsPalLayerSettings& layer( const QString& layerName ) = 0; //! @deprecated since 2.12 - if direct access to QgsPalLayerSettings is necessary, use QgsPalLayerSettings::fromLayer()
virtual QgsPalLayerSettings& layer( const QString& layerName ) = 0 /Deprecated/;
//! adds a diagram layer to the labeling engine //! adds a diagram layer to the labeling engine
virtual int addDiagramLayer( QgsVectorLayer* layer, const QgsDiagramLayerSettings* s ); //! @note added in QGIS 2.12
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/;
//! called for every feature //! called for every feature
virtual void registerFeature( const QString& layerID, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext(), QString dxfLayer = QString::null ) = 0; virtual void registerFeature( const QString& layerID, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext(), QString dxfLayer = QString::null ) = 0;
//! called for every diagram feature //! called for every diagram feature

View File

@ -699,7 +699,8 @@ class QgsPalLabeling : QgsLabelingEngineInterface
bool isShowingCandidates() const; bool isShowingCandidates() const;
void setShowingCandidates( bool showing ); void setShowingCandidates( bool showing );
const QList<QgsLabelCandidate>& candidates(); //! @deprecated since 2.12
const QList<QgsLabelCandidate>& candidates() /Deprecated/;
bool isShowingShadowRectangles() const; bool isShowingShadowRectangles() const;
void setShowingShadowRectangles( bool showing ); void setShowingShadowRectangles( bool showing );

View File

@ -17,6 +17,7 @@
#include "qgslogger.h" #include "qgslogger.h"
#include "qgspalgeometry.h" #include "qgspalgeometry.h"
#include "qgsproject.h"
#include "feature.h" #include "feature.h"
#include "labelposition.h" #include "labelposition.h"
@ -33,9 +34,8 @@ static bool _palIsCancelled( void* ctx )
} }
QgsLabelingEngineV2::QgsLabelingEngineV2( const QgsMapSettings& mapSettings ) QgsLabelingEngineV2::QgsLabelingEngineV2()
: mMapSettings( mapSettings ) : mFlags( RenderOutlineLabels | UsePartialCandidates )
, mFlags( RenderOutlineLabels | UsePartialCandidates )
, mSearchMethod( QgsPalLabeling::Chain ) , mSearchMethod( QgsPalLabeling::Chain )
, mCandPoint( 8 ) , mCandPoint( 8 )
, mCandLine( 8 ) , mCandLine( 8 )
@ -57,6 +57,15 @@ void QgsLabelingEngineV2::addProvider( QgsAbstractLabelProvider* provider )
mProviders << provider; mProviders << provider;
} }
void QgsLabelingEngineV2::removeProvider( QgsAbstractLabelProvider* provider )
{
int idx = mProviders.indexOf( provider );
if ( idx >= 0 )
{
delete mProviders.takeAt( idx );
}
}
void QgsLabelingEngineV2::run( QgsRenderContext& context ) void QgsLabelingEngineV2::run( QgsRenderContext& context )
{ {
pal::Pal p; pal::Pal p;
@ -146,7 +155,7 @@ void QgsLabelingEngineV2::run( QgsRenderContext& context )
l->setUpsidedownLabels( upsdnlabels ); l->setUpsidedownLabels( upsdnlabels );
QList<QgsLabelFeature*> features = provider->labelFeatures( mMapSettings, context ); QList<QgsLabelFeature*> features = provider->labelFeatures( context );
foreach ( QgsLabelFeature* feature, features ) foreach ( QgsLabelFeature* feature, features )
{ {
@ -286,6 +295,40 @@ QgsLabelingResults* QgsLabelingEngineV2::takeResults()
return res; return res;
} }
void QgsLabelingEngineV2::readSettingsFromProject()
{
bool saved = false;
QgsProject* prj = QgsProject::instance();
mSearchMethod = ( QgsPalLabeling::Search )( prj->readNumEntry( "PAL", "/SearchMethod", ( int ) QgsPalLabeling::Chain, &saved ) );
mCandPoint = prj->readNumEntry( "PAL", "/CandidatesPoint", 8, &saved );
mCandLine = prj->readNumEntry( "PAL", "/CandidatesLine", 8, &saved );
mCandPolygon = prj->readNumEntry( "PAL", "/CandidatesPolygon", 8, &saved );
mFlags = 0;
if ( prj->readBoolEntry( "PAL", "/ShowingCandidates", false, &saved ) ) mFlags |= DrawCandidates;
if ( prj->readBoolEntry( "PAL", "/DrawRectOnly", false, &saved ) ) mFlags |= DrawLabelRectOnly;
if ( prj->readBoolEntry( "PAL", "/ShowingShadowRects", false, &saved ) ) mFlags |= DrawShadowRects;
if ( prj->readBoolEntry( "PAL", "/ShowingAllLabels", false, &saved ) ) mFlags |= UseAllLabels;
if ( prj->readBoolEntry( "PAL", "/ShowingPartialsLabels", true, &saved ) ) mFlags |= UsePartialCandidates;
if ( prj->readBoolEntry( "PAL", "/DrawOutlineLabels", true, &saved ) ) mFlags |= RenderOutlineLabels;
}
void QgsLabelingEngineV2::writeSettingsToProject()
{
QgsProject::instance()->writeEntry( "PAL", "/SearchMethod", ( int )mSearchMethod );
QgsProject::instance()->writeEntry( "PAL", "/CandidatesPoint", mCandPoint );
QgsProject::instance()->writeEntry( "PAL", "/CandidatesLine", mCandLine );
QgsProject::instance()->writeEntry( "PAL", "/CandidatesPolygon", mCandPolygon );
QgsProject::instance()->writeEntry( "PAL", "/ShowingCandidates", mFlags.testFlag( DrawCandidates ) );
QgsProject::instance()->writeEntry( "PAL", "/DrawRectOnly", mFlags.testFlag( DrawLabelRectOnly ) );
QgsProject::instance()->writeEntry( "PAL", "/ShowingShadowRects", mFlags.testFlag( DrawShadowRects ) );
QgsProject::instance()->writeEntry( "PAL", "/ShowingAllLabels", mFlags.testFlag( UseAllLabels ) );
QgsProject::instance()->writeEntry( "PAL", "/ShowingPartialsLabels", mFlags.testFlag( UsePartialCandidates ) );
QgsProject::instance()->writeEntry( "PAL", "/DrawOutlineLabels", mFlags.testFlag( RenderOutlineLabels ) );
}
QgsAbstractLabelProvider* QgsLabelingEngineV2::providerById( const QString& id ) QgsAbstractLabelProvider* QgsLabelingEngineV2::providerById( const QString& id )
{ {
Q_FOREACH ( QgsAbstractLabelProvider* provider, mProviders ) Q_FOREACH ( QgsAbstractLabelProvider* provider, mProviders )

View File

@ -164,7 +164,7 @@ class CORE_EXPORT QgsAbstractLabelProvider
virtual QString id() const = 0; virtual QString id() const = 0;
//! Return list of labels //! Return list of labels
virtual QList<QgsLabelFeature*> labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& context ) = 0; virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) = 0;
//! draw this label at the position determined by the labeling engine //! draw this label at the position determined by the labeling engine
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const = 0; virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const = 0;
@ -210,7 +210,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( QgsAbstractLabelProvider::Flags )
class CORE_EXPORT QgsLabelingEngineV2 class CORE_EXPORT QgsLabelingEngineV2
{ {
public: public:
QgsLabelingEngineV2( const QgsMapSettings& mapSettings ); QgsLabelingEngineV2();
~QgsLabelingEngineV2(); ~QgsLabelingEngineV2();
enum Flag enum Flag
@ -224,9 +224,18 @@ class CORE_EXPORT QgsLabelingEngineV2
}; };
Q_DECLARE_FLAGS( Flags, Flag ) Q_DECLARE_FLAGS( Flags, Flag )
void setMapSettings( const QgsMapSettings& mapSettings ) { mMapSettings = mapSettings; }
const QgsMapSettings& mapSettings() const { return mMapSettings; }
//! Add provider of label features. Takes ownership of the provider //! Add provider of label features. Takes ownership of the provider
void addProvider( QgsAbstractLabelProvider* provider ); void addProvider( QgsAbstractLabelProvider* provider );
//! Remove provider if the provider's initialization failed. Provider instance is deleted.
void removeProvider( QgsAbstractLabelProvider* provider );
//! Lookup provider by its ID
QgsAbstractLabelProvider* providerById( const QString& id );
//! compute the labeling with given map settings and providers //! compute the labeling with given map settings and providers
void run( QgsRenderContext& context ); void run( QgsRenderContext& context );
@ -238,6 +247,8 @@ class CORE_EXPORT QgsLabelingEngineV2
void setFlags( Flags flags ) { mFlags = flags; } void setFlags( Flags flags ) { mFlags = flags; }
Flags flags() const { return mFlags; } Flags flags() const { return mFlags; }
bool testFlag( Flag f ) const { return mFlags.testFlag( f ); }
void setFlag( Flag f, bool enabled ) { if ( enabled ) mFlags |= f; else mFlags &= ~f; }
void numCandidatePositions( int& candPoint, int& candLine, int& candPolygon ) { candPoint = mCandPoint; candLine = mCandLine; candPolygon = mCandPolygon; } void numCandidatePositions( int& candPoint, int& candLine, int& candPolygon ) { candPoint = mCandPoint; candLine = mCandLine; candPolygon = mCandPolygon; }
void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ) { mCandPoint = candPoint; mCandLine = candLine; mCandPolygon = candPolygon; } void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ) { mCandPoint = candPoint; mCandLine = candLine; mCandPolygon = candPolygon; }
@ -245,8 +256,8 @@ class CORE_EXPORT QgsLabelingEngineV2
void setSearchMethod( QgsPalLabeling::Search s ) { mSearchMethod = s; } void setSearchMethod( QgsPalLabeling::Search s ) { mSearchMethod = s; }
QgsPalLabeling::Search searchMethod() const { return mSearchMethod; } QgsPalLabeling::Search searchMethod() const { return mSearchMethod; }
protected: void readSettingsFromProject();
QgsAbstractLabelProvider* providerById( const QString& id ); void writeSettingsToProject();
protected: protected:
QgsMapSettings mMapSettings; QgsMapSettings mMapSettings;

View File

@ -84,9 +84,15 @@ class CORE_EXPORT QgsLabelingEngineInterface
//! called when starting rendering of a layer //! called when starting rendering of a layer
virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0; virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0;
//! returns PAL layer settings for a registered layer //! returns PAL layer settings for a registered layer
virtual QgsPalLayerSettings& layer( const QString& layerName ) = 0; //! @deprecated since 2.12 - if direct access to QgsPalLayerSettings is necessary, use QgsPalLayerSettings::fromLayer()
Q_DECL_DEPRECATED virtual QgsPalLayerSettings& layer( const QString& layerName ) = 0;
//! adds a diagram layer to the labeling engine //! adds a diagram layer to the labeling engine
virtual int addDiagramLayer( QgsVectorLayer* layer, const QgsDiagramLayerSettings* s ) //! @note added in QGIS 2.12
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_UNUSED( layer ); Q_UNUSED( s ); return 0; } { Q_UNUSED( layer ); Q_UNUSED( s ); return 0; }
//! called for every feature //! called for every feature
virtual void registerFeature( const QString& layerID, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext(), QString dxfLayer = QString::null ) = 0; virtual void registerFeature( const QString& layerID, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext(), QString dxfLayer = QString::null ) = 0;

View File

@ -85,7 +85,9 @@ void QgsMapRendererCustomPainterJob::start()
if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) ) if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) )
{ {
#ifdef LABELING_V2 #ifdef LABELING_V2
mLabelingEngineV2 = new QgsLabelingEngineV2( mSettings ); mLabelingEngineV2 = new QgsLabelingEngineV2();
mLabelingEngineV2->readSettingsFromProject();
mLabelingEngineV2->setMapSettings( mSettings );
#else #else
mLabelingEngine = new QgsPalLabeling; mLabelingEngine = new QgsPalLabeling;
mLabelingEngine->loadEngineSettings(); mLabelingEngine->loadEngineSettings();

View File

@ -64,7 +64,9 @@ void QgsMapRendererParallelJob::start()
if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) ) if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) )
{ {
#ifdef LABELING_V2 #ifdef LABELING_V2
mLabelingEngineV2 = new QgsLabelingEngineV2( mSettings ); mLabelingEngineV2 = new QgsLabelingEngineV2();
mLabelingEngineV2->readSettingsFromProject();
mLabelingEngineV2->setMapSettings( mSettings );
#else #else
mLabelingEngine = new QgsPalLabeling; mLabelingEngine = new QgsPalLabeling;
mLabelingEngine->loadEngineSettings(); mLabelingEngine->loadEngineSettings();

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,9 @@ class QgsCoordinateTransform;
class QgsLabelSearchTree; class QgsLabelSearchTree;
class QgsMapSettings; class QgsMapSettings;
class QgsLabelFeature; class QgsLabelFeature;
class QgsLabelingEngineV2;
class QgsVectorLayerLabelProvider;
class QgsVectorLayerDiagramProvider;
class CORE_EXPORT QgsPalLayerSettings class CORE_EXPORT QgsPalLayerSettings
{ {
@ -781,7 +784,8 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
QgsPalLabeling(); QgsPalLabeling();
~QgsPalLabeling(); ~QgsPalLabeling();
QgsPalLayerSettings& layer( const QString& layerName ) override; //! @deprecated since 2.12 - if direct access to QgsPalLayerSettings is necessary, use QgsPalLayerSettings::fromLayer()
Q_DECL_DEPRECATED QgsPalLayerSettings& layer( const QString& layerName ) override;
void numCandidatePositions( int& candPoint, int& candLine, int& candPolygon ); void numCandidatePositions( int& candPoint, int& candLine, int& candPolygon );
void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ); void setNumCandidatePositions( int candPoint, int candLine, int candPolygon );
@ -791,29 +795,30 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
void setSearchMethod( Search s ); void setSearchMethod( Search s );
Search searchMethod() const; Search searchMethod() const;
bool isShowingCandidates() const { return mShowingCandidates; } bool isShowingCandidates() const;
void setShowingCandidates( bool showing ) { mShowingCandidates = showing; } void setShowingCandidates( bool showing );
const QList<QgsLabelCandidate>& candidates() { return mCandidates; } //! @deprecated since 2.12
Q_DECL_DEPRECATED const QList<QgsLabelCandidate>& candidates() { return mCandidates; }
bool isShowingShadowRectangles() const { return mShowingShadowRects; } bool isShowingShadowRectangles() const;
void setShowingShadowRectangles( bool showing ) { mShowingShadowRects = showing; } void setShowingShadowRectangles( bool showing );
bool isShowingAllLabels() const { return mShowingAllLabels; } bool isShowingAllLabels() const;
void setShowingAllLabels( bool showing ) { mShowingAllLabels = showing; } void setShowingAllLabels( bool showing );
bool isShowingPartialsLabels() const { return mShowingPartialsLabels; } bool isShowingPartialsLabels() const;
void setShowingPartialsLabels( bool showing ) { mShowingPartialsLabels = showing; } void setShowingPartialsLabels( bool showing );
//! @note added in 2.4 //! @note added in 2.4
bool isDrawingOutlineLabels() const { return mDrawOutlineLabels; } bool isDrawingOutlineLabels() const;
void setDrawingOutlineLabels( bool outline ) { mDrawOutlineLabels = outline; } void setDrawingOutlineLabels( bool outline );
/** Returns whether the engine will only draw the outline rectangles of labels, /** Returns whether the engine will only draw the outline rectangles of labels,
* not the label contents themselves. Used for debugging and testing purposes. * not the label contents themselves. Used for debugging and testing purposes.
* @see setDrawLabelRectOnly * @see setDrawLabelRectOnly
* @note added in QGIS 2.12 * @note added in QGIS 2.12
*/ */
bool drawLabelRectOnly() const { return mDrawLabelRectOnly; } bool drawLabelRectOnly() const;
/** Sets whether the engine should only draw the outline rectangles of labels, /** Sets whether the engine should only draw the outline rectangles of labels,
* not the label contents themselves. Used for debugging and testing purposes. * not the label contents themselves. Used for debugging and testing purposes.
@ -821,7 +826,7 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
* @see drawLabelRectOnly * @see drawLabelRectOnly
* @note added in QGIS 2.12 * @note added in QGIS 2.12
*/ */
void setDrawLabelRectOnly( bool drawRect ) { mDrawLabelRectOnly = drawRect; } void setDrawLabelRectOnly( bool drawRect );
// implemented methods from labeling engine interface // implemented methods from labeling engine interface
@ -845,7 +850,11 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
//! hook called when drawing layer before issuing select() //! hook called when drawing layer before issuing select()
virtual int prepareLayer( QgsVectorLayer* layer, QStringList &attrNames, QgsRenderContext& ctx ) override; virtual int prepareLayer( QgsVectorLayer* layer, QStringList &attrNames, QgsRenderContext& ctx ) override;
//! adds a diagram layer to the labeling engine //! adds a diagram layer to the labeling engine
virtual int addDiagramLayer( QgsVectorLayer* layer, const QgsDiagramLayerSettings *s ) override; //! @note added in QGIS 2.12
virtual int prepareDiagramLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) override;
//! 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 ) override;
/** Register a feature for labelling. /** Register a feature for labelling.
* @param layerID string identifying layer associated with label * @param layerID string identifying layer associated with label
@ -976,31 +985,18 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
*/ */
static bool checkMinimumSizeMM( const QgsRenderContext &context, const QgsGeometry *geom, double minSize ); static bool checkMinimumSizeMM( const QgsRenderContext &context, const QgsGeometry *geom, double minSize );
// hashtable of layer settings, being filled during labeling (key = layer ID) //! hashtable of label providers, being filled during labeling (key = layer ID)
QHash<QString, QgsPalLayerSettings> mActiveLayers; QHash<QString, QgsVectorLayerLabelProvider*> mLabelProviders;
// hashtable of active diagram layers (key = layer ID) //! hashtable of diagram providers (key = layer ID)
QHash<QString, QgsDiagramLayerSettings> mActiveDiagramLayers; QHash<QString, QgsVectorLayerDiagramProvider*> mDiagramProviders;
QgsPalLayerSettings mInvalidLayerSettings; QgsPalLayerSettings mInvalidLayerSettings;
const QgsMapSettings* mMapSettings; //! New labeling engine to interface with PAL
int mCandPoint, mCandLine, mCandPolygon; QgsLabelingEngineV2* mEngine;
Search mSearch;
pal::Pal* mPal;
// list of candidates from last labeling // list of candidates from last labeling
QList<QgsLabelCandidate> mCandidates; QList<QgsLabelCandidate> mCandidates;
//! Whether to only draw the label rect and not the actual label text (used for unit tests)
bool mDrawLabelRectOnly;
bool mShowingCandidates;
bool mShowingAllLabels; // whether to avoid collisions or not
bool mShowingShadowRects; // whether to show debugging rectangles for drop shadows
bool mShowingPartialsLabels; // whether to avoid partials labels or not
bool mDrawOutlineLabels; // whether to draw labels as text or outlines
QgsLabelingResults* mResults;
friend class QgsPalLayerSettings; friend class QgsPalLayerSettings;
}; };
Q_NOWARN_DEPRECATED_POP Q_NOWARN_DEPRECATED_POP

View File

@ -45,14 +45,14 @@ QgsVectorLayerDiagramProvider::QgsVectorLayerDiagramProvider(
} }
QgsVectorLayerDiagramProvider::QgsVectorLayerDiagramProvider( QgsVectorLayer* layer ) QgsVectorLayerDiagramProvider::QgsVectorLayerDiagramProvider( QgsVectorLayer* layer, bool ownFeatureLoop )
: mSettings( *layer->diagramLayerSettings() ) : mSettings( *layer->diagramLayerSettings() )
, mDiagRenderer( layer->diagramRenderer()->clone() ) , mDiagRenderer( layer->diagramRenderer()->clone() )
, mLayerId( layer->id() ) , mLayerId( layer->id() )
, mFields( layer->fields() ) , mFields( layer->fields() )
, mLayerCrs( layer->crs() ) , mLayerCrs( layer->crs() )
, mSource( new QgsVectorLayerFeatureSource( layer ) ) , mSource( ownFeatureLoop ? new QgsVectorLayerFeatureSource( layer ) : 0 )
, mOwnsSource( true ) , mOwnsSource( ownFeatureLoop )
{ {
init(); init();
} }
@ -81,67 +81,18 @@ QString QgsVectorLayerDiagramProvider::id() const
return mLayerId + "d"; return mLayerId + "d";
} }
QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& context ) QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsRenderContext& context )
{ {
if ( !mSource )
QgsDiagramLayerSettings& s2 = mSettings; {
// we have created the provider with "own feature loop" == false
s2.ct = 0; // so it is assumed that prepare() has been already called followed by registerFeature() calls
if ( mapSettings.hasCrsTransformEnabled() ) return mFeatures;
s2.ct = new QgsCoordinateTransform( mLayerCrs, mapSettings.destinationCrs() ); }
s2.xform = &mapSettings.mapToPixel();
s2.fields = mFields;
s2.renderer = mDiagRenderer;
const QgsDiagramRendererV2* diagRenderer = s2.renderer;
QStringList attributeNames; QStringList attributeNames;
if ( !prepare( context, attributeNames ) )
//add attributes needed by the diagram renderer return QList<QgsLabelFeature*>();
QList<QString> att = diagRenderer->diagramAttributes();
QList<QString>::const_iterator attIt = att.constBegin();
for ( ; attIt != att.constEnd(); ++attIt )
{
QgsExpression* expression = diagRenderer->diagram()->getExpression( *attIt, context.expressionContext() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
if ( !attributeNames.contains( *columnsIterator ) )
attributeNames << *columnsIterator;
}
}
const QgsLinearlyInterpolatedDiagramRenderer* linearlyInterpolatedDiagramRenderer = dynamic_cast<const QgsLinearlyInterpolatedDiagramRenderer*>( diagRenderer );
if ( linearlyInterpolatedDiagramRenderer != NULL )
{
if ( linearlyInterpolatedDiagramRenderer->classificationAttributeIsExpression() )
{
QgsExpression* expression = diagRenderer->diagram()->getExpression( linearlyInterpolatedDiagramRenderer->classificationAttributeExpression(), context.expressionContext() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
if ( !attributeNames.contains( *columnsIterator ) )
attributeNames << *columnsIterator;
}
}
else
{
QString name = mFields.at( linearlyInterpolatedDiagramRenderer->classificationAttribute() ).name();
if ( !attributeNames.contains( name ) )
attributeNames << name;
}
}
//and the ones needed for data defined diagram positions
if ( mSettings.xPosColumn != -1 )
attributeNames << mFields.at( mSettings.xPosColumn ).name();
if ( mSettings.yPosColumn != -1 )
attributeNames << mFields.at( mSettings.yPosColumn ).name();
QgsRectangle layerExtent = context.extent(); QgsRectangle layerExtent = context.extent();
if ( mSettings.ct ) if ( mSettings.ct )
@ -152,19 +103,17 @@ QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsM
request.setSubsetOfAttributes( attributeNames, mFields ); request.setSubsetOfAttributes( attributeNames, mFields );
QgsFeatureIterator fit = mSource->getFeatures( request ); QgsFeatureIterator fit = mSource->getFeatures( request );
QList<QgsLabelFeature*> features;
QgsFeature fet; QgsFeature fet;
while ( fit.nextFeature( fet ) ) while ( fit.nextFeature( fet ) )
{ {
QgsLabelFeature* label = registerDiagram( fet, mapSettings, context ); registerFeature( fet, context );
if ( label )
features << label;
} }
return features; return mFeatures;
} }
void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const
{ {
#if 1 // XXX strk #if 1 // XXX strk
@ -210,8 +159,88 @@ void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext& context, pal::L
} }
QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& feat, const QgsMapSettings& mapSettings, const QgsRenderContext& context ) bool QgsVectorLayerDiagramProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
{ {
QgsDiagramLayerSettings& s2 = mSettings;
const QgsMapSettings& mapSettings = mEngine->mapSettings();
s2.ct = 0;
if ( mapSettings.hasCrsTransformEnabled() )
{
if ( context.coordinateTransform() )
// this is context for layer rendering - use its CT as it includes correct datum transform
s2.ct = context.coordinateTransform()->clone();
else
// otherwise fall back to creating our own CT - this one may not have the correct datum transform!
s2.ct = new QgsCoordinateTransform( mLayerCrs, mapSettings.destinationCrs() );
}
s2.xform = &mapSettings.mapToPixel();
s2.fields = mFields;
s2.renderer = mDiagRenderer;
const QgsDiagramRendererV2* diagRenderer = s2.renderer;
//add attributes needed by the diagram renderer
QList<QString> att = diagRenderer->diagramAttributes();
QList<QString>::const_iterator attIt = att.constBegin();
for ( ; attIt != att.constEnd(); ++attIt )
{
QgsExpression* expression = diagRenderer->diagram()->getExpression( *attIt, context.expressionContext() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
if ( !attributeNames.contains( *columnsIterator ) )
attributeNames << *columnsIterator;
}
}
const QgsLinearlyInterpolatedDiagramRenderer* linearlyInterpolatedDiagramRenderer = dynamic_cast<const QgsLinearlyInterpolatedDiagramRenderer*>( diagRenderer );
if ( linearlyInterpolatedDiagramRenderer != NULL )
{
if ( linearlyInterpolatedDiagramRenderer->classificationAttributeIsExpression() )
{
QgsExpression* expression = diagRenderer->diagram()->getExpression( linearlyInterpolatedDiagramRenderer->classificationAttributeExpression(), context.expressionContext() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
if ( !attributeNames.contains( *columnsIterator ) )
attributeNames << *columnsIterator;
}
}
else
{
QString name = mFields.at( linearlyInterpolatedDiagramRenderer->classificationAttribute() ).name();
if ( !attributeNames.contains( name ) )
attributeNames << name;
}
}
//and the ones needed for data defined diagram positions
if ( mSettings.xPosColumn != -1 )
attributeNames << mFields.at( mSettings.xPosColumn ).name();
if ( mSettings.yPosColumn != -1 )
attributeNames << mFields.at( mSettings.yPosColumn ).name();
return true;
}
void QgsVectorLayerDiagramProvider::registerFeature( QgsFeature& feature, const QgsRenderContext& context )
{
QgsLabelFeature* label = registerDiagram( feature, context );
if ( label )
mFeatures << label;
}
QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& feat, const QgsRenderContext& context )
{
const QgsMapSettings& mapSettings = mEngine->mapSettings();
QgsDiagramRendererV2* dr = mSettings.renderer; QgsDiagramRendererV2* dr = mSettings.renderer;
if ( dr ) if ( dr )

View File

@ -33,7 +33,7 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
public: public:
//! Convenience constructor to initialize the provider from given vector layer //! Convenience constructor to initialize the provider from given vector layer
explicit QgsVectorLayerDiagramProvider( QgsVectorLayer* layer ); explicit QgsVectorLayerDiagramProvider( QgsVectorLayer* layer, bool ownFeatureLoop = true );
QgsVectorLayerDiagramProvider( const QgsDiagramLayerSettings* diagSettings, QgsVectorLayerDiagramProvider( const QgsDiagramLayerSettings* diagSettings,
const QgsDiagramRendererV2* diagRenderer, const QgsDiagramRendererV2* diagRenderer,
@ -47,13 +47,19 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
virtual QString id() const override; virtual QString id() const override;
virtual QList<QgsLabelFeature*> labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& context ) override; virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) override;
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override; virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
// new virtual methods
virtual bool prepare( const QgsRenderContext& context, QStringList& attributeNames );
virtual void registerFeature( QgsFeature& feature, const QgsRenderContext& context );
protected: protected:
void init(); void init();
QgsLabelFeature* registerDiagram( QgsFeature& feat, const QgsMapSettings& mapSettings, const QgsRenderContext& context ); QgsLabelFeature* registerDiagram( QgsFeature& feat, const QgsRenderContext& context );
protected: protected:
@ -66,6 +72,7 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
QgsAbstractFeatureSource* mSource; QgsAbstractFeatureSource* mSource;
bool mOwnsSource; bool mOwnsSource;
QList<QgsLabelFeature*> mFeatures;
}; };
#endif // QGSVECTORLAYERDIAGRAMPROVIDER_H #endif // QGSVECTORLAYERDIAGRAMPROVIDER_H

View File

@ -45,7 +45,7 @@ static void _fixQPictureDPI( QPainter* p )
typedef QgsPalLayerSettings QgsVectorLayerLabelSettings; typedef QgsPalLayerSettings QgsVectorLayerLabelSettings;
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer ) QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop )
{ {
if ( layer->customProperty( "labeling" ).toString() != QString( "pal" ) || !layer->labelsEnabled() ) if ( layer->customProperty( "labeling" ).toString() != QString( "pal" ) || !layer->labelsEnabled() )
return; return;
@ -54,7 +54,16 @@ QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer
mLayerId = layer->id(); mLayerId = layer->id();
mFields = layer->fields(); mFields = layer->fields();
mCrs = layer->crs(); mCrs = layer->crs();
if ( withFeatureLoop )
{
mSource = new QgsVectorLayerFeatureSource( layer ); mSource = new QgsVectorLayerFeatureSource( layer );
mOwnsSource = true;
}
else
{
mSource = 0;
mOwnsSource = false;
}
init(); init();
} }
@ -97,7 +106,19 @@ void QgsVectorLayerLabelProvider::init()
QgsVectorLayerLabelProvider::~QgsVectorLayerLabelProvider() QgsVectorLayerLabelProvider::~QgsVectorLayerLabelProvider()
{ {
// delete all QgsDataDefined objects (which also deletes their QgsExpression object)
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::iterator it = mSettings.dataDefinedProperties.begin();
for ( ; it != mSettings.dataDefinedProperties.constEnd(); ++it )
{
delete( it.value() );
it.value() = 0;
}
mSettings.dataDefinedProperties.clear();
qDeleteAll( mSettings.geometries ); qDeleteAll( mSettings.geometries );
if ( mOwnsSource )
delete mSource;
} }
QString QgsVectorLayerLabelProvider::id() const QString QgsVectorLayerLabelProvider::id() const
@ -105,10 +126,10 @@ QString QgsVectorLayerLabelProvider::id() const
return mLayerId; return mLayerId;
} }
bool QgsVectorLayerLabelProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& ctx )
{ {
QgsVectorLayerLabelSettings& lyr = mSettings; QgsVectorLayerLabelSettings& lyr = mSettings;
const QgsMapSettings& mapSettings = mEngine->mapSettings();
QgsDebugMsgLevel( "PREPARE LAYER " + mLayerId, 4 ); QgsDebugMsgLevel( "PREPARE LAYER " + mLayerId, 4 );
@ -116,7 +137,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
{ {
if ( lyr.fieldName.isEmpty() ) if ( lyr.fieldName.isEmpty() )
{ {
return QList<QgsLabelFeature*>(); return false;
} }
if ( lyr.isExpression ) if ( lyr.isExpression )
@ -125,7 +146,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
if ( exp.hasEvalError() ) if ( exp.hasEvalError() )
{ {
QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 ); QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
return QList<QgsLabelFeature*>(); return false;
} }
} }
else else
@ -133,13 +154,11 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
// If we aren't an expression, we check to see if we can find the column. // If we aren't an expression, we check to see if we can find the column.
if ( mFields.fieldNameIndex( lyr.fieldName ) == -1 ) if ( mFields.fieldNameIndex( lyr.fieldName ) == -1 )
{ {
return QList<QgsLabelFeature*>(); return false;
} }
} }
} }
QStringList attrNames;
lyr.mCurFields = mFields; lyr.mCurFields = mFields;
if ( lyr.drawLabels ) if ( lyr.drawLabels )
@ -149,7 +168,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
{ {
// prepare expression for use in QgsPalLayerSettings::registerFeature() // prepare expression for use in QgsPalLayerSettings::registerFeature()
QgsExpression* exp = lyr.getLabelExpression(); QgsExpression* exp = lyr.getLabelExpression();
exp->prepare( &ctx.expressionContext() ); exp->prepare( &context.expressionContext() );
if ( exp->hasEvalError() ) if ( exp->hasEvalError() )
{ {
QgsDebugMsgLevel( "Prepare error:" + exp->evalErrorString(), 4 ); QgsDebugMsgLevel( "Prepare error:" + exp->evalErrorString(), 4 );
@ -157,12 +176,12 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
Q_FOREACH ( const QString& name, exp->referencedColumns() ) Q_FOREACH ( const QString& name, exp->referencedColumns() )
{ {
QgsDebugMsgLevel( "REFERENCED COLUMN = " + name, 4 ); QgsDebugMsgLevel( "REFERENCED COLUMN = " + name, 4 );
attrNames.append( name ); attributeNames.append( name );
} }
} }
else else
{ {
attrNames.append( lyr.fieldName ); attributeNames.append( lyr.fieldName );
} }
// add field indices of data defined expression or field // add field indices of data defined expression or field
@ -179,26 +198,29 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
// store parameters for data defined expressions // store parameters for data defined expressions
QMap<QString, QVariant> exprParams; QMap<QString, QVariant> exprParams;
exprParams.insert( "scale", ctx.rendererScale() ); exprParams.insert( "scale", context.rendererScale() );
dd->setExpressionParams( exprParams ); dd->setExpressionParams( exprParams );
// this will return columns for expressions or field name, depending upon what is set to be used // this will return columns for expressions or field name, depending upon what is set to be used
QStringList cols = dd->referencedColumns( ctx.expressionContext() ); // <-- prepares any expressions, too QStringList cols = dd->referencedColumns( context.expressionContext() ); // <-- prepares any expressions, too
//QgsDebugMsgLevel( QString( "Data defined referenced columns:" ) + cols.join( "," ), 4 ); //QgsDebugMsgLevel( QString( "Data defined referenced columns:" ) + cols.join( "," ), 4 );
Q_FOREACH ( const QString& name, cols ) Q_FOREACH ( const QString& name, cols )
{ {
attrNames.append( name ); attributeNames.append( name );
} }
} }
} }
// NOW INITIALIZE QgsPalLayerSettings // NOW INITIALIZE QgsPalLayerSettings
// TODO: ideally these (non-configuration) members should get out of QgsPalLayerSettings to here
// (together with registerFeature() & related methods) and QgsPalLayerSettings just stores config
//raster and vector scale factors //raster and vector scale factors
lyr.vectorScaleFactor = ctx.scaleFactor(); lyr.vectorScaleFactor = context.scaleFactor();
lyr.rasterCompressFactor = ctx.rasterScaleFactor(); lyr.rasterCompressFactor = context.rasterScaleFactor();
// save the pal layer to our layer context (with some additional info) // save the pal layer to our layer context (with some additional info)
lyr.fieldIndex = mFields.fieldNameIndex( lyr.fieldName ); lyr.fieldIndex = mFields.fieldNameIndex( lyr.fieldName );
@ -206,7 +228,14 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
lyr.xform = &mapSettings.mapToPixel(); lyr.xform = &mapSettings.mapToPixel();
lyr.ct = 0; lyr.ct = 0;
if ( mapSettings.hasCrsTransformEnabled() ) if ( mapSettings.hasCrsTransformEnabled() )
{
if ( context.coordinateTransform() )
// this is context for layer rendering - use its CT as it includes correct datum transform
lyr.ct = context.coordinateTransform()->clone();
else
// otherwise fall back to creating our own CT - this one may not have the correct datum transform!
lyr.ct = new QgsCoordinateTransform( mCrs, mapSettings.destinationCrs() ); lyr.ct = new QgsCoordinateTransform( mCrs, mapSettings.destinationCrs() );
}
lyr.ptZero = lyr.xform->toMapCoordinates( 0, 0 ); lyr.ptZero = lyr.xform->toMapCoordinates( 0, 0 );
lyr.ptOne = lyr.xform->toMapCoordinates( 1, 0 ); lyr.ptOne = lyr.xform->toMapCoordinates( 1, 0 );
@ -220,30 +249,53 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
lyr.mFeatsSendingToPal = 0; lyr.mFeatsSendingToPal = 0;
return true;
}
QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsRenderContext& ctx )
{
if ( !mSource )
{
// we have created the provider with "own feature loop" == false
// so it is assumed that prepare() has been already called followed by registerFeature() calls
return mLabels;
}
QStringList attrNames;
if ( !prepare( ctx, attrNames ) )
return QList<QgsLabelFeature*>();
QgsRectangle layerExtent = ctx.extent(); QgsRectangle layerExtent = ctx.extent();
if ( lyr.ct ) if ( mSettings.ct )
layerExtent = lyr.ct->transformBoundingBox( ctx.extent(), QgsCoordinateTransform::ReverseTransform ); layerExtent = mSettings.ct->transformBoundingBox( ctx.extent(), QgsCoordinateTransform::ReverseTransform );
QgsFeatureRequest request; QgsFeatureRequest request;
request.setFilterRect( layerExtent ); request.setFilterRect( layerExtent );
request.setSubsetOfAttributes( attrNames, mFields ); request.setSubsetOfAttributes( attrNames, mFields );
QgsFeatureIterator fit = mSource->getFeatures( request ); QgsFeatureIterator fit = mSource->getFeatures( request );
QList<QgsLabelFeature*> labels;
QgsFeature fet; QgsFeature fet;
while ( fit.nextFeature( fet ) ) while ( fit.nextFeature( fet ) )
{ {
QgsLabelFeature* label = 0; registerFeature( fet, ctx );
lyr.registerFeature( fet, ctx, QString(), &label );
if ( label )
labels << label;
} }
return labels; return mLabels;
} }
void QgsVectorLayerLabelProvider::registerFeature( QgsFeature& feature, const QgsRenderContext& context )
{
QgsLabelFeature* label = 0;
mSettings.registerFeature( feature, context, QString(), &label );
if ( label )
mLabels << label;
}
void QgsVectorLayerLabelProvider::drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const void QgsVectorLayerLabelProvider::drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const
{ {
if ( !mSettings.drawLabels ) if ( !mSettings.drawLabels )
@ -303,7 +355,7 @@ void QgsVectorLayerLabelProvider::drawLabel( QgsRenderContext& context, pal::Lab
// update tmpLyr with any data defined drop shadow values // update tmpLyr with any data defined drop shadow values
QgsPalLabeling::dataDefinedDropShadow( tmpLyr, ddValues ); QgsPalLabeling::dataDefinedDropShadow( tmpLyr, ddValues );
tmpLyr.showingShadowRects = mEngine->flags().testFlag( QgsLabelingEngineV2::DrawShadowRects ); tmpLyr.showingShadowRects = mEngine->testFlag( QgsLabelingEngineV2::DrawShadowRects );
// Render the components of a label in reverse order // Render the components of a label in reverse order
// (backgrounds -> text) // (backgrounds -> text)
@ -367,7 +419,7 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition* label, Q
component.setOrigin( outPt ); component.setOrigin( outPt );
component.setRotation( label->getAlpha() ); component.setRotation( label->getAlpha() );
if ( mEngine->flags().testFlag( QgsLabelingEngineV2::DrawLabelRectOnly ) ) // TODO: this should get directly to labeling engine if ( mEngine->testFlag( QgsLabelingEngineV2::DrawLabelRectOnly ) ) // TODO: this should get directly to labeling engine
{ {
//debugging rect //debugging rect
if ( drawType != QgsPalLabeling::LabelText ) if ( drawType != QgsPalLabeling::LabelText )
@ -602,7 +654,7 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition* label, Q
// scale for any print output or image saving @ specific dpi // scale for any print output or image saving @ specific dpi
painter->scale( component.dpiRatio(), component.dpiRatio() ); painter->scale( component.dpiRatio(), component.dpiRatio() );
if ( mEngine->flags().testFlag( QgsLabelingEngineV2::RenderOutlineLabels ) ) if ( mEngine->testFlag( QgsLabelingEngineV2::RenderOutlineLabels ) )
{ {
// draw outlined text // draw outlined text
_fixQPictureDPI( painter ); _fixQPictureDPI( painter );

View File

@ -32,7 +32,7 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
public: public:
//! Convenience constructor to initialize the provider from given vector layer //! Convenience constructor to initialize the provider from given vector layer
explicit QgsVectorLayerLabelProvider( QgsVectorLayer* layer ); explicit QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop = true );
QgsVectorLayerLabelProvider( const QgsPalLayerSettings& settings, QgsVectorLayerLabelProvider( const QgsPalLayerSettings& settings,
const QString& layerId, const QString& layerId,
@ -45,10 +45,28 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
virtual QString id() const override; virtual QString id() const override;
virtual QList<QgsLabelFeature*> labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& context ) override; virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) override;
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override; virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
// new virtual methods
/**
* Prepare for registration of features. Must be called after provider has been added to engine (uses its map settings)
* @param context render context.
* @param attributeNames list of attribute names to which additional required attributes shall be added
* @return List of attributes necessary for labeling
*/
virtual bool prepare( const QgsRenderContext& context, QStringList& attributeNames );
/**
* Register a feature for labeling as one or more QgsLabelFeature objects stored into mLabels
*
* @param feature 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.
*/
virtual void registerFeature( QgsFeature& feature, const QgsRenderContext& context );
protected: protected:
void init(); void init();
@ -57,10 +75,13 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
protected: protected:
QgsPalLayerSettings mSettings; QgsPalLayerSettings mSettings;
QString mLayerId; QString mLayerId;
// these are needed only if using own renderer loop
QgsFields mFields; QgsFields mFields;
QgsCoordinateReferenceSystem mCrs; QgsCoordinateReferenceSystem mCrs;
QgsAbstractFeatureSource* mSource; QgsAbstractFeatureSource* mSource;
bool mOwnsSource; bool mOwnsSource;
QList<QgsLabelFeature*> mLabels;
}; };

View File

@ -47,6 +47,8 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender
, mCache( 0 ) , mCache( 0 )
, mLabeling( false ) , mLabeling( false )
, mDiagrams( false ) , mDiagrams( false )
, mLabelProvider( 0 )
, mDiagramProvider( 0 )
, mLayerTransparency( 0 ) , mLayerTransparency( 0 )
{ {
mSource = new QgsVectorLayerFeatureSource( layer ); mSource = new QgsVectorLayerFeatureSource( layer );
@ -312,6 +314,18 @@ void QgsVectorLayerRenderer::drawRendererV2( QgsFeatureIterator& fit )
mContext.labelingEngine()->registerDiagramFeature( mLayerID, fet, mContext ); mContext.labelingEngine()->registerDiagramFeature( mLayerID, fet, mContext );
} }
} }
// new labeling engine
if ( rendered && mContext.labelingEngineV2() )
{
if ( mLabelProvider )
{
mLabelProvider->registerFeature( fet, mContext );
}
if ( mDiagramProvider )
{
mDiagramProvider->registerFeature( fet, mContext );
}
}
} }
catch ( const QgsCsException &cse ) catch ( const QgsCsException &cse )
{ {
@ -469,9 +483,15 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
if ( QgsLabelingEngineV2* engine2 = mContext.labelingEngineV2() ) if ( QgsLabelingEngineV2* engine2 = mContext.labelingEngineV2() )
{ {
if ( layer->labelsEnabled() ) if ( layer->labelsEnabled() )
engine2->addProvider( new QgsVectorLayerLabelProvider( layer ) ); {
if ( layer->diagramsEnabled() ) mLabelProvider = new QgsVectorLayerLabelProvider( layer, false );
engine2->addProvider( new QgsVectorLayerDiagramProvider( layer ) ); engine2->addProvider( mLabelProvider );
if ( !mLabelProvider->prepare( mContext, attributeNames ) )
{
engine2->removeProvider( mLabelProvider );
mLabelProvider = 0; // deleted by engine
}
}
} }
return; return;
} }
@ -480,10 +500,9 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
{ {
mLabeling = true; mLabeling = true;
QgsPalLayerSettings& palyr = mContext.labelingEngine()->layer( mLayerID );
Q_UNUSED( palyr );
#if 0 // TODO: limit of labels, font not found #if 0 // TODO: limit of labels, font not found
QgsPalLayerSettings& palyr = mContext.labelingEngine()->layer( mLayerID );
// see if feature count limit is set for labeling // see if feature count limit is set for labeling
if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 ) if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 )
{ {
@ -514,58 +533,29 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
void QgsVectorLayerRenderer::prepareDiagrams( QgsVectorLayer* layer, QStringList& attributeNames ) void QgsVectorLayerRenderer::prepareDiagrams( QgsVectorLayer* layer, QStringList& attributeNames )
{ {
if ( !mContext.labelingEngine() ) if ( !mContext.labelingEngine() )
{
if ( QgsLabelingEngineV2* engine2 = mContext.labelingEngineV2() )
{
if ( layer->diagramsEnabled() )
{
mDiagramProvider = new QgsVectorLayerDiagramProvider( layer );
// need to be added before calling prepare() - uses map settings from engine
engine2->addProvider( mDiagramProvider );
if ( !mDiagramProvider->prepare( mContext, attributeNames ) )
{
engine2->removeProvider( mDiagramProvider );
mDiagramProvider = 0; // deleted by engine
}
}
}
return; return;
}
if ( !layer->diagramsEnabled() ) if ( !layer->diagramsEnabled() )
return; return;
mDiagrams = true; mDiagrams = true;
const QgsDiagramRendererV2* diagRenderer = layer->diagramRenderer(); mContext.labelingEngine()->prepareDiagramLayer( layer, attributeNames, mContext ); // will make internal copy of diagSettings + initialize it
const QgsDiagramLayerSettings* diagSettings = layer->diagramLayerSettings();
mContext.labelingEngine()->addDiagramLayer( layer, diagSettings ); // will make internal copy of diagSettings + initialize it
//add attributes needed by the diagram renderer
QList<QString> att = diagRenderer->diagramAttributes();
QList<QString>::const_iterator attIt = att.constBegin();
for ( ; attIt != att.constEnd(); ++attIt )
{
QgsExpression* expression = diagRenderer->diagram()->getExpression( *attIt, mContext.expressionContext() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
if ( !attributeNames.contains( *columnsIterator ) )
attributeNames << *columnsIterator;
}
}
const QgsLinearlyInterpolatedDiagramRenderer* linearlyInterpolatedDiagramRenderer = dynamic_cast<const QgsLinearlyInterpolatedDiagramRenderer*>( layer->diagramRenderer() );
if ( linearlyInterpolatedDiagramRenderer != NULL )
{
if ( linearlyInterpolatedDiagramRenderer->classificationAttributeIsExpression() )
{
QgsExpression* expression = diagRenderer->diagram()->getExpression( linearlyInterpolatedDiagramRenderer->classificationAttributeExpression(), mContext.expressionContext() );
QStringList columns = expression->referencedColumns();
QStringList::const_iterator columnsIterator = columns.constBegin();
for ( ; columnsIterator != columns.constEnd(); ++columnsIterator )
{
if ( !attributeNames.contains( *columnsIterator ) )
attributeNames << *columnsIterator;
}
}
else
{
QString name = mFields.at( linearlyInterpolatedDiagramRenderer->classificationAttribute() ).name();
if ( !attributeNames.contains( name ) )
attributeNames << name;
}
}
//and the ones needed for data defined diagram positions
if ( diagSettings->xPosColumn != -1 )
attributeNames << mFields.at( diagSettings->xPosColumn ).name();
if ( diagSettings->yPosColumn != -1 )
attributeNames << mFields.at( diagSettings->yPosColumn ).name();
} }

View File

@ -41,6 +41,8 @@ typedef QList<int> QgsAttributeList;
#include "qgsmaplayerrenderer.h" #include "qgsmaplayerrenderer.h"
class QgsVectorLayerLabelProvider;
class QgsVectorLayerDiagramProvider;
/** /**
* Implementation of threaded rendering for vector layers. * Implementation of threaded rendering for vector layers.
@ -102,9 +104,18 @@ class QgsVectorLayerRenderer : public QgsMapLayerRenderer
QStringList mAttrNames; QStringList mAttrNames;
//! used with old labeling engine (QgsPalLabeling): whether labeling is enabled
bool mLabeling; bool mLabeling;
//! used with new labeling engine (QgsPalLabeling): whether diagrams are enabled
bool mDiagrams; bool mDiagrams;
//! used with new labeling engine (QgsLabelingEngineV2): provider for labels.
//! may be null. no need to delete: if exists it is owned by labeling engine
QgsVectorLayerLabelProvider* mLabelProvider;
//! used with new labeling engine (QgsLabelingEngineV2): provider for diagrams.
//! may be null. no need to delete: if exists it is owned by labeling engine
QgsVectorLayerDiagramProvider* mDiagramProvider;
int mLayerTransparency; int mLayerTransparency;
QPainter::CompositionMode mFeatureBlendMode; QPainter::CompositionMode mFeatureBlendMode;

View File

@ -77,7 +77,8 @@ void TestQgsLabelingEngineV2::testBasic()
vl->setCustomProperty( "labeling/enabled", true ); vl->setCustomProperty( "labeling/enabled", true );
vl->setCustomProperty( "labeling/fieldName", "Class" ); vl->setCustomProperty( "labeling/fieldName", "Class" );
QgsLabelingEngineV2 engine( mapSettings ); QgsLabelingEngineV2 engine;
engine.setMapSettings( mapSettings );
engine.addProvider( new QgsVectorLayerLabelProvider( vl ) ); engine.addProvider( new QgsVectorLayerLabelProvider( vl ) );
//engine.setFlags( QgsLabelingEngineV2::RenderOutlineLabels | QgsLabelingEngineV2::DrawLabelRectOnly ); //engine.setFlags( QgsLabelingEngineV2::RenderOutlineLabels | QgsLabelingEngineV2::DrawLabelRectOnly );
engine.run( context ); engine.run( context );
@ -87,6 +88,12 @@ void TestQgsLabelingEngineV2::testBasic()
// TODO: replace with render checker // TODO: replace with render checker
img.save( "/tmp/tstlabels.png" ); img.save( "/tmp/tstlabels.png" );
// now let's test the variant when integrated into rendering loop
job.start();
job.waitForFinished();
QImage img2 = job.renderedImage();
img2.save( "/tmp/tstlabels2.png" );
vl->setCustomProperty( "labeling/enabled", false ); vl->setCustomProperty( "labeling/enabled", false );
} }
@ -112,7 +119,8 @@ void TestQgsLabelingEngineV2::testDiagrams()
vl->loadNamedStyle( QString( TEST_DATA_DIR ) + "/points_diagrams.qml", res ); vl->loadNamedStyle( QString( TEST_DATA_DIR ) + "/points_diagrams.qml", res );
Q_ASSERT( res ); Q_ASSERT( res );
QgsLabelingEngineV2 engine( mapSettings ); QgsLabelingEngineV2 engine;
engine.setMapSettings( mapSettings );
engine.addProvider( new QgsVectorLayerDiagramProvider( vl ) ); engine.addProvider( new QgsVectorLayerDiagramProvider( vl ) );
engine.run( context ); engine.run( context );
@ -120,6 +128,12 @@ void TestQgsLabelingEngineV2::testDiagrams()
// TODO: replace with render checker // TODO: replace with render checker
img.save( "/tmp/tstdiagrams.png" ); img.save( "/tmp/tstdiagrams.png" );
// now let's test the variant when integrated into rendering loop
job.start();
job.waitForFinished();
QImage img2 = job.renderedImage();
img2.save( "/tmp/tstdiagrams2.png" );
} }
QTEST_MAIN( TestQgsLabelingEngineV2 ) QTEST_MAIN( TestQgsLabelingEngineV2 )