QGIS API Documentation  3.12.1-București (121cc00ff0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsalgorithmjoinbylocation.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmjoinbylocation.cpp
3  ---------------------
4  begin : January 2020
5  copyright : (C) 2020 by Alexis Roy-Lizotte
6  email : roya2 at premiertech 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 #include "qgsfeature.h"
24 #include "qgsfeaturesource.h"
25 
27 
28 
29 void QgsJoinByLocationAlgorithm::initAlgorithm( const QVariantMap & )
30 {
31  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
32  QObject::tr( "Base Layer" ), QList< int > () << QgsProcessing::QgsProcessing::TypeVectorAnyGeometry ) );
33  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "JOIN" ),
34  QObject::tr( "Join Layer" ), QList< int > () << QgsProcessing::QgsProcessing::TypeVectorAnyGeometry ) );
35 
36  QStringList predicates;
37  predicates << QObject::tr( "intersects" )
38  << QObject::tr( "contains" )
39  << QObject::tr( "equals" )
40  << QObject::tr( "touches" )
41  << QObject::tr( "overlaps" )
42  << QObject::tr( "within" )
43  << QObject::tr( "crosses" );
44 
45  std::unique_ptr< QgsProcessingParameterEnum > predicateParam = qgis::make_unique< QgsProcessingParameterEnum >( QStringLiteral( "PREDICATE" ), QObject::tr( "Geometric predicate" ), predicates, true, 0 );
46  QVariantMap predicateMetadata;
47  QVariantMap widgetMetadata;
48  widgetMetadata.insert( QStringLiteral( "useCheckBoxes" ), true );
49  widgetMetadata.insert( QStringLiteral( "columns" ), 2 );
50  predicateMetadata.insert( QStringLiteral( "widget_wrapper" ), widgetMetadata );
51  predicateParam->setMetadata( predicateMetadata );
52  addParameter( predicateParam.release() );
53  addParameter( new QgsProcessingParameterField( QStringLiteral( "JOIN_FIELDS" ),
54  QObject::tr( "Fields to add (leave empty to use all fields)" ),
55  QVariant(), QStringLiteral( "JOIN" ), QgsProcessingParameterField::Any, true, true ) );
56 
57  QStringList joinMethods;
58  joinMethods << QObject::tr( "Create separate feature for each matching feature (one-to-many)" )
59  << QObject::tr( "Take attributes of the first matching feature only (one-to-one)" )
60  << QObject::tr( "Take attributes of the feature with largest overlap only (one-to-one)" );
61  addParameter( new QgsProcessingParameterEnum( QStringLiteral( "METHOD" ),
62  QObject::tr( "Join type" ),
63  joinMethods, false, static_cast< int >( OneToMany ) ) );
64  addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "DISCARD_NONMATCHING" ),
65  QObject::tr( "Discard records which could not be joined" ),
66  false ) );
67  addParameter( new QgsProcessingParameterString( QStringLiteral( "PREFIX" ),
68  QObject::tr( "Joined field prefix" ), QVariant(), false, true ) );
69  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Joined layer" ), QgsProcessing::TypeVectorAnyGeometry, QVariant(), true, true ) );
70  addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "NON_MATCHING" ), QObject::tr( "Unjoinable features from first layer" ), QgsProcessing::TypeVectorAnyGeometry, QVariant(), true, false ) );
71  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "JOINED_COUNT" ), QObject::tr( "Number of joined features from input table" ) ) );
72 }
73 
74 QString QgsJoinByLocationAlgorithm::name() const
75 {
76  return QStringLiteral( "joinattributesbylocation" );
77 }
78 
79 QString QgsJoinByLocationAlgorithm::displayName() const
80 {
81  return QObject::tr( "Join attributes by location" );
82 }
83 
84 QStringList QgsJoinByLocationAlgorithm::tags() const
85 {
86  return QObject::tr( "join,intersects,intersecting,touching,within,contains,overlaps,relation,spatial" ).split( ',' );
87 }
88 
89 QString QgsJoinByLocationAlgorithm::group() const
90 {
91  return QObject::tr( "Vector general" );
92 }
93 
94 QString QgsJoinByLocationAlgorithm::groupId() const
95 {
96  return QStringLiteral( "vectorgeneral" );
97 }
98 
99 QString QgsJoinByLocationAlgorithm::shortHelpString() const
100 {
101  return QObject::tr( "This algorithm takes an input vector layer and creates a new vector layer "
102  "that is an extended version of the input one, with additional attributes in its attribute table.\n\n"
103  "The additional attributes and their values are taken from a second vector layer. "
104  "A spatial criteria is applied to select the values from the second layer that are added "
105  "to each feature from the first layer in the resulting one." );
106 }
107 
108 QString QgsJoinByLocationAlgorithm::shortDescription() const
109 {
110  return QObject::tr( "Join attributes from one vector layer to another by location." );
111 }
112 
113 QgsJoinByLocationAlgorithm *QgsJoinByLocationAlgorithm::createInstance() const
114 {
115  return new QgsJoinByLocationAlgorithm();
116 }
117 
118 
119 QVariantMap QgsJoinByLocationAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
120 {
121  mBaseSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
122  if ( !mBaseSource )
123  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
124 
125  mJoinSource.reset( parameterAsSource( parameters, QStringLiteral( "JOIN" ), context ) );
126  if ( !mJoinSource )
127  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "JOIN" ) ) );
128 
129  mJoinMethod = static_cast< JoinMethod >( parameterAsEnum( parameters, QStringLiteral( "METHOD" ), context ) );
130 
131  const QStringList joinedFieldNames = parameterAsFields( parameters, QStringLiteral( "JOIN_FIELDS" ), context );
132 
133  mPredicates = parameterAsEnums( parameters, QStringLiteral( "PREDICATE" ), context );
134  sortPredicates( mPredicates );
135 
136  QString prefix = parameterAsString( parameters, QStringLiteral( "PREFIX" ), context );
137 
138  QgsFields joinFields;
139  if ( joinedFieldNames.empty() )
140  {
141  joinFields = mJoinSource->fields();
142  mJoinedFieldIndices = joinFields.allAttributesList();
143  }
144  else
145  {
146  mJoinedFieldIndices.reserve( joinedFieldNames.count() );
147  for ( const QString &field : joinedFieldNames )
148  {
149  int index = mJoinSource->fields().lookupField( field );
150  if ( index >= 0 )
151  {
152  mJoinedFieldIndices << index;
153  joinFields.append( mJoinSource->fields().at( index ) );
154  }
155  }
156  }
157 
158  if ( !prefix.isEmpty() )
159  {
160  for ( int i = 0; i < joinFields.count(); ++i )
161  {
162  joinFields.rename( i, prefix + joinFields[ i ].name() );
163  }
164  }
165 
166  const QgsFields outputFields = QgsProcessingUtils::combineFields( mBaseSource->fields(), joinFields );
167 
168  QString joinedSinkId;
169  mJoinedFeatures.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, joinedSinkId, outputFields,
170  mBaseSource->wkbType(), mBaseSource->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
171 
172  if ( parameters.value( QStringLiteral( "OUTPUT" ) ).isValid() && !mJoinedFeatures )
173  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
174 
175  mDiscardNonMatching = parameterAsBoolean( parameters, QStringLiteral( "DISCARD_NONMATCHING" ), context );
176 
177  QString nonMatchingSinkId;
178  mUnjoinedFeatures.reset( parameterAsSink( parameters, QStringLiteral( "NON_MATCHING" ), context, nonMatchingSinkId, mBaseSource->fields(),
179  mBaseSource->wkbType(), mBaseSource->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) );
180  if ( parameters.value( QStringLiteral( "NON_MATCHING" ) ).isValid() && !mUnjoinedFeatures )
181  throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "NON_MATCHING" ) ) );
182 
183  switch ( mJoinMethod )
184  {
185  case OneToMany:
186  case JoinToFirst:
187  {
188  if ( mBaseSource->featureCount() > 0 && mJoinSource->featureCount() > 0 && mBaseSource->featureCount() < mJoinSource->featureCount() )
189  {
190  // joining FEWER features to a layer with MORE features. So we iterate over the FEW features and find matches from the MANY
191  processAlgorithmByIteratingOverInputSource( context, feedback );
192  }
193  else
194  {
195  // default -- iterate over the join source and match back to the base source. We do this on the assumption that the most common
196  // use case is joining a points layer to a polygon layer (taking polygon attributes and adding them to the points), so by iterating
197  // over the polygons we can take advantage of prepared geometries for the spatial relationship test.
198 
199  // TODO - consider using more heuristics to determine whether it's always best to iterate over the join
200  // source.
201  processAlgorithmByIteratingOverJoinedSource( context, feedback );
202  }
203  break;
204  }
205 
206  case JoinToLargestOverlap:
207  processAlgorithmByIteratingOverInputSource( context, feedback );
208  break;
209  }
210 
211  QVariantMap outputs;
212  if ( mJoinedFeatures )
213  {
214  outputs.insert( QStringLiteral( "OUTPUT" ), joinedSinkId );
215  }
216  if ( mUnjoinedFeatures )
217  {
218  outputs.insert( QStringLiteral( "NON_MATCHING" ), nonMatchingSinkId );
219  }
220 
221  // need to release sinks to finalize writing
222  mJoinedFeatures.reset();
223  mUnjoinedFeatures.reset();
224 
225  outputs.insert( QStringLiteral( "JOINED_COUNT" ), static_cast< long long >( mJoinedCount ) );
226  return outputs;
227 }
228 
229 bool QgsJoinByLocationAlgorithm::featureFilter( const QgsFeature &feature, QgsGeometryEngine *engine, bool comparingToJoinedFeature ) const
230 {
231  const QgsAbstractGeometry *geom = feature.geometry().constGet();
232  bool ok = false;
233  for ( const int predicate : mPredicates )
234  {
235  switch ( predicate )
236  {
237  case 0:
238  // intersects
239  if ( engine->intersects( geom ) )
240  {
241  ok = true;
242  }
243  break;
244  case 1:
245  // contains
246  if ( comparingToJoinedFeature )
247  {
248  if ( engine->contains( geom ) )
249  {
250  ok = true;
251  }
252  }
253  else
254  {
255  if ( engine->within( geom ) )
256  {
257  ok = true;
258  }
259  }
260  break;
261  case 2:
262  // equals
263  if ( engine->isEqual( geom ) )
264  {
265  ok = true;
266  }
267  break;
268  case 3:
269  // touches
270  if ( engine->touches( geom ) )
271  {
272  ok = true;
273  }
274  break;
275  case 4:
276  // overlaps
277  if ( engine->overlaps( geom ) )
278  {
279  ok = true;
280  }
281  break;
282  case 5:
283  // within
284  if ( comparingToJoinedFeature )
285  {
286  if ( engine->within( geom ) )
287  {
288  ok = true;
289  }
290  }
291  else
292  {
293  if ( engine->contains( geom ) )
294  {
295  ok = true;
296  }
297  }
298  break;
299  case 6:
300  // crosses
301  if ( engine->crosses( geom ) )
302  {
303  ok = true;
304  }
305  break;
306  }
307  if ( ok )
308  return ok;
309  }
310  return ok;
311 }
312 
313 void QgsJoinByLocationAlgorithm::processAlgorithmByIteratingOverJoinedSource( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
314 {
315  if ( mBaseSource->hasSpatialIndex() == QgsFeatureSource::SpatialIndexNotPresent )
316  feedback->reportError( QObject::tr( "No spatial index exists for input layer, performance will be severely degraded" ) );
317 
318  QgsFeatureIterator joinIter = mJoinSource->getFeatures( QgsFeatureRequest().setDestinationCrs( mBaseSource->sourceCrs(), context.transformContext() ).setSubsetOfAttributes( mJoinedFieldIndices ) );
319  QgsFeature f;
320 
321  // Create output vector layer with additional attributes
322  const double step = mJoinSource->featureCount() > 0 ? 100.0 / mJoinSource->featureCount() : 1;
323  long i = 0;
324  while ( joinIter.nextFeature( f ) )
325  {
326  if ( feedback->isCanceled() )
327  break;
328 
329  processFeatureFromJoinSource( f, feedback );
330 
331  i++;
332  feedback->setProgress( i * step );
333  }
334 
335  if ( !mDiscardNonMatching || mUnjoinedFeatures )
336  {
337  QgsFeatureIds unjoinedIds = mBaseSource->allFeatureIds();
338  unjoinedIds.subtract( mAddedIds );
339 
340  QgsFeature f2;
341  QgsFeatureRequest remainings = QgsFeatureRequest().setFilterFids( unjoinedIds );
342  QgsFeatureIterator remainIter = mBaseSource->getFeatures( remainings );
343 
344  QgsAttributes emptyAttributes;
345  emptyAttributes.reserve( mJoinedFieldIndices.count() );
346  for ( int i = 0; i < mJoinedFieldIndices.count(); ++i )
347  emptyAttributes << QVariant();
348 
349  while ( remainIter.nextFeature( f2 ) )
350  {
351  if ( feedback->isCanceled() )
352  break;
353 
354  if ( mJoinedFeatures && !mDiscardNonMatching )
355  {
356  QgsAttributes attributes = f2.attributes();
357  attributes.append( emptyAttributes );
358  QgsFeature outputFeature( f2 );
359  outputFeature.setAttributes( attributes );
360  mJoinedFeatures->addFeature( outputFeature, QgsFeatureSink::FastInsert );
361  }
362 
363  if ( mUnjoinedFeatures )
364  mUnjoinedFeatures->addFeature( f2, QgsFeatureSink::FastInsert );
365  }
366  }
367 }
368 
369 void QgsJoinByLocationAlgorithm::processAlgorithmByIteratingOverInputSource( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
370 {
371  if ( mJoinSource->hasSpatialIndex() == QgsFeatureSource::SpatialIndexNotPresent )
372  feedback->reportError( QObject::tr( "No spatial index exists for join layer, performance will be severely degraded" ) );
373 
374  QgsFeatureIterator it = mBaseSource->getFeatures();
375  QgsFeature f;
376 
377  const double step = mBaseSource->featureCount() > 0 ? 100.0 / mBaseSource->featureCount() : 1;
378  long i = 0;
379  while ( it .nextFeature( f ) )
380  {
381  if ( feedback->isCanceled() )
382  break;
383 
384  processFeatureFromInputSource( f, context, feedback );
385 
386  i++;
387  feedback->setProgress( i * step );
388  }
389 }
390 
391 void QgsJoinByLocationAlgorithm::sortPredicates( QList<int> &predicates )
392 {
393  // Sort predicate list so that faster predicates are earlier in the list
394  // Some predicates in GEOS do not have prepared geometry implementations, and are slow to calculate. So if users
395  // are testing multiple predicates, make sure the optimised ones are always tested first just in case we can shortcut
396  // these slower ones
397 
398  std::sort( predicates.begin(), predicates.end(), []( int a, int b ) -> bool
399  {
400  // return true if predicate a is faster than b
401 
402  if ( a == 0 ) // intersects is fastest
403  return true;
404  else if ( b == 0 )
405  return false;
406 
407  else if ( a == 5 ) // contains is fast for polygons
408  return true;
409  else if ( b == 5 )
410  return false;
411 
412  // that's it, the rest don't have optimised prepared methods (as of GEOS 3.8)
413  return a < b;
414  } );
415 }
416 
417 bool QgsJoinByLocationAlgorithm::processFeatureFromJoinSource( QgsFeature &joinFeature, QgsProcessingFeedback *feedback )
418 {
419  if ( !joinFeature.hasGeometry() )
420  return false;
421 
422  const QgsGeometry featGeom = joinFeature.geometry();
423  std::unique_ptr< QgsGeometryEngine > engine;
425  QgsFeatureIterator it = mBaseSource->getFeatures( req );
426  QList<QgsFeature> filtered;
427  QgsFeature baseFeature;
428  bool ok = false;
429  QgsAttributes joinAttributes;
430 
431  while ( it.nextFeature( baseFeature ) )
432  {
433  if ( feedback->isCanceled() )
434  break;
435 
436  switch ( mJoinMethod )
437  {
438  case JoinToFirst:
439  if ( mAddedIds.contains( baseFeature.id() ) )
440  {
441  // already added this feature, and user has opted to only output first match
442  continue;
443  }
444  break;
445 
446  case OneToMany:
447  break;
448 
449  case JoinToLargestOverlap:
450  Q_ASSERT_X( false, "QgsJoinByLocationAlgorithm::processFeatureFromJoinSource", "processFeatureFromJoinSource should not be used with join to largest overlap method" );
451  }
452 
453  if ( !engine )
454  {
455  engine.reset( QgsGeometry::createGeometryEngine( featGeom.constGet() ) );
456  engine->prepareGeometry();
457  for ( int ix : qgis::as_const( mJoinedFieldIndices ) )
458  {
459  joinAttributes.append( joinFeature.attribute( ix ) );
460  }
461  }
462  if ( featureFilter( baseFeature, engine.get(), false ) )
463  {
464  if ( mJoinedFeatures )
465  {
466  QgsFeature outputFeature( baseFeature );
467  outputFeature.setAttributes( baseFeature.attributes() + joinAttributes );
468  mJoinedFeatures->addFeature( outputFeature, QgsFeatureSink::FastInsert );
469  }
470  if ( !ok )
471  ok = true;
472 
473  mAddedIds.insert( baseFeature.id() );
474  mJoinedCount++;
475  }
476  }
477  return ok;
478 }
479 
480 bool QgsJoinByLocationAlgorithm::processFeatureFromInputSource( QgsFeature &baseFeature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
481 {
482  if ( !baseFeature.hasGeometry() )
483  {
484  // no geometry, treat as if we didn't find a match...
485  if ( mJoinedFeatures && !mDiscardNonMatching )
486  {
487  QgsAttributes emptyAttributes;
488  emptyAttributes.reserve( mJoinedFieldIndices.count() );
489  for ( int i = 0; i < mJoinedFieldIndices.count(); ++i )
490  emptyAttributes << QVariant();
491 
492  QgsAttributes attributes = baseFeature.attributes();
493  attributes.append( emptyAttributes );
494  QgsFeature outputFeature( baseFeature );
495  outputFeature.setAttributes( attributes );
496  mJoinedFeatures->addFeature( outputFeature, QgsFeatureSink::FastInsert );
497  }
498 
499  if ( mUnjoinedFeatures )
500  mUnjoinedFeatures->addFeature( baseFeature, QgsFeatureSink::FastInsert );
501 
502  return false;
503  }
504 
505  const QgsGeometry featGeom = baseFeature.geometry();
506  std::unique_ptr< QgsGeometryEngine > engine;
507  QgsFeatureRequest req = QgsFeatureRequest().setDestinationCrs( mBaseSource->sourceCrs(), context.transformContext() ).setFilterRect( featGeom.boundingBox() ).setSubsetOfAttributes( mJoinedFieldIndices );
508 
509  QgsFeatureIterator it = mJoinSource->getFeatures( req );
510  QList<QgsFeature> filtered;
511  QgsFeature joinFeature;
512  bool ok = false;
513 
514  double largestOverlap = std::numeric_limits< double >::lowest();
515  QgsFeature bestMatch;
516 
517  while ( it.nextFeature( joinFeature ) )
518  {
519  if ( feedback->isCanceled() )
520  break;
521 
522  if ( !engine )
523  {
524  engine.reset( QgsGeometry::createGeometryEngine( featGeom.constGet() ) );
525  engine->prepareGeometry();
526  }
527 
528  if ( featureFilter( joinFeature, engine.get(), true ) )
529  {
530  switch ( mJoinMethod )
531  {
532  case JoinToFirst:
533  case OneToMany:
534  if ( mJoinedFeatures )
535  {
536  QgsAttributes joinAttributes = baseFeature.attributes();
537  joinAttributes.reserve( joinAttributes.size() + mJoinedFieldIndices.size() );
538  for ( int ix : qgis::as_const( mJoinedFieldIndices ) )
539  {
540  joinAttributes.append( joinFeature.attribute( ix ) );
541  }
542 
543  QgsFeature outputFeature( baseFeature );
544  outputFeature.setAttributes( joinAttributes );
545  mJoinedFeatures->addFeature( outputFeature, QgsFeatureSink::FastInsert );
546  }
547  break;
548 
549  case JoinToLargestOverlap:
550  {
551  // calculate area of overlap
552  std::unique_ptr< QgsAbstractGeometry > intersection( engine->intersection( joinFeature.geometry().constGet() ) );
553  double overlap = 0;
554  switch ( QgsWkbTypes::geometryType( intersection->wkbType() ) )
555  {
557  overlap = intersection->length();
558  break;
559 
561  overlap = intersection->area();
562  break;
563 
567  break;
568  }
569 
570  if ( overlap > largestOverlap )
571  {
572  largestOverlap = overlap;
573  bestMatch = joinFeature;
574  }
575  break;
576  }
577  }
578 
579  ok = true;
580 
581  if ( mJoinMethod == JoinToFirst )
582  break;
583  }
584  }
585 
586  switch ( mJoinMethod )
587  {
588  case OneToMany:
589  case JoinToFirst:
590  break;
591 
592  case JoinToLargestOverlap:
593  {
594  if ( bestMatch.isValid() )
595  {
596  // grab attributes from feature with best match
597  if ( mJoinedFeatures )
598  {
599  QgsAttributes joinAttributes = baseFeature.attributes();
600  joinAttributes.reserve( joinAttributes.size() + mJoinedFieldIndices.size() );
601  for ( int ix : qgis::as_const( mJoinedFieldIndices ) )
602  {
603  joinAttributes.append( bestMatch.attribute( ix ) );
604  }
605 
606  QgsFeature outputFeature( baseFeature );
607  outputFeature.setAttributes( joinAttributes );
608  mJoinedFeatures->addFeature( outputFeature, QgsFeatureSink::FastInsert );
609  }
610  }
611  else
612  {
613  ok = false; // shouldn't happen...
614  }
615  break;
616  }
617  }
618 
619  if ( !ok )
620  {
621  // didn't find a match...
622  if ( mJoinedFeatures && !mDiscardNonMatching )
623  {
624  QgsAttributes emptyAttributes;
625  emptyAttributes.reserve( mJoinedFieldIndices.count() );
626  for ( int i = 0; i < mJoinedFieldIndices.count(); ++i )
627  emptyAttributes << QVariant();
628 
629  QgsAttributes attributes = baseFeature.attributes();
630  attributes.append( emptyAttributes );
631  QgsFeature outputFeature( baseFeature );
632  outputFeature.setAttributes( attributes );
633  mJoinedFeatures->addFeature( outputFeature, QgsFeatureSink::FastInsert );
634  }
635 
636  if ( mUnjoinedFeatures )
637  mUnjoinedFeatures->addFeature( baseFeature, QgsFeatureSink::FastInsert );
638  }
639  else
640  mJoinedCount++;
641 
642  return ok;
643 }
644 
645 
647 
648 
649 
A boolean parameter for processing algorithms.
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature&#39;s geometries.
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
No spatial index exists for the source.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
virtual bool crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom crosses this.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
Base class for providing feedback from a processing algorithm.
virtual bool within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom is within this.
A vector layer or feature source field parameter for processing algorithms.
virtual bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom touches this.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:64
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
A numeric output for processing algorithms.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
bool rename(int fieldIdx, const QString &name)
Renames a name of field.
Definition: qgsfields.cpp:72
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
A feature sink output for processing algorithms.
virtual bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom intersects this.
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:351
An enum based parameter for processing algorithms, allowing for selection from predefined values...
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:812
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
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
Abstract base class for all geometries.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
virtual bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom overlaps this.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:55
An input feature source (such as vector layers) parameter for processing algorithms.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
virtual bool contains(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom contains this.
Contains geometry relation and modification algorithms.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
QgsGeometry geometry
Definition: qgsfeature.h:67
bool nextFeature(QgsFeature &f)
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
A vector of attributes.
Definition: qgsattributes.h:57
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
Contains information about the context in which a processing algorithm is executed.
A string parameter for processing algorithms.
Any vector layer with geometry.
Definition: qgsprocessing.h:47
QgsAttributes attributes
Definition: qgsfeature.h:65
virtual bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if this is equal to geom.