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
virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0;
//! 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
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
virtual void registerFeature( const QString& layerID, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext(), QString dxfLayer = QString::null ) = 0;
//! called for every diagram feature

View File

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

View File

@ -17,6 +17,7 @@
#include "qgslogger.h"
#include "qgspalgeometry.h"
#include "qgsproject.h"
#include "feature.h"
#include "labelposition.h"
@ -33,9 +34,8 @@ static bool _palIsCancelled( void* ctx )
}
QgsLabelingEngineV2::QgsLabelingEngineV2( const QgsMapSettings& mapSettings )
: mMapSettings( mapSettings )
, mFlags( RenderOutlineLabels | UsePartialCandidates )
QgsLabelingEngineV2::QgsLabelingEngineV2()
: mFlags( RenderOutlineLabels | UsePartialCandidates )
, mSearchMethod( QgsPalLabeling::Chain )
, mCandPoint( 8 )
, mCandLine( 8 )
@ -57,6 +57,15 @@ void QgsLabelingEngineV2::addProvider( QgsAbstractLabelProvider* 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 )
{
pal::Pal p;
@ -146,7 +155,7 @@ void QgsLabelingEngineV2::run( QgsRenderContext& context )
l->setUpsidedownLabels( upsdnlabels );
QList<QgsLabelFeature*> features = provider->labelFeatures( mMapSettings, context );
QList<QgsLabelFeature*> features = provider->labelFeatures( context );
foreach ( QgsLabelFeature* feature, features )
{
@ -286,6 +295,40 @@ QgsLabelingResults* QgsLabelingEngineV2::takeResults()
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 )
{
Q_FOREACH ( QgsAbstractLabelProvider* provider, mProviders )

View File

@ -164,7 +164,7 @@ class CORE_EXPORT QgsAbstractLabelProvider
virtual QString id() const = 0;
//! 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
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
{
public:
QgsLabelingEngineV2( const QgsMapSettings& mapSettings );
QgsLabelingEngineV2();
~QgsLabelingEngineV2();
enum Flag
@ -224,9 +224,18 @@ class CORE_EXPORT QgsLabelingEngineV2
};
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
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
void run( QgsRenderContext& context );
@ -238,6 +247,8 @@ class CORE_EXPORT QgsLabelingEngineV2
void setFlags( Flags flags ) { mFlags = flags; }
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 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; }
QgsPalLabeling::Search searchMethod() const { return mSearchMethod; }
protected:
QgsAbstractLabelProvider* providerById( const QString& id );
void readSettingsFromProject();
void writeSettingsToProject();
protected:
QgsMapSettings mMapSettings;

View File

@ -84,9 +84,15 @@ class CORE_EXPORT QgsLabelingEngineInterface
//! called when starting rendering of a layer
virtual int prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx ) = 0;
//! 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
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; }
//! called for every feature
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 ) )
{
#ifdef LABELING_V2
mLabelingEngineV2 = new QgsLabelingEngineV2( mSettings );
mLabelingEngineV2 = new QgsLabelingEngineV2();
mLabelingEngineV2->readSettingsFromProject();
mLabelingEngineV2->setMapSettings( mSettings );
#else
mLabelingEngine = new QgsPalLabeling;
mLabelingEngine->loadEngineSettings();

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,9 @@ class QgsCoordinateTransform;
class QgsLabelSearchTree;
class QgsMapSettings;
class QgsLabelFeature;
class QgsLabelingEngineV2;
class QgsVectorLayerLabelProvider;
class QgsVectorLayerDiagramProvider;
class CORE_EXPORT QgsPalLayerSettings
{
@ -781,7 +784,8 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
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 setNumCandidatePositions( int candPoint, int candLine, int candPolygon );
@ -791,29 +795,30 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
void setSearchMethod( Search s );
Search searchMethod() const;
bool isShowingCandidates() const { return mShowingCandidates; }
void setShowingCandidates( bool showing ) { mShowingCandidates = showing; }
const QList<QgsLabelCandidate>& candidates() { return mCandidates; }
bool isShowingCandidates() const;
void setShowingCandidates( bool showing );
//! @deprecated since 2.12
Q_DECL_DEPRECATED const QList<QgsLabelCandidate>& candidates() { return mCandidates; }
bool isShowingShadowRectangles() const { return mShowingShadowRects; }
void setShowingShadowRectangles( bool showing ) { mShowingShadowRects = showing; }
bool isShowingShadowRectangles() const;
void setShowingShadowRectangles( bool showing );
bool isShowingAllLabels() const { return mShowingAllLabels; }
void setShowingAllLabels( bool showing ) { mShowingAllLabels = showing; }
bool isShowingAllLabels() const;
void setShowingAllLabels( bool showing );
bool isShowingPartialsLabels() const { return mShowingPartialsLabels; }
void setShowingPartialsLabels( bool showing ) { mShowingPartialsLabels = showing; }
bool isShowingPartialsLabels() const;
void setShowingPartialsLabels( bool showing );
//! @note added in 2.4
bool isDrawingOutlineLabels() const { return mDrawOutlineLabels; }
void setDrawingOutlineLabels( bool outline ) { mDrawOutlineLabels = outline; }
bool isDrawingOutlineLabels() const;
void setDrawingOutlineLabels( bool outline );
/** Returns whether the engine will only draw the outline rectangles of labels,
* not the label contents themselves. Used for debugging and testing purposes.
* @see setDrawLabelRectOnly
* @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,
* not the label contents themselves. Used for debugging and testing purposes.
@ -821,7 +826,7 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
* @see drawLabelRectOnly
* @note added in QGIS 2.12
*/
void setDrawLabelRectOnly( bool drawRect ) { mDrawLabelRectOnly = drawRect; }
void setDrawLabelRectOnly( bool drawRect );
// implemented methods from labeling engine interface
@ -845,7 +850,11 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
//! hook called when drawing layer before issuing select()
virtual int prepareLayer( QgsVectorLayer* layer, QStringList &attrNames, QgsRenderContext& ctx ) override;
//! 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.
* @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 );
// hashtable of layer settings, being filled during labeling (key = layer ID)
QHash<QString, QgsPalLayerSettings> mActiveLayers;
// hashtable of active diagram layers (key = layer ID)
QHash<QString, QgsDiagramLayerSettings> mActiveDiagramLayers;
//! hashtable of label providers, being filled during labeling (key = layer ID)
QHash<QString, QgsVectorLayerLabelProvider*> mLabelProviders;
//! hashtable of diagram providers (key = layer ID)
QHash<QString, QgsVectorLayerDiagramProvider*> mDiagramProviders;
QgsPalLayerSettings mInvalidLayerSettings;
const QgsMapSettings* mMapSettings;
int mCandPoint, mCandLine, mCandPolygon;
Search mSearch;
pal::Pal* mPal;
//! New labeling engine to interface with PAL
QgsLabelingEngineV2* mEngine;
// list of candidates from last labeling
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;
};
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() )
, mDiagRenderer( layer->diagramRenderer()->clone() )
, mLayerId( layer->id() )
, mFields( layer->fields() )
, mLayerCrs( layer->crs() )
, mSource( new QgsVectorLayerFeatureSource( layer ) )
, mOwnsSource( true )
, mSource( ownFeatureLoop ? new QgsVectorLayerFeatureSource( layer ) : 0 )
, mOwnsSource( ownFeatureLoop )
{
init();
}
@ -81,67 +81,18 @@ QString QgsVectorLayerDiagramProvider::id() const
return mLayerId + "d";
}
QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& context )
QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsRenderContext& context )
{
QgsDiagramLayerSettings& s2 = mSettings;
s2.ct = 0;
if ( mapSettings.hasCrsTransformEnabled() )
s2.ct = new QgsCoordinateTransform( mLayerCrs, mapSettings.destinationCrs() );
s2.xform = &mapSettings.mapToPixel();
s2.fields = mFields;
s2.renderer = mDiagRenderer;
const QgsDiagramRendererV2* diagRenderer = s2.renderer;
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 mFeatures;
}
QStringList attributeNames;
//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();
if ( !prepare( context, attributeNames ) )
return QList<QgsLabelFeature*>();
QgsRectangle layerExtent = context.extent();
if ( mSettings.ct )
@ -152,19 +103,17 @@ QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsM
request.setSubsetOfAttributes( attributeNames, mFields );
QgsFeatureIterator fit = mSource->getFeatures( request );
QList<QgsLabelFeature*> features;
QgsFeature fet;
while ( fit.nextFeature( fet ) )
{
QgsLabelFeature* label = registerDiagram( fet, mapSettings, context );
if ( label )
features << label;
registerFeature( fet, context );
}
return features;
return mFeatures;
}
void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const
{
#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;
if ( dr )

View File

@ -33,7 +33,7 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
public:
//! 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,
const QgsDiagramRendererV2* diagRenderer,
@ -47,13 +47,19 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
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;
// new virtual methods
virtual bool prepare( const QgsRenderContext& context, QStringList& attributeNames );
virtual void registerFeature( QgsFeature& feature, const QgsRenderContext& context );
protected:
void init();
QgsLabelFeature* registerDiagram( QgsFeature& feat, const QgsMapSettings& mapSettings, const QgsRenderContext& context );
QgsLabelFeature* registerDiagram( QgsFeature& feat, const QgsRenderContext& context );
protected:
@ -66,6 +72,7 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
QgsAbstractFeatureSource* mSource;
bool mOwnsSource;
QList<QgsLabelFeature*> mFeatures;
};
#endif // QGSVECTORLAYERDIAGRAMPROVIDER_H

View File

@ -45,7 +45,7 @@ static void _fixQPictureDPI( QPainter* p )
typedef QgsPalLayerSettings QgsVectorLayerLabelSettings;
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer )
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop )
{
if ( layer->customProperty( "labeling" ).toString() != QString( "pal" ) || !layer->labelsEnabled() )
return;
@ -54,7 +54,16 @@ QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer
mLayerId = layer->id();
mFields = layer->fields();
mCrs = layer->crs();
mSource = new QgsVectorLayerFeatureSource( layer );
if ( withFeatureLoop )
{
mSource = new QgsVectorLayerFeatureSource( layer );
mOwnsSource = true;
}
else
{
mSource = 0;
mOwnsSource = false;
}
init();
}
@ -97,7 +106,19 @@ void QgsVectorLayerLabelProvider::init()
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 );
if ( mOwnsSource )
delete mSource;
}
QString QgsVectorLayerLabelProvider::id() const
@ -105,10 +126,10 @@ QString QgsVectorLayerLabelProvider::id() const
return mLayerId;
}
QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMapSettings& mapSettings, const QgsRenderContext& ctx )
bool QgsVectorLayerLabelProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
{
QgsVectorLayerLabelSettings& lyr = mSettings;
const QgsMapSettings& mapSettings = mEngine->mapSettings();
QgsDebugMsgLevel( "PREPARE LAYER " + mLayerId, 4 );
@ -116,7 +137,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
{
if ( lyr.fieldName.isEmpty() )
{
return QList<QgsLabelFeature*>();
return false;
}
if ( lyr.isExpression )
@ -125,7 +146,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
if ( exp.hasEvalError() )
{
QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
return QList<QgsLabelFeature*>();
return false;
}
}
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 ( mFields.fieldNameIndex( lyr.fieldName ) == -1 )
{
return QList<QgsLabelFeature*>();
return false;
}
}
}
QStringList attrNames;
lyr.mCurFields = mFields;
if ( lyr.drawLabels )
@ -149,7 +168,7 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
{
// prepare expression for use in QgsPalLayerSettings::registerFeature()
QgsExpression* exp = lyr.getLabelExpression();
exp->prepare( &ctx.expressionContext() );
exp->prepare( &context.expressionContext() );
if ( exp->hasEvalError() )
{
QgsDebugMsgLevel( "Prepare error:" + exp->evalErrorString(), 4 );
@ -157,12 +176,12 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
Q_FOREACH ( const QString& name, exp->referencedColumns() )
{
QgsDebugMsgLevel( "REFERENCED COLUMN = " + name, 4 );
attrNames.append( name );
attributeNames.append( name );
}
}
else
{
attrNames.append( lyr.fieldName );
attributeNames.append( lyr.fieldName );
}
// 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
QMap<QString, QVariant> exprParams;
exprParams.insert( "scale", ctx.rendererScale() );
exprParams.insert( "scale", context.rendererScale() );
dd->setExpressionParams( exprParams );
// 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 );
Q_FOREACH ( const QString& name, cols )
{
attrNames.append( name );
attributeNames.append( name );
}
}
}
// 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
lyr.vectorScaleFactor = ctx.scaleFactor();
lyr.rasterCompressFactor = ctx.rasterScaleFactor();
lyr.vectorScaleFactor = context.scaleFactor();
lyr.rasterCompressFactor = context.rasterScaleFactor();
// save the pal layer to our layer context (with some additional info)
lyr.fieldIndex = mFields.fieldNameIndex( lyr.fieldName );
@ -206,7 +228,14 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
lyr.xform = &mapSettings.mapToPixel();
lyr.ct = 0;
if ( mapSettings.hasCrsTransformEnabled() )
lyr.ct = new QgsCoordinateTransform( mCrs, mapSettings.destinationCrs() );
{
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.ptZero = lyr.xform->toMapCoordinates( 0, 0 );
lyr.ptOne = lyr.xform->toMapCoordinates( 1, 0 );
@ -220,30 +249,53 @@ QList<QgsLabelFeature*> QgsVectorLayerLabelProvider::labelFeatures( const QgsMap
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();
if ( lyr.ct )
layerExtent = lyr.ct->transformBoundingBox( ctx.extent(), QgsCoordinateTransform::ReverseTransform );
if ( mSettings.ct )
layerExtent = mSettings.ct->transformBoundingBox( ctx.extent(), QgsCoordinateTransform::ReverseTransform );
QgsFeatureRequest request;
request.setFilterRect( layerExtent );
request.setSubsetOfAttributes( attrNames, mFields );
QgsFeatureIterator fit = mSource->getFeatures( request );
QList<QgsLabelFeature*> labels;
QgsFeature fet;
while ( fit.nextFeature( fet ) )
{
QgsLabelFeature* label = 0;
lyr.registerFeature( fet, ctx, QString(), &label );
if ( label )
labels << label;
registerFeature( fet, ctx );
}
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
{
if ( !mSettings.drawLabels )
@ -303,7 +355,7 @@ void QgsVectorLayerLabelProvider::drawLabel( QgsRenderContext& context, pal::Lab
// update tmpLyr with any data defined drop shadow values
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
// (backgrounds -> text)
@ -367,7 +419,7 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition* label, Q
component.setOrigin( outPt );
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
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
painter->scale( component.dpiRatio(), component.dpiRatio() );
if ( mEngine->flags().testFlag( QgsLabelingEngineV2::RenderOutlineLabels ) )
if ( mEngine->testFlag( QgsLabelingEngineV2::RenderOutlineLabels ) )
{
// draw outlined text
_fixQPictureDPI( painter );

View File

@ -32,7 +32,7 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
public:
//! 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,
const QString& layerId,
@ -45,10 +45,28 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
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;
// 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:
void init();
@ -57,10 +75,13 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
protected:
QgsPalLayerSettings mSettings;
QString mLayerId;
// these are needed only if using own renderer loop
QgsFields mFields;
QgsCoordinateReferenceSystem mCrs;
QgsAbstractFeatureSource* mSource;
bool mOwnsSource;
QList<QgsLabelFeature*> mLabels;
};

View File

@ -47,6 +47,8 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRender
, mCache( 0 )
, mLabeling( false )
, mDiagrams( false )
, mLabelProvider( 0 )
, mDiagramProvider( 0 )
, mLayerTransparency( 0 )
{
mSource = new QgsVectorLayerFeatureSource( layer );
@ -312,6 +314,18 @@ void QgsVectorLayerRenderer::drawRendererV2( QgsFeatureIterator& fit )
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 )
{
@ -469,9 +483,15 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
if ( QgsLabelingEngineV2* engine2 = mContext.labelingEngineV2() )
{
if ( layer->labelsEnabled() )
engine2->addProvider( new QgsVectorLayerLabelProvider( layer ) );
if ( layer->diagramsEnabled() )
engine2->addProvider( new QgsVectorLayerDiagramProvider( layer ) );
{
mLabelProvider = new QgsVectorLayerLabelProvider( layer, false );
engine2->addProvider( mLabelProvider );
if ( !mLabelProvider->prepare( mContext, attributeNames ) )
{
engine2->removeProvider( mLabelProvider );
mLabelProvider = 0; // deleted by engine
}
}
}
return;
}
@ -480,10 +500,9 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
{
mLabeling = true;
QgsPalLayerSettings& palyr = mContext.labelingEngine()->layer( mLayerID );
Q_UNUSED( palyr );
#if 0 // TODO: limit of labels, font not found
QgsPalLayerSettings& palyr = mContext.labelingEngine()->layer( mLayerID );
// see if feature count limit is set for labeling
if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 )
{
@ -514,58 +533,29 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
void QgsVectorLayerRenderer::prepareDiagrams( QgsVectorLayer* layer, QStringList& attributeNames )
{
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;
}
if ( !layer->diagramsEnabled() )
return;
mDiagrams = true;
const QgsDiagramRendererV2* diagRenderer = layer->diagramRenderer();
const QgsDiagramLayerSettings* diagSettings = layer->diagramLayerSettings();
mContext.labelingEngine()->prepareDiagramLayer( layer, attributeNames, mContext ); // will make internal copy of diagSettings + initialize it
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"
class QgsVectorLayerLabelProvider;
class QgsVectorLayerDiagramProvider;
/**
* Implementation of threaded rendering for vector layers.
@ -102,9 +104,18 @@ class QgsVectorLayerRenderer : public QgsMapLayerRenderer
QStringList mAttrNames;
//! used with old labeling engine (QgsPalLabeling): whether labeling is enabled
bool mLabeling;
//! used with new labeling engine (QgsPalLabeling): whether diagrams are enabled
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;
QPainter::CompositionMode mFeatureBlendMode;

View File

@ -77,7 +77,8 @@ void TestQgsLabelingEngineV2::testBasic()
vl->setCustomProperty( "labeling/enabled", true );
vl->setCustomProperty( "labeling/fieldName", "Class" );
QgsLabelingEngineV2 engine( mapSettings );
QgsLabelingEngineV2 engine;
engine.setMapSettings( mapSettings );
engine.addProvider( new QgsVectorLayerLabelProvider( vl ) );
//engine.setFlags( QgsLabelingEngineV2::RenderOutlineLabels | QgsLabelingEngineV2::DrawLabelRectOnly );
engine.run( context );
@ -87,6 +88,12 @@ void TestQgsLabelingEngineV2::testBasic()
// TODO: replace with render checker
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 );
}
@ -112,7 +119,8 @@ void TestQgsLabelingEngineV2::testDiagrams()
vl->loadNamedStyle( QString( TEST_DATA_DIR ) + "/points_diagrams.qml", res );
Q_ASSERT( res );
QgsLabelingEngineV2 engine( mapSettings );
QgsLabelingEngineV2 engine;
engine.setMapSettings( mapSettings );
engine.addProvider( new QgsVectorLayerDiagramProvider( vl ) );
engine.run( context );
@ -120,6 +128,12 @@ void TestQgsLabelingEngineV2::testDiagrams()
// TODO: replace with render checker
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 )