QGIS API Documentation  3.21.0-Master (909859188c)
qgsfeaturerequest.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfeaturerequest.cpp
3  ---------------------
4  begin : Mai 2012
5  copyright : (C) 2012 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include "qgsfeaturerequest.h"
16 
17 #include "qgsfields.h"
18 #include "qgsgeometry.h"
19 #include "qgsgeometryengine.h"
20 
21 #include <QStringList>
22 
23 //constants
24 const QString QgsFeatureRequest::ALL_ATTRIBUTES = QStringLiteral( "#!allattributes!#" );
25 
27 {
28 }
29 
31 
33  : mFilter( FilterFid )
34  , mFilterFid( fid )
35 {
36 }
37 
39  : mFilter( FilterFids )
40  , mFilterFids( fids )
41 {
42 
43 }
44 
46  : mSpatialFilter( !rect.isNull() ? Qgis::SpatialFilterType::BoundingBox : Qgis::SpatialFilterType::NoFilter )
47  , mFilterRect( rect )
48 {
49 }
50 
52  : mFilter( FilterExpression )
53  , mFilterExpression( new QgsExpression( expr ) )
54  , mExpressionContext( context )
55 {
56 }
57 
59 {
60  operator=( rh );
61 }
62 
64 {
65  if ( &rh == this )
66  return *this;
67 
68  mFlags = rh.mFlags;
69  mFilter = rh.mFilter;
73  if ( !mReferenceGeometry.isEmpty() )
74  {
76  mReferenceGeometryEngine->prepareGeometry();
77  }
81  if ( rh.mFilterExpression )
82  {
84  }
85  else
86  {
87  mFilterExpression.reset( nullptr );
88  }
92  mAttrs = rh.mAttrs;
94  mLimit = rh.mLimit;
95  mOrderBy = rh.mOrderBy;
96  mCrs = rh.mCrs;
99  mTimeout = rh.mTimeout;
101  mFeedback = rh.mFeedback;
102  return *this;
103 }
104 
106 {
107  mFilterRect = rect;
109  mDistanceWithin = 0;
110  if ( mFilterRect.isNull() )
111  {
113  }
114  else
115  {
117  }
118  return *this;
119 }
120 
122 {
123  return mFilterRect;
124 }
125 
127 {
128  mReferenceGeometry = geometry;
129  if ( !mReferenceGeometry.isEmpty() )
130  {
132  mReferenceGeometryEngine->prepareGeometry();
133  }
134  else
135  {
136  mReferenceGeometryEngine.reset();
137  }
138  mDistanceWithin = distance;
141 
142  return *this;
143 }
144 
146 {
147  mFilter = FilterFid;
148  mFilterFid = fid;
149  return *this;
150 }
151 
153 {
155  mFilterFids = fids;
156  return *this;
157 }
158 
160 {
161  mInvalidGeometryFilter = check;
162  return *this;
163 }
164 
165 QgsFeatureRequest &QgsFeatureRequest::setInvalidGeometryCallback( const std::function<void ( const QgsFeature & )> &callback )
166 {
167  mInvalidGeometryCallback = callback;
168  return *this;
169 }
170 
172 {
174  mFilterExpression.reset( new QgsExpression( expression ) );
175  return *this;
176 }
177 
179 {
180  if ( mFilterExpression )
181  {
182  setFilterExpression( QStringLiteral( "(%1) AND (%2)" ).arg( mFilterExpression->expression(), expression ) );
183  }
184  else
185  {
186  setFilterExpression( expression );
187  }
188  return *this;
189 }
190 
192 {
193  mExpressionContext = context;
194  return *this;
195 }
196 
197 QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending )
198 {
199  mOrderBy.append( OrderByClause( expression, ascending ) );
200  return *this;
201 }
202 
203 QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending, bool nullsfirst )
204 {
205  mOrderBy.append( OrderByClause( expression, ascending, nullsfirst ) );
206  return *this;
207 }
208 
210 {
211  return mOrderBy;
212 }
213 
215 {
216  mOrderBy = orderBy;
217  return *this;
218 }
219 
221 {
222  mLimit = limit;
223  return *this;
224 }
225 
226 QgsFeatureRequest &QgsFeatureRequest::setFlags( QgsFeatureRequest::Flags flags )
227 {
228  mFlags = flags;
229  return *this;
230 }
231 
233 {
235  mAttrs = attrs;
236  return *this;
237 }
238 
240 {
242 }
243 
244 QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QStringList &attrNames, const QgsFields &fields )
245 {
246  if ( attrNames.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) )
247  {
248  //attribute string list contains the all attributes flag, so we must fetch all attributes
249  return *this;
250  }
251 
253  mAttrs.clear();
254 
255  const auto constAttrNames = attrNames;
256  for ( const QString &attrName : constAttrNames )
257  {
258  const int attrNum = fields.lookupField( attrName );
259  if ( attrNum != -1 && !mAttrs.contains( attrNum ) )
260  mAttrs.append( attrNum );
261  }
262 
263  return *this;
264 }
265 
266 QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QSet<QString> &attrNames, const QgsFields &fields )
267 {
268  if ( attrNames.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) )
269  {
270  //attribute string list contains the all attributes flag, so we must fetch all attributes
271  return *this;
272  }
273 
275  mAttrs.clear();
276 
277  const auto constAttrNames = attrNames;
278  for ( const QString &attrName : constAttrNames )
279  {
280  const int attrNum = fields.lookupField( attrName );
281  if ( attrNum != -1 && !mAttrs.contains( attrNum ) )
282  mAttrs.append( attrNum );
283  }
284 
285  return *this;
286 }
287 
289 {
291  return *this;
292 }
293 
294 
296 {
297  return mCrs;
298 }
299 
301 {
302  return mTransformContext;
303 }
304 
306 {
307  mCrs = crs;
308  mTransformContext = context;
309  return *this;
310 }
311 
312 QgsFeatureRequest &QgsFeatureRequest::setTransformErrorCallback( const std::function<void ( const QgsFeature & )> &callback )
313 {
314  mTransformErrorCallback = callback;
315  return *this;
316 }
317 
319 {
320  // check the attribute/id filter first, it's more likely to be faster than
321  // the spatial filter
322  switch ( mFilter )
323  {
325  break;
326 
328  if ( feature.id() != mFilterFid )
329  return false;
330  break;
331 
333  mExpressionContext.setFeature( feature );
334  if ( !mFilterExpression->evaluate( &mExpressionContext ).toBool() )
335  return false;
336  break;
337 
339  if ( !mFilterFids.contains( feature.id() ) )
340  return false;
341  break;
342  }
343 
344  switch ( mSpatialFilter )
345  {
347  break;
348 
350  if ( !feature.hasGeometry() ||
351  (
352  ( mFlags & ExactIntersect && !feature.geometry().intersects( mFilterRect ) )
353  ||
355  )
356  )
357  return false;
358  break;
359 
361  if ( !feature.hasGeometry()
364  || mReferenceGeometryEngine->distance( feature.geometry().constGet() ) > mDistanceWithin
365  )
366  return false;
367  break;
368  }
369 
370  return true;
371 }
372 
374 {
375  return mTimeout;
376 }
377 
379 {
381  return *this;
382 }
383 
385 {
386  return mTimeout;
387 }
388 
390 {
391  mTimeout = timeout;
392  return *this;
393 }
394 
396 {
397  return mRequestMayBeNested;
398 }
399 
401 {
403  return *this;
404 }
405 
407 {
409 }
410 
412 {
413  return mFeedback;
414 }
415 
416 
417 #include "qgsfeatureiterator.h"
418 #include "qgslogger.h"
419 
421 {
422  while ( !mActiveIterators.empty() )
423  {
425  QgsDebugMsgLevel( QStringLiteral( "closing active iterator" ), 2 );
426  it->close();
427  }
428 }
429 
431 {
432  mActiveIterators.insert( it );
433 }
434 
436 {
437  mActiveIterators.remove( it );
438 }
439 
440 
441 
442 QgsFeatureRequest::OrderByClause::OrderByClause( const QString &expression, bool ascending )
443  : mExpression( expression )
444  , mAscending( ascending )
445 {
446  // postgres behavior: default for ASC: NULLS LAST, default for DESC: NULLS FIRST
447  mNullsFirst = !ascending;
448 }
449 
450 QgsFeatureRequest::OrderByClause::OrderByClause( const QString &expression, bool ascending, bool nullsfirst )
451  : mExpression( expression )
452  , mAscending( ascending )
453  , mNullsFirst( nullsfirst )
454 {
455 }
456 
458  : mExpression( expression )
459  , mAscending( ascending )
460 {
461  // postgres behavior: default for ASC: NULLS LAST, default for DESC: NULLS FIRST
462  mNullsFirst = !ascending;
463 }
464 
465 QgsFeatureRequest::OrderByClause::OrderByClause( const QgsExpression &expression, bool ascending, bool nullsfirst )
466  : mExpression( expression )
467  , mAscending( ascending )
468  , mNullsFirst( nullsfirst )
469 {
470 
471 }
472 
474 {
475  return mAscending;
476 }
477 
479 {
480  mAscending = ascending;
481 }
482 
484 {
485  return mNullsFirst;
486 }
487 
489 {
490  mNullsFirst = nullsFirst;
491 }
492 
494 {
495  return QStringLiteral( "%1 %2 %3" )
496  .arg( mExpression.expression(),
497  mAscending ? "ASC" : "DESC",
498  mNullsFirst ? "NULLS FIRST" : "NULLS LAST" );
499 }
500 
502 {
503  return mExpression;
504 }
505 
507 {
508  return mExpression.prepare( context );
509 }
510 
512 
513 QgsFeatureRequest::OrderBy::OrderBy( const QList<QgsFeatureRequest::OrderByClause> &other )
514 {
515  const auto constOther = other;
516  for ( const QgsFeatureRequest::OrderByClause &clause : constOther )
517  {
518  append( clause );
519  }
520 }
521 
522 QList<QgsFeatureRequest::OrderByClause> QgsFeatureRequest::OrderBy::list() const
523 {
524  return *this;
525 }
526 
527 void QgsFeatureRequest::OrderBy::save( QDomElement &elem ) const
528 {
529  QDomDocument doc = elem.ownerDocument();
530  QList<OrderByClause>::ConstIterator it;
531  for ( it = constBegin(); it != constEnd(); ++it )
532  {
533  const OrderByClause &clause = *it;
534  QDomElement clauseElem = doc.createElement( QStringLiteral( "orderByClause" ) );
535  clauseElem.setAttribute( QStringLiteral( "asc" ), clause.ascending() );
536  clauseElem.setAttribute( QStringLiteral( "nullsFirst" ), clause.nullsFirst() );
537  clauseElem.appendChild( doc.createTextNode( clause.expression().expression() ) );
538 
539  elem.appendChild( clauseElem );
540  }
541 }
542 
543 void QgsFeatureRequest::OrderBy::load( const QDomElement &elem )
544 {
545  clear();
546 
547  const QDomNodeList clauses = elem.childNodes();
548 
549  for ( int i = 0; i < clauses.size(); ++i )
550  {
551  const QDomElement clauseElem = clauses.at( i ).toElement();
552  const QString expression = clauseElem.text();
553  const bool asc = clauseElem.attribute( QStringLiteral( "asc" ) ).toInt() != 0;
554  const bool nullsFirst = clauseElem.attribute( QStringLiteral( "nullsFirst" ) ).toInt() != 0;
555 
556  append( OrderByClause( expression, asc, nullsFirst ) );
557  }
558 }
559 
561 {
562  QSet<QString> usedAttributes;
563 
564  QList<OrderByClause>::ConstIterator it;
565  for ( it = constBegin(); it != constEnd(); ++it )
566  {
567  const OrderByClause &clause = *it;
568 
569  usedAttributes.unite( clause.expression().referencedColumns() );
570  }
571 
572  return usedAttributes;
573 }
574 
576 {
577  QSet<int> usedAttributeIdx;
578  for ( const OrderByClause &clause : *this )
579  {
580  const auto referencedColumns = clause.expression().referencedColumns();
581  for ( const QString &fieldName : referencedColumns )
582  {
583  const int idx = fields.lookupField( fieldName );
584  if ( idx >= 0 )
585  {
586  usedAttributeIdx.insert( idx );
587  }
588  }
589  }
590  return usedAttributeIdx;
591 }
592 
594 {
595  QStringList results;
596 
597  QList<OrderByClause>::ConstIterator it;
598  for ( it = constBegin(); it != constEnd(); ++it )
599  {
600  const OrderByClause &clause = *it;
601 
602  results << clause.dump();
603  }
604 
605  return results.join( QLatin1String( ", " ) );
606 }
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:63
@ DistanceWithin
Filter by distance to reference geometry.
@ BoundingBox
Filter using a bounding box.
@ NoFilter
No spatial filtering of features.
Internal feature iterator to be implemented within data providers.
virtual bool close()=0
end of iterating: free the resources / lock
void iteratorOpened(QgsAbstractFeatureIterator *it)
void iteratorClosed(QgsAbstractFeatureIterator *it)
QSet< QgsAbstractFeatureIterator * > mActiveIterators
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
QString expression() const
Returns the original, unmodified expression string.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The OrderByClause class represents an order by clause for a QgsFeatureRequest.
OrderByClause(const QString &expression, bool ascending=true)
Creates a new OrderByClause for a QgsFeatureRequest.
QString dump() const
Dumps the content to an SQL equivalent.
QgsExpression expression() const
The expression.
bool ascending() const
Order ascending.
bool nullsFirst() const
Set if NULLS should be returned first.
void setAscending(bool ascending)
Set if ascending order is requested.
bool prepare(QgsExpressionContext *context)
Prepare the expression with the given context.
void setNullsFirst(bool nullsFirst)
Set if NULLS should be returned first.
Represents a list of OrderByClauses, with the most important first and the least important last.
QSet< int > CORE_EXPORT usedAttributeIndices(const QgsFields &fields) const
Returns a set of used, validated attribute indices.
QSet< QString > CORE_EXPORT usedAttributes() const
Returns a set of used attributes.
void CORE_EXPORT load(const QDomElement &elem)
Deserialize from XML.
QList< QgsFeatureRequest::OrderByClause > CORE_EXPORT list() const
Gets a copy as a list of OrderByClauses.
QString CORE_EXPORT dump() const
Dumps the content to an SQL equivalent syntax.
CORE_EXPORT OrderBy()
Create a new empty order by.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
std::unique_ptr< QgsExpression > mFilterExpression
QgsCoordinateReferenceSystem mCrs
std::unique_ptr< QgsGeometryEngine > mReferenceGeometryEngine
Prepared geometry engine for mReferenceGeometry.
const QgsSimplifyMethod & simplifyMethod() const
Returns the simplification method for geometries that will be fetched.
QgsFeatureRequest & setSimplifyMethod(const QgsSimplifyMethod &simplifyMethod)
Set a simplification method for geometries that will be fetched.
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
QgsCoordinateTransformContext mTransformContext
InvalidGeometryCheck
Handling of features with invalid geometries.
QgsFeatureId mFilterFid
Q_DECL_DEPRECATED QgsFeatureRequest & setConnectionTimeout(int connectionTimeout)
Sets the timeout (in milliseconds) for how long we should wait for a connection if none is available ...
FilterType mFilter
Attribute/ID filter type.
QgsRectangle mFilterRect
Bounding box for spatial filtering.
Qgis::SpatialFilterType mSpatialFilter
Spatial filter type.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the iterator to check if it should be ca...
QgsFeatureRequest & setRequestMayBeNested(bool requestMayBeNested)
In case this request may be run nested within another already running iteration on the same connectio...
long long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
QgsFeatureRequest & combineFilterExpression(const QString &expression)
Modifies the existing filter expression to add an additional expression filter.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
OrderBy orderBy() const
Returns a list of order by clauses specified for this feature request.
QgsFeatureIds mFilterFids
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsGeometry mReferenceGeometry
Reference geometry for Qgis::RequestSpatialFilter::DistanceWithin filtering.
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one.
QgsFeatureRequest & setTimeout(int timeout)
Sets the timeout (in milliseconds) for the maximum time we should wait during feature requests before...
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
Flags flags() const
Returns the flags which affect how features are fetched.
QgsExpressionContext mExpressionContext
QgsSimplifyMethod mSimplifyMethod
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
int timeout() const
Returns the timeout (in milliseconds) for the maximum time we should wait during feature requests bef...
InvalidGeometryCheck mInvalidGeometryFilter
QgsFeedback * mFeedback
std::function< void(const QgsFeature &) > mTransformErrorCallback
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the iterator to check if it should be cance...
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for feature's geometries, or an invalid QgsCoordi...
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
QgsAttributeList mAttrs
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
std::function< void(const QgsFeature &) > mInvalidGeometryCallback
Q_DECL_DEPRECATED int connectionTimeout() const
Returns the timeout (in milliseconds) for how long we should wait for a connection if none is availab...
QgsCoordinateTransformContext transformContext() const
Returns the transform context, for use when a destinationCrs() has been set and reprojection is requi...
QgsFeatureRequest & setInvalidGeometryCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering an invalid geometry and invalidGeometryCheck() is s...
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureRequest & operator=(const QgsFeatureRequest &rh)
Assignment operator.
QgsFeatureRequest & setInvalidGeometryCheck(InvalidGeometryCheck check)
Sets invalid geometry checking behavior.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
QgsFeatureRequest & setTransformErrorCallback(const std::function< void(const QgsFeature &)> &callback)
Sets a callback function to use when encountering a transform error when iterating features and a des...
double mDistanceWithin
Maximum distance from reference geometry.
bool requestMayBeNested() const
In case this request may be run nested within another already running iteration on the same connectio...
@ FilterFid
Filter using feature ID.
@ FilterFids
Filter using feature IDs.
@ FilterNone
No filter is applied.
@ FilterExpression
Filter using expression.
QgsFeatureRequest()
construct a default request: for all features get attributes and geometries
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsFeatureRequest & setDistanceWithin(const QgsGeometry &geometry, double distance)
Sets a reference geometry and a maximum distance from this geometry to retrieve features within.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
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.
bool boundingBoxIntersects(const QgsRectangle &rectangle) const
Returns true if the bounding box of this geometry intersects with a rectangle.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
QgsRectangle buffered(double width) const
Gets rectangle enlarged by buffer.
Definition: qgsrectangle.h:325
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
const QgsCoordinateReferenceSystem & crs