QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsalgorithmpointsinpolygon.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmpointsinpolygon.cpp
3  ---------------------
4  begin : November 2019
5  copyright : (C) 2019 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgsprocessing.h"
20 #include "qgsgeometryengine.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsapplication.h"
23 
25 
26 void QgsPointsInPolygonAlgorithm::initParameters( const QVariantMap &configuration )
27 {
28  mIsInPlace = configuration.value( QStringLiteral( "IN_PLACE" ) ).toBool();
29 
30  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "POINTS" ),
31  QObject::tr( "Points" ), QList< int > () << QgsProcessing::TypeVectorPoint ) );
32  addParameter( new QgsProcessingParameterField( QStringLiteral( "WEIGHT" ),
33  QObject::tr( "Weight field" ), QVariant(), QStringLiteral( "POINTS" ), QgsProcessingParameterField::Any, false, true ) );
34  addParameter( new QgsProcessingParameterField( QStringLiteral( "CLASSFIELD" ),
35  QObject::tr( "Class field" ), QVariant(), QStringLiteral( "POINTS" ), QgsProcessingParameterField::Any, false, true ) );
36  if ( mIsInPlace )
37  {
38  addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ),
39  QObject::tr( "Count field" ), QStringLiteral( "NUMPOINTS" ), inputParameterName() ) );
40  }
41  else
42  {
43  addParameter( new QgsProcessingParameterString( QStringLiteral( "FIELD" ),
44  QObject::tr( "Count field name" ), QStringLiteral( "NUMPOINTS" ) ) );
45  }
46 }
47 
48 QString QgsPointsInPolygonAlgorithm::name() const
49 {
50  return QStringLiteral( "countpointsinpolygon" );
51 }
52 
53 QString QgsPointsInPolygonAlgorithm::displayName() const
54 {
55  return QObject::tr( "Count points in polygon" );
56 }
57 
58 QStringList QgsPointsInPolygonAlgorithm::tags() const
59 {
60  return QObject::tr( "extract,filter,intersects,intersecting,disjoint,touching,within,contains,overlaps,relation" ).split( ',' );
61 }
62 
63 QString QgsPointsInPolygonAlgorithm::svgIconPath() const
64 {
65  return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmSumPoints.svg" ) );
66 }
67 
68 QIcon QgsPointsInPolygonAlgorithm::icon() const
69 {
70  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmSumPoints.svg" ) );
71 }
72 
73 QString QgsPointsInPolygonAlgorithm::group() const
74 {
75  return QObject::tr( "Vector analysis" );
76 }
77 
78 QString QgsPointsInPolygonAlgorithm::groupId() const
79 {
80  return QStringLiteral( "vectoranalysis" );
81 }
82 
83 QString QgsPointsInPolygonAlgorithm::shortHelpString() const
84 {
85  return QObject::tr( "This algorithm takes a points layer and a polygon layer and counts the number of points from "
86  "the first one in each polygons of the second one.\n\n"
87  "A new polygons layer is generated, with the exact same content as the input polygons layer, but "
88  "containing an additional field with the points count corresponding to each polygon.\n\n"
89  "An optional weight field can be used to assign weights to each point. If set, the count generated "
90  "will be the sum of the weight field for each point contained by the polygon.\n\n"
91  "Alternatively, a unique class field can be specified. If set, points are classified based on "
92  "the selected attribute, and if several points with the same attribute value are within the polygon, "
93  "only one of them is counted. The final count of the point in a polygon is, therefore, the count of "
94  "different classes that are found in it.\n\n"
95  "Both the weight field and unique class field cannot be specified. If they are, the weight field will "
96  "take precedence and the unique class field will be ignored." );
97 }
98 
99 QString QgsPointsInPolygonAlgorithm::shortDescription() const
100 {
101  return QObject::tr( "Counts point features located within polygon features." );
102 }
103 
104 QgsPointsInPolygonAlgorithm *QgsPointsInPolygonAlgorithm::createInstance() const
105 {
106  return new QgsPointsInPolygonAlgorithm();
107 }
108 
109 QList<int> QgsPointsInPolygonAlgorithm::inputLayerTypes() const
110 {
111  return QList< int >() << QgsProcessing::TypeVectorPolygon;
112 }
113 
114 QgsProcessing::SourceType QgsPointsInPolygonAlgorithm::outputLayerType() const
115 {
117 }
118 
120 {
121  mCrs = inputCrs;
122  return mCrs;
123 }
124 
125 QString QgsPointsInPolygonAlgorithm::inputParameterName() const
126 {
127  return QStringLiteral( "POLYGONS" );
128 }
129 
130 QString QgsPointsInPolygonAlgorithm::inputParameterDescription() const
131 {
132  return QObject::tr( "Polygons" );
133 }
134 
135 QString QgsPointsInPolygonAlgorithm::outputName() const
136 {
137  return QObject::tr( "Count" );
138 }
139 
140 bool QgsPointsInPolygonAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
141 {
142  mFieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
143  mWeightFieldName = parameterAsString( parameters, QStringLiteral( "WEIGHT" ), context );
144  mClassFieldName = parameterAsString( parameters, QStringLiteral( "CLASSFIELD" ), context );
145  mPointSource.reset( parameterAsSource( parameters, QStringLiteral( "POINTS" ), context ) );
146  if ( !mPointSource )
147  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "POINTS" ) ) );
148 
149  if ( !mWeightFieldName.isEmpty() )
150  {
151  mWeightFieldIndex = mPointSource->fields().lookupField( mWeightFieldName );
152  if ( mWeightFieldIndex == -1 )
153  throw QgsProcessingException( QObject::tr( "Could not find field %1" ).arg( mWeightFieldName ) );
154  mPointAttributes.append( mWeightFieldIndex );
155  }
156 
157  if ( !mClassFieldName.isEmpty() )
158  {
159  mClassFieldIndex = mPointSource->fields().lookupField( mClassFieldName );
160  if ( mClassFieldIndex == -1 )
161  throw QgsProcessingException( QObject::tr( "Could not find field %1" ).arg( mClassFieldIndex ) );
162  mPointAttributes.append( mClassFieldIndex );
163  }
164 
165  if ( mPointSource->hasSpatialIndex() == QgsFeatureSource::SpatialIndexNotPresent )
166  feedback->pushWarning( QObject::tr( "No spatial index exists for points layer, performance will be severely degraded" ) );
167 
168  return true;
169 }
170 
171 QgsFeatureList QgsPointsInPolygonAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
172 {
173  QgsFeature outputFeature = feature;
174  if ( !feature.hasGeometry() )
175  {
176  QgsAttributes attrs = feature.attributes();
177  if ( mDestFieldIndex < 0 )
178  attrs.append( 0 );
179  else
180  attrs[mDestFieldIndex] = 0;
181  outputFeature.setAttributes( attrs );
182  return QList< QgsFeature > () << outputFeature;
183  }
184  else
185  {
186  const QgsGeometry polyGeom = feature.geometry();
187  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( polyGeom.constGet() ) );
188  engine->prepareGeometry();
189 
190  double count = 0;
191  QSet< QVariant> classes;
192 
194  req.setSubsetOfAttributes( mPointAttributes );
195  QgsFeatureIterator it = mPointSource->getFeatures( req );
196 
197  bool ok = false;
198  QgsFeature pointFeature;
199  while ( it.nextFeature( pointFeature ) )
200  {
201  if ( feedback->isCanceled() )
202  break;
203 
204  if ( engine->contains( pointFeature.geometry().constGet() ) )
205  {
206  if ( mWeightFieldIndex >= 0 )
207  {
208  const QVariant weight = pointFeature.attribute( mWeightFieldIndex );
209  const double pointWeight = weight.toDouble( &ok );
210  // Ignore fields with non-numeric values
211  if ( ok )
212  count += pointWeight;
213  else
214  feedback->reportError( QObject::tr( "Weight field value “%1” is not a numeric value" ).arg( weight.toString() ) );
215  }
216  else if ( mClassFieldIndex >= 0 )
217  {
218  const QVariant pointClass = pointFeature.attribute( mClassFieldIndex );
219  classes.insert( pointClass );
220  }
221  else
222  {
223  count++;
224  }
225  }
226  }
227 
228  QgsAttributes attrs = feature.attributes();
229  double score = 0;
230 
231  if ( mClassFieldIndex >= 0 )
232  score = classes.size();
233  else
234  score = count;
235 
236  if ( mDestFieldIndex < 0 )
237  attrs.append( score );
238  else
239  attrs[mDestFieldIndex] = score;
240 
241  outputFeature.setAttributes( attrs );
242  return QList< QgsFeature >() << outputFeature;
243  }
244 }
245 
246 QgsFields QgsPointsInPolygonAlgorithm::outputFields( const QgsFields &inputFields ) const
247 {
248  if ( mIsInPlace )
249  {
250  mDestFieldIndex = inputFields.lookupField( mFieldName );
251  return inputFields;
252  }
253  else
254  {
255  QgsFields outFields = inputFields;
256  mDestFieldIndex = inputFields.lookupField( mFieldName );
257  if ( mDestFieldIndex < 0 )
258  outFields.append( QgsField( mFieldName, QVariant::Double ) );
259 
260  mFields = outFields;
261  return outFields;
262  }
263 }
264 
265 bool QgsPointsInPolygonAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
266 {
267  if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
268  {
269  return vl->geometryType() == QgsWkbTypes::PolygonGeometry;
270  }
271  return false;
272 }
273 
274 
276 
277 
278 
outputCrs
const QgsCoordinateReferenceSystem & outputCrs
Definition: qgswfsgetfeature.cpp:115
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsFeatureSource::SpatialIndexNotPresent
@ SpatialIndexNotPresent
No spatial index exists for the source.
Definition: qgsfeaturesource.h:190
QgsProcessingFeedback::reportError
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
Definition: qgsprocessingfeedback.cpp:59
QgsProcessing::TypeVectorPolygon
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsProcessingParameterFeatureSource
An input feature source (such as vector layers) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:3057
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:228
QgsFields::append
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
QgsApplication::iconPath
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Definition: qgsapplication.cpp:682
QgsProcessing::TypeVectorPoint
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
qgsapplication.h
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:101
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
qgsgeometryengine.h
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingParameterString
A string parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2647
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:882
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:327
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:165
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:136
QgsFeature::attributes
QgsAttributes attributes
Definition: qgsfeature.h:69
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
qgsvectorlayer.h
QgsGeometry::createGeometryEngine
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
Definition: qgsgeometry.cpp:3972
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
qgsprocessing.h
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:230
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
qgsalgorithmpointsinpolygon.h
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:1080
QgsAttributes
A vector of attributes. Mostly equal to QVector<QVariant>.
Definition: qgsattributes.h:57
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsFeatureRequest::setDestinationCrs
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
Definition: qgsfeaturerequest.cpp:301
QgsFeature::setAttributes
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:160
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QgsProcessingParameterField::Any
@ Any
Accepts any field.
Definition: qgsprocessingparameters.h:2947
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsProcessing::SourceType
SourceType
Data source types enum.
Definition: qgsprocessing.h:45
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsProcessingParameterField
A vector layer or feature source field parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2940
QgsProcessingFeedback::pushWarning
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:68
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50