Skip to content

Commit 6a87889

Browse files
nyalldawsonm-kuhn
authored andcommitted
Don't wastefully recalculate memory provider extent after every
feature addition Previously, the memory provider would automatically recalculate the extent of the layer after new features are added by looping through the entire set of existing features and calculating the bounding boxes. This is very wasteful, as many code paths add features one-by-one, so with every new feature added to the provider every existing feature is iterated over. This caused memory layers to slow to a crawl after many features are added. This commit improves the logic so that IF an existing layer extent is known, then it's updated on the fly as each individual feauture is added. Instead of looping through all features, we just expand the existing known extent with the added features bounds. If the extent isn't known, we just invalidate it when adding/deleting/modifying features, and defer the actual extent calculation until it's next requested. Makes memory layers many thousands of magnitudes of orders faster when adding lots of features (e.g. when memory providers are used as temporary outputs in processing)
1 parent be2ec2f commit 6a87889

File tree

2 files changed

+28
-27
lines changed

2 files changed

+28
-27
lines changed

src/core/providers/memory/qgsmemoryprovider.cpp

+26-21
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,16 @@ QgsFeatureIterator QgsMemoryProvider::getFeatures( const QgsFeatureRequest &requ
272272

273273
QgsRectangle QgsMemoryProvider::extent() const
274274
{
275+
if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
276+
{
277+
mExtent.setMinimal();
278+
Q_FOREACH ( const QgsFeature &feat, mFeatures )
279+
{
280+
if ( feat.hasGeometry() )
281+
mExtent.unionRect( feat.geometry().boundingBox() );
282+
}
283+
}
284+
275285
return mExtent;
276286
}
277287

@@ -315,6 +325,9 @@ QgsCoordinateReferenceSystem QgsMemoryProvider::crs() const
315325

316326
bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist )
317327
{
328+
// whether or not to update the layer extent on the fly as we add features
329+
bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
330+
318331
// TODO: sanity checks of fields and geometries
319332
for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
320333
{
@@ -323,15 +336,19 @@ bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist )
323336

324337
mFeatures.insert( mNextFeatureId, *it );
325338

326-
// update spatial index
327-
if ( mSpatialIndex )
328-
mSpatialIndex->insertFeature( *it );
339+
if ( it->hasGeometry() )
340+
{
341+
if ( updateExtent )
342+
mExtent.combineExtentWith( it->geometry().boundingBox() );
343+
344+
// update spatial index
345+
if ( mSpatialIndex )
346+
mSpatialIndex->insertFeature( *it );
347+
}
329348

330349
mNextFeatureId++;
331350
}
332351

333-
updateExtent();
334-
335352
return true;
336353
}
337354

@@ -352,7 +369,7 @@ bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds &id )
352369
mFeatures.erase( fit );
353370
}
354371

355-
updateExtent();
372+
updateExtents();
356373

357374
return true;
358375
}
@@ -471,7 +488,7 @@ bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map
471488
mSpatialIndex->insertFeature( *fit );
472489
}
473490

474-
updateExtent();
491+
updateExtents();
475492

476493
return true;
477494
}
@@ -522,21 +539,9 @@ QgsVectorDataProvider::Capabilities QgsMemoryProvider::capabilities() const
522539
}
523540

524541

525-
void QgsMemoryProvider::updateExtent()
542+
void QgsMemoryProvider::updateExtents()
526543
{
527-
if ( mFeatures.isEmpty() )
528-
{
529-
mExtent = QgsRectangle();
530-
}
531-
else
532-
{
533-
mExtent.setMinimal();
534-
Q_FOREACH ( const QgsFeature &feat, mFeatures )
535-
{
536-
if ( feat.hasGeometry() )
537-
mExtent.unionRect( feat.geometry().boundingBox() );
538-
}
539-
}
544+
mExtent.setMinimal();
540545
}
541546

542547
QString QgsMemoryProvider::name() const

src/core/providers/memory/qgsmemoryprovider.h

+2-6
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,18 @@ class QgsMemoryProvider : public QgsVectorDataProvider
6868
QString name() const override;
6969
QString description() const override;
7070
virtual QgsRectangle extent() const override;
71+
void updateExtents() override;
7172
bool isValid() const override;
7273
virtual QgsCoordinateReferenceSystem crs() const override;
7374

74-
protected:
75-
76-
// called when added / removed features or geometries has been changed
77-
void updateExtent();
78-
7975
private:
8076
// Coordinate reference system
8177
QgsCoordinateReferenceSystem mCrs;
8278

8379
// fields
8480
QgsFields mFields;
8581
QgsWkbTypes::Type mWkbType;
86-
QgsRectangle mExtent;
82+
mutable QgsRectangle mExtent;
8783

8884
// features
8985
QgsFeatureMap mFeatures;

0 commit comments

Comments
 (0)