QGIS API Documentation  3.9.0-Master (224899f119)
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  , mFeatureCount( layer->featureCount() )
26 {
27  if ( !mExpressionContext.scopeCount() )
28  {
29  mExpressionContext = layer->createExpressionContext();
30  }
31 }
32 
34 {
35  mSymbolFeatureCountMap.clear();
36  mSymbolFeatureIdMap.clear();
37  QgsLegendSymbolList symbolList = mRenderer->legendSymbolItems();
38  QgsLegendSymbolList::const_iterator symbolIt = symbolList.constBegin();
39 
40  for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
41  {
42  mSymbolFeatureCountMap.insert( symbolIt->label(), 0 );
43  mSymbolFeatureIdMap.insert( symbolIt->label(), QgsFeatureIds() );
44  }
45 
46  // If there are no features to be counted, we can spare us the trouble
47  if ( mFeatureCount > 0 )
48  {
49  int featuresCounted = 0;
50 
51  // Renderer (rule based) may depend on context scale, with scale is ignored if 0
52  QgsRenderContext renderContext;
53  renderContext.setRendererScale( 0 );
54  renderContext.setExpressionContext( mExpressionContext );
55 
56  QgsFeatureRequest request;
57  if ( !mRenderer->filterNeedsGeometry() )
59  request.setSubsetOfAttributes( mRenderer->usedAttributes( renderContext ), mSource->fields() );
60  QgsFeatureIterator fit = mSource->getFeatures( request );
61 
62  // TODO: replace QgsInterruptionChecker with QgsFeedback
63  // fit.setInterruptionChecker( mFeedback );
64 
65  mRenderer->startRender( renderContext, mSource->fields() );
66 
67  double progress = 0;
68  QgsFeature f;
69  while ( fit.nextFeature( f ) )
70  {
71  renderContext.expressionContext().setFeature( f );
72 
73  const QSet<QString> featureKeyList = mRenderer->legendKeysForFeature( f, renderContext );
74  for ( const QString &key : featureKeyList )
75  {
76  mSymbolFeatureCountMap[key] += 1;
77  mSymbolFeatureIdMap[key].insert( f.id() );
78  }
79  ++featuresCounted;
80 
81  double p = ( static_cast< double >( featuresCounted ) / mFeatureCount ) * 100;
82  if ( p - progress > 1 )
83  {
84  progress = p;
85  setProgress( progress );
86  }
87 
88  if ( isCanceled() )
89  {
90  mRenderer->stopRender( renderContext );
91  return false;
92  }
93  }
94  mRenderer->stopRender( renderContext );
95  }
96  setProgress( 100 );
97  emit symbolsCounted();
98  return true;
99 }
100 
102 {
103  return mSymbolFeatureCountMap;
104 }
105 
106 long QgsVectorLayerFeatureCounter::featureCount( const QString &legendKey ) const
107 {
108  return mSymbolFeatureCountMap.value( legendKey, -1 );
109 }
110 
111 QHash<QString, QgsFeatureIds> QgsVectorLayerFeatureCounter::symbolFeatureIdMap() const
112 {
113  return mSymbolFeatureIdMap;
114 }
115 
117 {
118  return mSymbolFeatureIdMap.value( symbolkey, QgsFeatureIds() );
119 }
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
void setProgress(double progress)
Sets the task&#39;s current progress.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
QList< QgsLegendSymbolItem > QgsLegendSymbolList
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
bool run() override
Calculates the feature count and Ids per symbol.
void setRendererScale(double scale)
Sets the renderer map scale.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool isCanceled() const
Will return true if task should terminate ASAP.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
QgsVectorLayerFeatureCounter(QgsVectorLayer *layer, const QgsExpressionContext &context=QgsExpressionContext())
Create a new feature counter for layer.
void symbolsCounted()
Emitted when the symbols have been counted.
long featureCount(const QString &legendKey) const
Returns the feature count for a particular legendKey.
int scopeCount() const
Returns the number of scopes contained in the context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Abstract base class for long running background tasks.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QHash< QString, QgsFeatureIds > symbolFeatureIdMap() const
Returns the QgsFeatureIds for each symbol.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
QgsExpressionContext & expressionContext()
Gets the expression context.
Contains information about the context of a rendering operation.
double progress() const
Returns the task&#39;s progress (between 0.0 and 100.0)
QHash< QString, long > symbolFeatureCountMap() const
Returns the count for each symbol.
QgsFeatureIds featureIds(const QString &symbolkey) const
Returns the feature Ids for a particular legendKey.
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.