QGIS API Documentation  3.27.0-Master (0e23467727)
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;
77  if ( rh.mFilterExpression )
78  {
80  }
81  else
82  {
83  mFilterExpression.reset( nullptr );
84  }
88  mAttrs = rh.mAttrs;
90  mLimit = rh.mLimit;
91  mOrderBy = rh.mOrderBy;
92  mCrs = rh.mCrs;
95  mTimeout = rh.mTimeout;
97  mFeedback = rh.mFeedback;
98  return *this;
99 }
100 
102 {
103  mFilterRect = rect;
105  mDistanceWithin = 0;
106  if ( mFilterRect.isNull() )
107  {
109  }
110  else
111  {
113  }
114  return *this;
115 }
116 
118 {
119  return mFilterRect;
120 }
121 
123 {
124  mReferenceGeometry = geometry;
125  if ( !mReferenceGeometry.isEmpty() )
126  {
128  mReferenceGeometryEngine->prepareGeometry();
129  }
130  else
131  {
132  mReferenceGeometryEngine.reset();
133  }
134  mDistanceWithin = distance;
137 
138  return *this;
139 }
140 
142 {
143  mFilter = FilterFid;
144  mFilterFid = fid;
145  return *this;
146 }
147 
149 {
151  mFilterFids = fids;
152  return *this;
153 }
154 
156 {
157  mInvalidGeometryFilter = check;
158  return *this;
159 }
160 
161 QgsFeatureRequest &QgsFeatureRequest::setInvalidGeometryCallback( const std::function<void ( const QgsFeature & )> &callback )
162 {
163  mInvalidGeometryCallback = callback;
164  return *this;
165 }
166 
168 {
170  mFilterExpression.reset( new QgsExpression( expression ) );
171  return *this;
172 }
173 
175 {
176  if ( mFilterExpression )
177  {
178  setFilterExpression( QStringLiteral( "(%1) AND (%2)" ).arg( mFilterExpression->expression(), expression ) );
179  }
180  else
181  {
182  setFilterExpression( expression );
183  }
184  return *this;
185 }
186 
188 {
189  mExpressionContext = context;
190  return *this;
191 }
192 
193 QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending )
194 {
195  mOrderBy.append( OrderByClause( expression, ascending ) );
196  return *this;
197 }
198 
199 QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending, bool nullsfirst )
200 {
201  mOrderBy.append( OrderByClause( expression, ascending, nullsfirst ) );
202  return *this;
203 }
204 
206 {
207  return mOrderBy;
208 }
209 
211 {
212  mOrderBy = orderBy;
213  return *this;
214 }
215 
217 {
218  mLimit = limit;
219  return *this;
220 }
221 
222 QgsFeatureRequest &QgsFeatureRequest::setFlags( QgsFeatureRequest::Flags flags )
223 {
224  mFlags = flags;
225  return *this;
226 }
227 
229 {
231  mAttrs = attrs;
232  return *this;
233 }
234 
236 {
238 }
239 
240 QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QStringList &attrNames, const QgsFields &fields )
241 {
242  if ( attrNames.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) )
243  {
244  //attribute string list contains the all attributes flag, so we must fetch all attributes
245  return *this;
246  }
247 
249  mAttrs.clear();
250 
251  const auto constAttrNames = attrNames;
252  for ( const QString &attrName : constAttrNames )
253  {
254  const int attrNum = fields.lookupField( attrName );
255  if ( attrNum != -1 && !mAttrs.contains( attrNum ) )
256  mAttrs.append( attrNum );
257  }
258 
259  return *this;
260 }
261 
262 QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QSet<QString> &attrNames, const QgsFields &fields )
263 {
264  if ( attrNames.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) )
265  {
266  //attribute string list contains the all attributes flag, so we must fetch all attributes
267  return *this;
268  }
269 
271  mAttrs.clear();
272 
273  const auto constAttrNames = attrNames;
274  for ( const QString &attrName : constAttrNames )
275  {
276  const int attrNum = fields.lookupField( attrName );
277  if ( attrNum != -1 && !mAttrs.contains( attrNum ) )
278  mAttrs.append( attrNum );
279  }
280 
281  return *this;
282 }
283 
285 {
287  return *this;
288 }
289 
290 
292 {
293  return mCrs;
294 }
295 
297 {
298  return mTransformContext;
299 }
300 
302 {
303  mCrs = crs;
304  mTransformContext = context;
305  return *this;
306 }
307 
308 QgsFeatureRequest &QgsFeatureRequest::setTransformErrorCallback( const std::function<void ( const QgsFeature & )> &callback )
309 {
310  mTransformErrorCallback = callback;
311  return *this;
312 }
313 
315 {
316  // check the attribute/id filter first, it's more likely to be faster than
317  // the spatial filter
318  switch ( mFilter )
319  {
321  break;
322 
324  if ( feature.id() != mFilterFid )
325  return false;
326  break;
327 
329  mExpressionContext.setFeature( feature );
330  if ( !mFilterExpression->evaluate( &mExpressionContext ).toBool() )
331  return false;
332  break;
333 
335  if ( !mFilterFids.contains( feature.id() ) )
336  return false;
337  break;
338  }
339 
340  switch ( mSpatialFilter )
341  {
343  break;
344 
346  if ( !feature.hasGeometry() ||
347  (
348  ( mFlags & ExactIntersect && !feature.geometry().intersects( mFilterRect ) )
349  ||
351  )
352  )
353  return false;
354  break;
355 
357  if ( !feature.hasGeometry()
360  || !mReferenceGeometryEngine->distanceWithin( feature.geometry().constGet(), mDistanceWithin )
361  )
362  return false;
363  break;
364  }
365 
366  return true;
367 }
368 
370 {
371  return mTimeout;
372 }
373 
375 {
377  return *this;
378 }
379 
381 {
382  return mTimeout;
383 }
384 
386 {
387  mTimeout = timeout;
388  return *this;
389 }
390 
392 {
393  return mRequestMayBeNested;
394 }
395 
397 {
399  return *this;
400 }
401 
403 {
405 }
406 
408 {
409  return mFeedback;
410 }
411 
412 
413 #include "qgsfeatureiterator.h"
414 #include "qgslogger.h"
415 
417 {
418  while ( !mActiveIterators.empty() )
419  {
421  QgsDebugMsgLevel( QStringLiteral( "closing active iterator" ), 2 );
422  it->close();
423  }
424 }
425 
427 {
428  mActiveIterators.insert( it );
429 }
430 
432 {
433  mActiveIterators.remove( it );
434 }
435 
436 
437 
438 QgsFeatureRequest::OrderByClause::OrderByClause( const QString &expression, bool ascending )
439  : mExpression( expression )
440  , mAscending( ascending )
441 {
442  // postgres behavior: default for ASC: NULLS LAST, default for DESC: NULLS FIRST
443  mNullsFirst = !ascending;
444 }
445 
446 QgsFeatureRequest::OrderByClause::OrderByClause( const QString &expression, bool ascending, bool nullsfirst )
447  : mExpression( expression )
448  , mAscending( ascending )
449  , mNullsFirst( nullsfirst )
450 {
451 }
452 
454  : mExpression( expression )
455  , mAscending( ascending )
456 {
457  // postgres behavior: default for ASC: NULLS LAST, default for DESC: NULLS FIRST
458  mNullsFirst = !ascending;
459 }
460 
461 QgsFeatureRequest::OrderByClause::OrderByClause( const QgsExpression &expression, bool ascending, bool nullsfirst )
462  : mExpression( expression )
463  , mAscending( ascending )
464  , mNullsFirst( nullsfirst )
465 {
466 
467 }
468 
470 {
471  return mAscending;
472 }
473 
475 {
476  mAscending = ascending;
477 }
478 
480 {
481  return mNullsFirst;
482 }
483 
485 {
486  mNullsFirst = nullsFirst;
487 }
488 
490 {
491  return QStringLiteral( "%1 %2 %3" )
492  .arg( mExpression.expression(),
493  mAscending ? "ASC" : "DESC",
494  mNullsFirst ? "NULLS FIRST" : "NULLS LAST" );
495 }
496 
498 {
499  return mExpression;
500 }
501 
503 {
504  return mExpression.prepare( context );
505 }
506 
508 
509 QgsFeatureRequest::OrderBy::OrderBy( const QList<QgsFeatureRequest::OrderByClause> &other )
510 {
511  const auto constOther = other;
512  for ( const QgsFeatureRequest::OrderByClause &clause : constOther )
513  {
514  append( clause );
515  }
516 }
517 
518 QList<QgsFeatureRequest::OrderByClause> QgsFeatureRequest::OrderBy::list() const
519 {
520  return *this;
521 }
522 
523 void QgsFeatureRequest::OrderBy::save( QDomElement &elem ) const
524 {
525  QDomDocument doc = elem.ownerDocument();
526  QList<OrderByClause>::ConstIterator it;
527  for ( it = constBegin(); it != constEnd(); ++it )
528  {
529  const OrderByClause &clause = *it;
530  QDomElement clauseElem = doc.createElement( QStringLiteral( "orderByClause" ) );
531  clauseElem.setAttribute( QStringLiteral( "asc" ), clause.ascending() );
532  clauseElem.setAttribute( QStringLiteral( "nullsFirst" ), clause.nullsFirst() );
533  clauseElem.appendChild( doc.createTextNode( clause.expression().expression() ) );
534 
535  elem.appendChild( clauseElem );
536  }
537 }
538 
539 void QgsFeatureRequest::OrderBy::load( const QDomElement &elem )
540 {
541  clear();
542 
543  const QDomNodeList clauses = elem.childNodes();
544 
545  for ( int i = 0; i < clauses.size(); ++i )
546  {
547  const QDomElement clauseElem = clauses.at( i ).toElement();
548  const QString expression = clauseElem.text();
549  const bool asc = clauseElem.attribute( QStringLiteral( "asc" ) ).toInt() != 0;
550  const bool nullsFirst = clauseElem.attribute( QStringLiteral( "nullsFirst" ) ).toInt() != 0;
551 
552  append( OrderByClause( expression, asc, nullsFirst ) );
553  }
554 }
555 
557 {
558  QSet<QString> usedAttributes;
559 
560  QList<OrderByClause>::ConstIterator it;
561  for ( it = constBegin(); it != constEnd(); ++it )
562  {
563  const OrderByClause &clause = *it;
564 
565  usedAttributes.unite( clause.expression().referencedColumns() );
566  }
567 
568  return usedAttributes;
569 }
570 
572 {
573  QSet<int> usedAttributeIdx;
574  for ( const OrderByClause &clause : *this )
575  {
576  const auto referencedColumns = clause.expression().referencedColumns();
577  for ( const QString &fieldName : referencedColumns )
578  {
579  const int idx = fields.lookupField( fieldName );
580  if ( idx >= 0 )
581  {
582  usedAttributeIdx.insert( idx );
583  }
584  }
585  }
586  return usedAttributeIdx;
587 }
588 
590 {
591  QStringList results;
592 
593  QList<OrderByClause>::ConstIterator it;
594  for ( it = constBegin(); it != constEnd(); ++it )
595  {
596  const OrderByClause &clause = *it;
597 
598  results << clause.dump();
599  }
600 
601  return results.join( QLatin1String( ", " ) );
602 }
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:72
@ 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
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::shared_ptr< QgsGeometryEngine > mReferenceGeometryEngine
Prepared geometry engine for mReferenceGeometry.
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:223
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:349
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
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