QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 & )
27 {
28  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "POINTS" ),
29  QObject::tr( "Points" ), QList< int > () << QgsProcessing::TypeVectorPoint ) );
30  addParameter( new QgsProcessingParameterField( QStringLiteral( "WEIGHT" ),
31  QObject::tr( "Weight field" ), QVariant(), QStringLiteral( "POINTS" ), QgsProcessingParameterField::Any, false, true ) );
32  addParameter( new QgsProcessingParameterField( QStringLiteral( "CLASSFIELD" ),
33  QObject::tr( "Class field" ), QVariant(), QStringLiteral( "POINTS" ), QgsProcessingParameterField::Any, false, true ) );
34  addParameter( new QgsProcessingParameterString( QStringLiteral( "FIELD" ),
35  QObject::tr( "Count field name" ), QStringLiteral( "NUMPOINTS" ) ) );
36 }
37 
38 QString QgsPointsInPolygonAlgorithm::name() const
39 {
40  return QStringLiteral( "countpointsinpolygon" );
41 }
42 
43 QString QgsPointsInPolygonAlgorithm::displayName() const
44 {
45  return QObject::tr( "Count points in polygon" );
46 }
47 
48 QStringList QgsPointsInPolygonAlgorithm::tags() const
49 {
50  return QObject::tr( "extract,filter,intersects,intersecting,disjoint,touching,within,contains,overlaps,relation" ).split( ',' );
51 }
52 
53 QString QgsPointsInPolygonAlgorithm::svgIconPath() const
54 {
55  return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmSumPoints.svg" ) );
56 }
57 
58 QIcon QgsPointsInPolygonAlgorithm::icon() const
59 {
60  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmSumPoints.svg" ) );
61 }
62 
63 QString QgsPointsInPolygonAlgorithm::group() const
64 {
65  return QObject::tr( "Vector analysis" );
66 }
67 
68 QString QgsPointsInPolygonAlgorithm::groupId() const
69 {
70  return QStringLiteral( "vectoranalysis" );
71 }
72 
73 QString QgsPointsInPolygonAlgorithm::shortHelpString() const
74 {
75  return QObject::tr( "This algorithm takes a points layer and a polygon layer and counts the number of points from "
76  "the first one in each polygons of the second one.\n\n"
77  "A new polygons layer is generated, with the exact same content as the input polygons layer, but "
78  "containing an additional field with the points count corresponding to each polygon.\n\n"
79  "An optional weight field can be used to assign weights to each point. If set, the count generated "
80  "will be the sum of the weight field for each point contained by the polygon.\n\n"
81  "Alternatively, a unique class field can be specified. If set, points are classified based on "
82  "the selected attribute, and if several points with the same attribute value are within the polygon, "
83  "only one of them is counted. The final count of the point in a polygon is, therefore, the count of "
84  "different classes that are found in it.\n\n"
85  "Both the weight field and unique class field cannot be specified. If they are, the weight field will "
86  "take precedence and the unique class field will be ignored." );
87 }
88 
89 QString QgsPointsInPolygonAlgorithm::shortDescription() const
90 {
91  return QObject::tr( "Counts point features located within polygon features." );
92 }
93 
94 QgsPointsInPolygonAlgorithm *QgsPointsInPolygonAlgorithm::createInstance() const
95 {
96  return new QgsPointsInPolygonAlgorithm();
97 }
98 
99 QList<int> QgsPointsInPolygonAlgorithm::inputLayerTypes() const
100 {
101  return QList< int >() << QgsProcessing::TypeVectorPolygon;
102 }
103 
104 QgsProcessing::SourceType QgsPointsInPolygonAlgorithm::outputLayerType() const
105 {
107 }
108 
110 {
111  mCrs = inputCrs;
112  return mCrs;
113 }
114 
115 QString QgsPointsInPolygonAlgorithm::inputParameterName() const
116 {
117  return QStringLiteral( "POLYGONS" );
118 }
119 
120 QString QgsPointsInPolygonAlgorithm::inputParameterDescription() const
121 {
122  return QObject::tr( "Polygons" );
123 }
124 
125 QString QgsPointsInPolygonAlgorithm::outputName() const
126 {
127  return QObject::tr( "Count" );
128 }
129 
130 bool QgsPointsInPolygonAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
131 {
132  mFieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
133  mWeightFieldName = parameterAsString( parameters, QStringLiteral( "WEIGHT" ), context );
134  mClassFieldName = parameterAsString( parameters, QStringLiteral( "CLASSFIELD" ), context );
135  mPointSource.reset( parameterAsSource( parameters, QStringLiteral( "POINTS" ), context ) );
136  if ( !mPointSource )
137  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "POINTS" ) ) );
138 
139  if ( !mWeightFieldName.isEmpty() )
140  {
141  mWeightFieldIndex = mPointSource->fields().lookupField( mWeightFieldName );
142  if ( mWeightFieldIndex == -1 )
143  throw QgsProcessingException( QObject::tr( "Could not find field %1" ).arg( mWeightFieldName ) );
144  mPointAttributes.append( mWeightFieldIndex );
145  }
146 
147  if ( !mClassFieldName.isEmpty() )
148  {
149  mClassFieldIndex = mPointSource->fields().lookupField( mClassFieldName );
150  if ( mClassFieldIndex == -1 )
151  throw QgsProcessingException( QObject::tr( "Could not find field %1" ).arg( mClassFieldIndex ) );
152  mPointAttributes.append( mClassFieldIndex );
153  }
154 
155  if ( mPointSource->hasSpatialIndex() == QgsFeatureSource::SpatialIndexNotPresent )
156  feedback->reportError( QObject::tr( "No spatial index exists for points layer, performance will be severely degraded" ) );
157 
158  return true;
159 }
160 
161 QgsFeatureList QgsPointsInPolygonAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
162 {
163  QgsFeature outputFeature = feature;
164  if ( !feature.hasGeometry() )
165  {
166  QgsAttributes attrs = feature.attributes();
167  if ( mDestFieldIndex < 0 )
168  attrs.append( 0 );
169  else
170  attrs[mDestFieldIndex] = 0;
171  outputFeature.setAttributes( attrs );
172  return QList< QgsFeature > () << outputFeature;
173  }
174  else
175  {
176  const QgsGeometry polyGeom = feature.geometry();
177  std::unique_ptr< QgsGeometryEngine > engine( QgsGeometry::createGeometryEngine( polyGeom.constGet() ) );
178  engine->prepareGeometry();
179 
180  double count = 0;
181  QSet< QVariant> classes;
182 
184  req.setSubsetOfAttributes( mPointAttributes );
185  QgsFeatureIterator it = mPointSource->getFeatures( req );
186 
187  bool ok = false;
188  QgsFeature pointFeature;
189  while ( it.nextFeature( pointFeature ) )
190  {
191  if ( feedback->isCanceled() )
192  break;
193 
194  if ( engine->contains( pointFeature.geometry().constGet() ) )
195  {
196  if ( mWeightFieldIndex >= 0 )
197  {
198  const QVariant weight = pointFeature.attribute( mWeightFieldIndex );
199  double pointWeight = weight.toDouble( &ok );
200  // Ignore fields with non-numeric values
201  if ( ok )
202  count += pointWeight;
203  else
204  feedback->reportError( QObject::tr( "Weight field value “%1” is not a numeric value" ).arg( weight.toString() ) );
205  }
206  else if ( mClassFieldIndex >= 0 )
207  {
208  const QVariant pointClass = pointFeature.attribute( mClassFieldIndex );
209  classes.insert( pointClass );
210  }
211  else
212  {
213  count++;
214  }
215  }
216  }
217 
218  QgsAttributes attrs = feature.attributes();
219  double score = 0;
220 
221  if ( mClassFieldIndex >= 0 )
222  score = classes.size();
223  else
224  score = count;
225 
226  if ( mDestFieldIndex < 0 )
227  attrs.append( score );
228  else
229  attrs[mDestFieldIndex] = score;
230 
231  outputFeature.setAttributes( attrs );
232  return QList< QgsFeature >() << outputFeature;
233  }
234 }
235 
236 QgsFields QgsPointsInPolygonAlgorithm::outputFields( const QgsFields &inputFields ) const
237 {
238  QgsFields outFields = inputFields;
239  mDestFieldIndex = inputFields.lookupField( mFieldName );
240  if ( mDestFieldIndex < 0 )
241  outFields.append( QgsField( mFieldName, QVariant::Double ) );
242 
243  mFields = outFields;
244  return outFields;
245 }
246 
247 
249 
250 
251 
outputCrs
const QgsCoordinateReferenceSystem & outputCrs
Definition: qgswfsgetfeature.cpp:115
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsProcessingFeedback
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:39
QgsProcessing::TypeVectorPolygon
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:50
QgsFields
Definition: qgsfields.h:44
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsProcessingParameterFeatureSource
Definition: qgsprocessingparameters.h:2612
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:190
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:594
QgsProcessing::TypeVectorPoint
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:48
qgsapplication.h
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:97
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
qgsgeometryengine.h
QgsProcessingContext
Definition: qgsprocessingcontext.h:43
QgsProcessingParameterString
Definition: qgsprocessingparameters.h:2202
QgsFeatureList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:572
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:135
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:128
QgsFeature::attributes
QgsAttributes attributes
Definition: qgsfeature.h:69
QgsCoordinateReferenceSystem
Definition: qgscoordinatereferencesystem.h:206
qgsvectorlayer.h
QgsFeedback::isCanceled
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:66
QgsGeometry::createGeometryEngine
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
Definition: qgsgeometry.cpp:3659
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
qgsprocessing.h
QgsGeometry
Definition: qgsgeometry.h:122
QgsFeature::hasGeometry
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
qgsalgorithmpointsinpolygon.h
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:962
QgsAttributes
Definition: qgsattributes.h:57
QgsFeature
Definition: qgsfeature.h:55
QgsFeatureRequest::setDestinationCrs
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
Definition: qgsfeaturerequest.cpp:263
QgsFeature::setAttributes
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:127
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:324
QgsProcessingParameterField::Any
@ Any
Accepts any field.
Definition: qgsprocessingparameters.h:2502
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
QgsProcessing::SourceType
SourceType
Data source types enum.
Definition: qgsprocessing.h:44
QgsProcessingException
Definition: qgsexception.h:82
QgsProcessingParameterField
Definition: qgsprocessingparameters.h:2495
QgsField
Definition: qgsfield.h:49