QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsvectorlayerfeaturecounter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerfeaturecounter.cpp
3  ---------------------
4  begin : May 2017
5  copyright : (C) 2017 by Matthias Kuhn
6  email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsvectorlayer.h"
18 #include "qgsfeatureid.h"
19 
21  : QgsTask( tr( "Counting features in %1" ).arg( layer->name() ), QgsTask::CanCancel )
22  , mSource( new QgsVectorLayerFeatureSource( layer ) )
23  , mRenderer( layer->renderer()->clone() )
24  , mExpressionContext( context )
25  , mWithFids( storeSymbolFids )
26  , mFeatureCount( layer->featureCount() )
27 {
28  if ( !mExpressionContext.scopeCount() )
29  {
30  mExpressionContext = layer->createExpressionContext();
31  }
32 }
33 
35 {
36  mSymbolFeatureCountMap.clear();
37  mSymbolFeatureIdMap.clear();
38  QgsLegendSymbolList symbolList = mRenderer->legendSymbolItems();
39  QgsLegendSymbolList::const_iterator symbolIt = symbolList.constBegin();
40 
41  for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
42  {
43  mSymbolFeatureCountMap.insert( symbolIt->ruleKey(), 0 );
44  if ( mWithFids )
45  mSymbolFeatureIdMap.insert( symbolIt->ruleKey(), QgsFeatureIds() );
46  }
47 
48  // If there are no features to be counted, we can spare us the trouble
49  if ( mFeatureCount > 0 )
50  {
51  int featuresCounted = 0;
52 
53  // Renderer (rule based) may depend on context scale, with scale is ignored if 0
54  QgsRenderContext renderContext;
55  renderContext.setRendererScale( 0 );
56  renderContext.setExpressionContext( mExpressionContext );
57 
58  QgsFeatureRequest request;
59  if ( !mRenderer->filterNeedsGeometry() )
61  request.setSubsetOfAttributes( mRenderer->usedAttributes( renderContext ), mSource->fields() );
62  QgsFeatureIterator fit = mSource->getFeatures( request );
63 
64  // TODO: replace QgsInterruptionChecker with QgsFeedback
65  // fit.setInterruptionChecker( mFeedback );
66 
67  mRenderer->startRender( renderContext, mSource->fields() );
68 
69  double progress = 0;
70  QgsFeature f;
71  while ( fit.nextFeature( f ) )
72  {
73  renderContext.expressionContext().setFeature( f );
74 
75  const QSet<QString> featureKeyList = mRenderer->legendKeysForFeature( f, renderContext );
76  for ( const QString &key : featureKeyList )
77  {
78  mSymbolFeatureCountMap[key] += 1;
79  if ( mWithFids )
80  mSymbolFeatureIdMap[key].insert( f.id() );
81  }
82  ++featuresCounted;
83 
84  double p = ( static_cast< double >( featuresCounted ) / mFeatureCount ) * 100;
85  if ( p - progress > 1 )
86  {
87  progress = p;
89  }
90 
91  if ( isCanceled() )
92  {
93  mRenderer->stopRender( renderContext );
94  return false;
95  }
96  }
97  mRenderer->stopRender( renderContext );
98  }
99  setProgress( 100 );
100  emit symbolsCounted();
101  return true;
102 }
103 
105 {
106  return mSymbolFeatureCountMap;
107 }
108 
109 long long QgsVectorLayerFeatureCounter::featureCount( const QString &legendKey ) const
110 {
111  return mSymbolFeatureCountMap.value( legendKey, -1 );
112 }
113 
114 QHash<QString, QgsFeatureIds> QgsVectorLayerFeatureCounter::symbolFeatureIdMap() const
115 {
116  return mSymbolFeatureIdMap;
117 }
118 
120 {
121  return mSymbolFeatureIdMap.value( symbolkey, QgsFeatureIds() );
122 }
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
int scopeCount() const
Returns the number of scopes contained in the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Contains information about the context of a rendering operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setRendererScale(double scale)
Sets the renderer map scale.
Abstract base class for long running background tasks.
double progress() const
Returns the task's progress (between 0.0 and 100.0)
bool isCanceled() const
Will return true if task should terminate ASAP.
void setProgress(double progress)
Sets the task's current progress.
void symbolsCounted()
Emitted when the symbols have been counted.
QgsVectorLayerFeatureCounter(QgsVectorLayer *layer, const QgsExpressionContext &context=QgsExpressionContext(), bool storeSymbolFids=false)
Create a new feature counter for layer.
bool run() override
Calculates the feature count and Ids per symbol.
QHash< QString, long long > symbolFeatureCountMap() const
Returns the count for each symbol.
long long featureCount(const QString &legendKey) const
Returns the feature count for a particular legendKey.
QgsFeatureIds featureIds(const QString &symbolkey) const
Returns the feature Ids for a particular legendKey.
QHash< QString, QgsFeatureIds > symbolFeatureIdMap() const
Returns the QgsFeatureIds for each symbol.
Partial snapshot of vector layer's state (only the members necessary for access to features)
Represents a vector layer which manages a vector based data sets.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
QList< QgsLegendSymbolItem > QgsLegendSymbolList