QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
24const 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;
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;
126 {
128 mReferenceGeometryEngine->prepareGeometry();
129 }
130 else
131 {
133 }
134 mDistanceWithin = distance;
137
138 return *this;
139}
140
142{
144 mFilterFid = fid;
145 return *this;
146}
147
149{
151 mFilterFids = fids;
152 return *this;
153}
154
156{
158 return *this;
159}
160
161QgsFeatureRequest &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
193QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending )
194{
195 mOrderBy.append( OrderByClause( expression, ascending ) );
196 return *this;
197}
198
199QgsFeatureRequest &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{
213 return *this;
214}
215
217{
218 mLimit = limit;
219 return *this;
220}
221
222QgsFeatureRequest &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
240QgsFeatureRequest &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
262QgsFeatureRequest &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
308QgsFeatureRequest &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
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 (
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{
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
438QgsFeatureRequest::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
446QgsFeatureRequest::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
461QgsFeatureRequest::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
509QgsFeatureRequest::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
518QList<QgsFeatureRequest::OrderByClause> QgsFeatureRequest::OrderBy::list() const
519{
520 return *this;
521}
522
523void 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
539void 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
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.
const QgsSimplifyMethod & simplifyMethod() const
Returns the simplification method for geometries that will be fetched.
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:233
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:164
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