Ensure consistent label positioning by sorting rule based label providers

This commit is contained in:
PatrikSylve 2025-02-04 02:04:57 +01:00 committed by GitHub
parent 5745bd634b
commit 12a2079225
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 28 deletions

View File

@ -21,7 +21,7 @@ Rule based labeling for a vector layer.
%End
public:
typedef QList<QgsRuleBasedLabeling::Rule *> RuleList;
typedef QMap<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *> RuleToProviderMap;
public:
class Rule
{
@ -312,8 +312,6 @@ Set pal settings for a specific provider (takes ownership).
protected:
};

View File

@ -21,7 +21,7 @@ Rule based labeling for a vector layer.
%End
public:
typedef QList<QgsRuleBasedLabeling::Rule *> RuleList;
typedef QMap<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *> RuleToProviderMap;
public:
class Rule
{
@ -312,8 +312,6 @@ Set pal settings for a specific provider (takes ownership).
protected:
};

View File

@ -31,8 +31,10 @@ QgsVectorLayerLabelProvider *QgsRuleBasedLabelProvider::createProvider( QgsVecto
bool QgsRuleBasedLabelProvider::prepare( QgsRenderContext &context, QSet<QString> &attributeNames )
{
for ( QgsVectorLayerLabelProvider *provider : std::as_const( mSubProviders ) )
provider->setEngine( mEngine );
for ( const auto &subprovider : std::as_const( mSubProviders ) )
{
subprovider.second->setEngine( mEngine );
}
// populate sub-providers
mRules->rootRule()->prepare( context, attributeNames, mSubProviders );
@ -48,8 +50,10 @@ QList<QgsLabelFeature *> QgsRuleBasedLabelProvider::registerFeature( const QgsFe
QList<QgsAbstractLabelProvider *> QgsRuleBasedLabelProvider::subProviders()
{
QList<QgsAbstractLabelProvider *> lst;
for ( QgsVectorLayerLabelProvider *subprovider : std::as_const( mSubProviders ) )
lst << subprovider;
for ( const auto &subprovider : std::as_const( mSubProviders ) )
{
lst << subprovider.second;
}
return lst;
}
@ -312,14 +316,25 @@ QDomElement QgsRuleBasedLabeling::Rule::save( QDomDocument &doc, const QgsReadWr
return ruleElem;
}
void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer *layer, QgsRuleBasedLabeling::RuleToProviderMap &subProviders, QgsRuleBasedLabelProvider *provider )
void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer *layer, QgsRuleBasedLabeling::RuleToProviderVec &subProviders, QgsRuleBasedLabelProvider *provider )
{
if ( mSettings )
{
// add provider!
QgsVectorLayerLabelProvider *p = provider->createProvider( layer, mRuleKey, false, mSettings.get() );
delete subProviders.value( this, nullptr );
subProviders[this] = p;
auto it = std::find_if( subProviders.begin(), subProviders.end(),
[this]( const std::pair<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *> &item )
{
return item.first == this;
} );
if ( it != subProviders.end() )
{
delete it->second;
subProviders.erase( it );
}
subProviders.push_back( {this, p} );
}
// call recursively
@ -329,15 +344,24 @@ void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer *layer, QgsR
}
}
void QgsRuleBasedLabeling::Rule::prepare( QgsRenderContext &context, QSet<QString> &attributeNames, QgsRuleBasedLabeling::RuleToProviderMap &subProviders )
void QgsRuleBasedLabeling::Rule::prepare( QgsRenderContext &context, QSet<QString> &attributeNames, QgsRuleBasedLabeling::RuleToProviderVec &subProviders )
{
if ( mSettings )
{
QgsVectorLayerLabelProvider *p = subProviders[this];
if ( !p->prepare( context, attributeNames ) )
auto it = std::find_if( subProviders.begin(), subProviders.end(),
[this]( const std::pair<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *> &item )
{
subProviders.remove( this );
delete p;
return item.first == this;
} );
if ( it != subProviders.end() )
{
QgsVectorLayerLabelProvider *p = it->second;
if ( !p->prepare( context, attributeNames ) )
{
subProviders.erase( it );
delete p;
}
}
}
@ -354,7 +378,7 @@ void QgsRuleBasedLabeling::Rule::prepare( QgsRenderContext &context, QSet<QStrin
}
}
std::tuple< QgsRuleBasedLabeling::Rule::RegisterResult, QList< QgsLabelFeature * > > QgsRuleBasedLabeling::Rule::registerFeature( const QgsFeature &feature, QgsRenderContext &context, QgsRuleBasedLabeling::RuleToProviderMap &subProviders, const QgsGeometry &obstacleGeometry, const QgsSymbol *symbol )
std::tuple< QgsRuleBasedLabeling::Rule::RegisterResult, QList< QgsLabelFeature * > > QgsRuleBasedLabeling::Rule::registerFeature( const QgsFeature &feature, QgsRenderContext &context, QgsRuleBasedLabeling::RuleToProviderVec &subProviders, const QgsGeometry &obstacleGeometry, const QgsSymbol *symbol )
{
QList< QgsLabelFeature * > labels;
if ( !isFilterOK( feature, context )
@ -366,9 +390,15 @@ std::tuple< QgsRuleBasedLabeling::Rule::RegisterResult, QList< QgsLabelFeature *
bool registered = false;
// do we have active subprovider for the rule?
if ( subProviders.contains( this ) && mIsActive )
auto it = std::find_if( subProviders.begin(), subProviders.end(),
[this]( const std::pair<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *> &item )
{
labels.append( subProviders[this]->registerFeature( feature, context, obstacleGeometry, symbol ) );
return item.first == this;
} );
if ( it != subProviders.end() && mIsActive )
{
labels.append( it->second->registerFeature( feature, context, obstacleGeometry, symbol ) );
registered = true;
}

View File

@ -43,7 +43,10 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
public:
class Rule;
typedef QList<QgsRuleBasedLabeling::Rule *> RuleList;
typedef QMap<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *> RuleToProviderMap;
private:
typedef std::vector<std::pair<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *>> RuleToProviderVec;
public:
/**
* \ingroup core
@ -261,7 +264,7 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
* add providers
* \note not available in Python bindings
*/
void createSubProviders( QgsVectorLayer *layer, RuleToProviderMap &subProviders, QgsRuleBasedLabelProvider *provider ) SIP_SKIP;
void createSubProviders( QgsVectorLayer *layer, RuleToProviderVec &subProviders, QgsRuleBasedLabelProvider *provider ) SIP_SKIP;
/**
* append rule keys of descendants that contain valid settings (i.e. they will be sub-providers)
@ -273,7 +276,7 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
* call prepare() on sub-providers and populate attributeNames
* \note not available in Python bindings
*/
void prepare( QgsRenderContext &context, QSet<QString> &attributeNames, RuleToProviderMap &subProviders ) SIP_SKIP;
void prepare( QgsRenderContext &context, QSet<QString> &attributeNames, RuleToProviderVec &subProviders ) SIP_SKIP;
/**
* Register individual features
@ -284,7 +287,7 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
*
* \note not available in Python bindings
*/
std::tuple< RegisterResult, QList< QgsLabelFeature * > > registerFeature( const QgsFeature &feature, QgsRenderContext &context, RuleToProviderMap &subProviders, const QgsGeometry &obstacleGeometry = QgsGeometry(), const QgsSymbol *symbol = nullptr ) SIP_SKIP;
std::tuple< RegisterResult, QList< QgsLabelFeature * > > registerFeature( const QgsFeature &feature, QgsRenderContext &context, RuleToProviderVec &subProviders, const QgsGeometry &obstacleGeometry = QgsGeometry(), const QgsSymbol *symbol = nullptr ) SIP_SKIP;
/**
* Returns TRUE if this rule or any of its children requires advanced composition effects
@ -391,8 +394,6 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
protected:
std::unique_ptr<Rule> mRootRule;
};
#ifndef SIP_RUN
@ -425,7 +426,7 @@ class CORE_EXPORT QgsRuleBasedLabelProvider : public QgsVectorLayerLabelProvider
//! owned copy
std::unique_ptr<QgsRuleBasedLabeling> mRules;
//! label providers are owned by labeling engine
QgsRuleBasedLabeling::RuleToProviderMap mSubProviders;
std::vector<std::pair<QgsRuleBasedLabeling::Rule *, QgsVectorLayerLabelProvider *>> mSubProviders;
};
#endif