QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 = std::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->pushWarning( 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->pushWarning( 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 : std::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 : std::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 : std::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 
Abstract base class for all geometries.
A vector of attributes.
Definition: qgsattributes.h:58
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
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.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
@ SpatialIndexNotPresent
No spatial index exists for the source.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:191
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:371
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
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
bool rename(int fieldIdx, const QString &name)
Renames a name of field.
Definition: qgsfields.cpp:72
A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use wi...
virtual bool isEqual(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if this is equal to geom.
virtual bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom intersects this.
virtual bool touches(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom touches this.
virtual bool crosses(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom crosses this.
virtual bool overlaps(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom overlaps this.
virtual bool within(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom is within this.
virtual bool contains(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const =0
Checks if geom contains this.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
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.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
A numeric output for processing algorithms.
A boolean parameter for processing algorithms.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A feature sink output for processing algorithms.
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.
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).
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
const QgsField & field
Definition: qgsfield.h:463