QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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
26void QgsPointsInPolygonAlgorithm::initParameters( const QVariantMap &configuration )
27{
28 mIsInPlace = configuration.value( QStringLiteral( "IN_PLACE" ) ).toBool();
29
30 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "POINTS" ), QObject::tr( "Points" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) ) );
31 addParameter( new QgsProcessingParameterField( QStringLiteral( "WEIGHT" ), QObject::tr( "Weight field" ), QVariant(), QStringLiteral( "POINTS" ), Qgis::ProcessingFieldParameterDataType::Any, false, true ) );
32 addParameter( new QgsProcessingParameterField( QStringLiteral( "CLASSFIELD" ), QObject::tr( "Class field" ), QVariant(), QStringLiteral( "POINTS" ), Qgis::ProcessingFieldParameterDataType::Any, false, true ) );
33 if ( mIsInPlace )
34 {
35 addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Count field" ), QStringLiteral( "NUMPOINTS" ), inputParameterName() ) );
36 }
37 else
38 {
39 addParameter( new QgsProcessingParameterString( QStringLiteral( "FIELD" ), QObject::tr( "Count field name" ), QStringLiteral( "NUMPOINTS" ) ) );
40 }
41}
42
43QString QgsPointsInPolygonAlgorithm::name() const
44{
45 return QStringLiteral( "countpointsinpolygon" );
46}
47
48QString QgsPointsInPolygonAlgorithm::displayName() const
49{
50 return QObject::tr( "Count points in polygon" );
51}
52
53QStringList QgsPointsInPolygonAlgorithm::tags() const
54{
55 return QObject::tr( "extract,filter,intersects,intersecting,disjoint,touching,within,contains,overlaps,relation" ).split( ',' );
56}
57
58QString QgsPointsInPolygonAlgorithm::svgIconPath() const
59{
60 return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmSumPoints.svg" ) );
61}
62
63QIcon QgsPointsInPolygonAlgorithm::icon() const
64{
65 return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmSumPoints.svg" ) );
66}
67
68QString QgsPointsInPolygonAlgorithm::group() const
69{
70 return QObject::tr( "Vector analysis" );
71}
72
73QString QgsPointsInPolygonAlgorithm::groupId() const
74{
75 return QStringLiteral( "vectoranalysis" );
76}
77
78QString QgsPointsInPolygonAlgorithm::shortHelpString() const
79{
80 return QObject::tr( "This algorithm takes a points layer and a polygon layer and counts the number of points from "
81 "the first one in each polygons of the second one.\n\n"
82 "A new polygons layer is generated, with the exact same content as the input polygons layer, but "
83 "containing an additional field with the points count corresponding to each polygon.\n\n"
84 "An optional weight field can be used to assign weights to each point. If set, the count generated "
85 "will be the sum of the weight field for each point contained by the polygon.\n\n"
86 "Alternatively, a unique class field can be specified. If set, points are classified based on "
87 "the selected attribute, and if several points with the same attribute value are within the polygon, "
88 "only one of them is counted. The final count of the point in a polygon is, therefore, the count of "
89 "different classes that are found in it.\n\n"
90 "Both the weight field and unique class field cannot be specified. If they are, the weight field will "
91 "take precedence and the unique class field will be ignored." );
92}
93
94QString QgsPointsInPolygonAlgorithm::shortDescription() const
95{
96 return QObject::tr( "Counts point features located within polygon features." );
97}
98
99QgsPointsInPolygonAlgorithm *QgsPointsInPolygonAlgorithm::createInstance() const
100{
101 return new QgsPointsInPolygonAlgorithm();
102}
103
104QList<int> QgsPointsInPolygonAlgorithm::inputLayerTypes() const
105{
106 return QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon );
107}
108
109Qgis::ProcessingSourceType QgsPointsInPolygonAlgorithm::outputLayerType() const
110{
112}
113
114QgsCoordinateReferenceSystem QgsPointsInPolygonAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const
115{
116 mCrs = inputCrs;
117 return mCrs;
118}
119
120QString QgsPointsInPolygonAlgorithm::inputParameterName() const
121{
122 return QStringLiteral( "POLYGONS" );
123}
124
125QString QgsPointsInPolygonAlgorithm::inputParameterDescription() const
126{
127 return QObject::tr( "Polygons" );
128}
129
130QString QgsPointsInPolygonAlgorithm::outputName() const
131{
132 return QObject::tr( "Count" );
133}
134
135bool QgsPointsInPolygonAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
136{
137 mFieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
138 mWeightFieldName = parameterAsString( parameters, QStringLiteral( "WEIGHT" ), context );
139 mClassFieldName = parameterAsString( parameters, QStringLiteral( "CLASSFIELD" ), context );
140 mPointSource.reset( parameterAsSource( parameters, QStringLiteral( "POINTS" ), context ) );
141 if ( !mPointSource )
142 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "POINTS" ) ) );
143
144 if ( !mWeightFieldName.isEmpty() )
145 {
146 mWeightFieldIndex = mPointSource->fields().lookupField( mWeightFieldName );
147 if ( mWeightFieldIndex == -1 )
148 throw QgsProcessingException( QObject::tr( "Could not find field %1" ).arg( mWeightFieldName ) );
149 mPointAttributes.append( mWeightFieldIndex );
150 }
151
152 if ( !mClassFieldName.isEmpty() )
153 {
154 mClassFieldIndex = mPointSource->fields().lookupField( mClassFieldName );
155 if ( mClassFieldIndex == -1 )
156 throw QgsProcessingException( QObject::tr( "Could not find field %1" ).arg( mClassFieldIndex ) );
157 mPointAttributes.append( mClassFieldIndex );
158 }
159
160 if ( mPointSource->hasSpatialIndex() == Qgis::SpatialIndexPresence::NotPresent )
161 feedback->pushWarning( QObject::tr( "No spatial index exists for points layer, performance will be severely degraded" ) );
162
163 return true;
164}
165
166QgsFeatureList QgsPointsInPolygonAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
167{
168 QgsFeature outputFeature = feature;
169 if ( !feature.hasGeometry() )
170 {
171 QgsAttributes attrs = feature.attributes();
172 if ( mDestFieldIndex < 0 )
173 attrs.append( 0 );
174 else
175 attrs[mDestFieldIndex] = 0;
176 outputFeature.setAttributes( attrs );
177 return QList<QgsFeature>() << outputFeature;
178 }
179 else
180 {
181 const QgsGeometry polyGeom = feature.geometry();
182 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( polyGeom.constGet() ) );
183 engine->prepareGeometry();
184
185 double count = 0;
186 QSet<QVariant> classes;
187
189 req.setSubsetOfAttributes( mPointAttributes );
190 QgsFeatureIterator it = mPointSource->getFeatures( req );
191
192 bool ok = false;
193 QgsFeature pointFeature;
194 while ( it.nextFeature( pointFeature ) )
195 {
196 if ( feedback->isCanceled() )
197 break;
198
199 if ( engine->contains( pointFeature.geometry().constGet() ) )
200 {
201 if ( mWeightFieldIndex >= 0 )
202 {
203 const QVariant weight = pointFeature.attribute( mWeightFieldIndex );
204 const double pointWeight = weight.toDouble( &ok );
205 // Ignore fields with non-numeric values
206 if ( ok )
207 count += pointWeight;
208 else
209 feedback->reportError( QObject::tr( "Weight field value “%1” is not a numeric value" ).arg( weight.toString() ) );
210 }
211 else if ( mClassFieldIndex >= 0 )
212 {
213 const QVariant pointClass = pointFeature.attribute( mClassFieldIndex );
214 classes.insert( pointClass );
215 }
216 else
217 {
218 count++;
219 }
220 }
221 }
222
223 QgsAttributes attrs = feature.attributes();
224 double score = 0;
225
226 if ( mClassFieldIndex >= 0 )
227 score = classes.size();
228 else
229 score = count;
230
231 if ( mDestFieldIndex < 0 )
232 attrs.append( score );
233 else
234 attrs[mDestFieldIndex] = score;
235
236 outputFeature.setAttributes( attrs );
237 return QList<QgsFeature>() << outputFeature;
238 }
239}
240
241QgsFields QgsPointsInPolygonAlgorithm::outputFields( const QgsFields &inputFields ) const
242{
243 if ( mIsInPlace )
244 {
245 mDestFieldIndex = inputFields.lookupField( mFieldName );
246 return inputFields;
247 }
248 else
249 {
250 QgsFields outFields = inputFields;
251 mDestFieldIndex = inputFields.lookupField( mFieldName );
252 if ( mDestFieldIndex < 0 )
253 outFields.append( QgsField( mFieldName, QMetaType::Type::Double ) );
254
255 mFields = outFields;
256 return outFields;
257 }
258}
259
260bool QgsPointsInPolygonAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
261{
262 if ( const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( layer ) )
263 {
264 return vl->geometryType() == Qgis::GeometryType::Polygon;
265 }
266 return false;
267}
268
269
ProcessingSourceType
Processing data source types.
Definition qgis.h:3333
@ VectorPoint
Vector point layers.
@ VectorPolygon
Vector polygon layers.
@ NotPresent
No spatial index exists for the source.
@ Polygon
Polygons.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A vector of attributes.
This class represents a coordinate reference system (CRS).
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsAttributes attributes
Definition qgsfeature.h:67
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QgsGeometry geometry
Definition qgsfeature.h:69
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Base class for all map layer types.
Definition qgsmaplayer.h:76
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A string parameter for processing algorithms.
Represents a vector layer which manages a vector based data sets.
QList< QgsFeature > QgsFeatureList