@@ -109,6 +109,17 @@ QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeat
109
109
, mFetchedFid( false )
110
110
, mInterruptionChecker( nullptr )
111
111
{
112
+ if ( mRequest .destinationCrs ().isValid () && mRequest .destinationCrs () != mSource ->mCrs )
113
+ {
114
+ mTransform = QgsCoordinateTransform ( mSource ->mCrs , mRequest .destinationCrs () );
115
+ }
116
+ mFilterRect = transformedFilterRect ( mTransform );
117
+ if ( !mFilterRect .isNull () )
118
+ {
119
+ // update request to be the unprojected filter rect
120
+ mRequest .setFilterRect ( mFilterRect );
121
+ }
122
+
112
123
if ( mRequest .filterType () == QgsFeatureRequest::FilterExpression )
113
124
{
114
125
mRequest .expressionContext ()->setFields ( mSource ->mFields );
@@ -129,6 +140,13 @@ QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeat
129
140
130
141
// by default provider's request is the same
131
142
mProviderRequest = mRequest ;
143
+ // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
144
+ // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
145
+ // values
146
+ if ( mRequest .destinationCrs ().isValid () )
147
+ {
148
+ mProviderRequest .setDestinationCrs ( QgsCoordinateReferenceSystem () );
149
+ }
132
150
133
151
if ( mProviderRequest .flags () & QgsFeatureRequest::SubsetOfAttributes )
134
152
{
@@ -253,7 +271,7 @@ bool QgsVectorLayerFeatureIterator::fetchFeature( QgsFeature &f )
253
271
if ( mFetchedFid )
254
272
return false ;
255
273
bool res = nextFeatureFid ( f );
256
- if ( res && testFeature ( f ) )
274
+ if ( res && postProcessFeature ( f ) )
257
275
{
258
276
mFetchedFid = true ;
259
277
return res;
@@ -264,7 +282,7 @@ bool QgsVectorLayerFeatureIterator::fetchFeature( QgsFeature &f )
264
282
}
265
283
}
266
284
267
- if ( !mRequest . filterRect () .isNull () )
285
+ if ( !mFilterRect .isNull () )
268
286
{
269
287
if ( fetchNextChangedGeomFeature ( f ) )
270
288
return true ;
@@ -327,7 +345,7 @@ bool QgsVectorLayerFeatureIterator::fetchFeature( QgsFeature &f )
327
345
if ( !( mRequest .flags () & QgsFeatureRequest::NoGeometry ) )
328
346
updateFeatureGeometry ( f );
329
347
330
- if ( !testFeature ( f ) )
348
+ if ( !postProcessFeature ( f ) )
331
349
continue ;
332
350
333
351
return true ;
@@ -387,15 +405,17 @@ bool QgsVectorLayerFeatureIterator::fetchNextAddedFeature( QgsFeature &f )
387
405
// must have changed geometry outside rectangle
388
406
continue ;
389
407
390
- if ( !mRequest .acceptFeature ( *mFetchAddedFeaturesIt ) )
408
+ useAddedFeature ( *mFetchAddedFeaturesIt , f );
409
+
410
+ // can't test for feature acceptance until after calling useAddedFeature
411
+ // since acceptFeature may rely on virtual fields
412
+ if ( !mRequest .acceptFeature ( f ) )
391
413
// skip features which are not accepted by the filter
392
414
continue ;
393
415
394
- if ( !testFeature ( * mFetchAddedFeaturesIt ) )
416
+ if ( !postProcessFeature ( f ) )
395
417
continue ;
396
418
397
- useAddedFeature ( *mFetchAddedFeaturesIt , f );
398
-
399
419
return true ;
400
420
}
401
421
@@ -406,23 +426,13 @@ bool QgsVectorLayerFeatureIterator::fetchNextAddedFeature( QgsFeature &f )
406
426
407
427
void QgsVectorLayerFeatureIterator::useAddedFeature ( const QgsFeature &src, QgsFeature &f )
408
428
{
409
- f.setId ( src.id () );
429
+ // since QgsFeature is implicitly shared, it's more efficient to just copy the
430
+ // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
431
+ // This helps potentially avoid an unnecessary detach of the feature
432
+ f = src;
410
433
f.setValid ( true );
411
434
f.setFields ( mSource ->mFields );
412
435
413
- if ( src.hasGeometry () && !( mRequest .flags () & QgsFeatureRequest::NoGeometry ) )
414
- {
415
- f.setGeometry ( src.geometry () );
416
- }
417
- else
418
- {
419
- f.clearGeometry ();
420
- }
421
-
422
- // TODO[MD]: if subset set just some attributes
423
-
424
- f.setAttributes ( src.attributes () );
425
-
426
436
if ( mHasVirtualAttributes )
427
437
addVirtualAttributes ( f );
428
438
}
@@ -442,7 +452,7 @@ bool QgsVectorLayerFeatureIterator::fetchNextChangedGeomFeature( QgsFeature &f )
442
452
443
453
mFetchConsidered << fid;
444
454
445
- if ( !mRequest . filterRect (). isNull () && !mFetchChangedGeomIt ->intersects ( mRequest . filterRect () ) )
455
+ if ( !mFilterRect . isNull () && !mFetchChangedGeomIt ->intersects ( mFilterRect ) )
446
456
// skip changed geometries not in rectangle and don't check again
447
457
continue ;
448
458
@@ -457,7 +467,7 @@ bool QgsVectorLayerFeatureIterator::fetchNextChangedGeomFeature( QgsFeature &f )
457
467
}
458
468
}
459
469
460
- if ( testFeature ( f ) )
470
+ if ( postProcessFeature ( f ) )
461
471
{
462
472
// return complete feature
463
473
mFetchChangedGeomIt ++;
@@ -484,7 +494,7 @@ bool QgsVectorLayerFeatureIterator::fetchNextChangedAttributeFeature( QgsFeature
484
494
addVirtualAttributes ( f );
485
495
486
496
mRequest .expressionContext ()->setFeature ( f );
487
- if ( mRequest .filterExpression ()->evaluate ( mRequest .expressionContext () ).toBool () && testFeature ( f ) )
497
+ if ( mRequest .filterExpression ()->evaluate ( mRequest .expressionContext () ).toBool () && postProcessFeature ( f ) )
488
498
{
489
499
return true ;
490
500
}
@@ -703,9 +713,11 @@ void QgsVectorLayerFeatureIterator::createOrderedJoinList()
703
713
}
704
714
}
705
715
706
- bool QgsVectorLayerFeatureIterator::testFeature ( const QgsFeature &feature )
716
+ bool QgsVectorLayerFeatureIterator::postProcessFeature ( QgsFeature &feature )
707
717
{
708
718
bool result = checkGeometryValidity ( feature );
719
+ if ( result )
720
+ transformFeatureGeometry ( feature, mTransform );
709
721
return result;
710
722
}
711
723
0 commit comments