Skip to content

Commit ebfa9f1

Browse files
committedJun 12, 2017
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) (cherry-picked from 6a87889)
1 parent e91e247 commit ebfa9f1

File tree

2 files changed

+28
-26
lines changed

2 files changed

+28
-26
lines changed
 

‎src/providers/memory/qgsmemoryprovider.cpp

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,16 @@ QgsFeatureIterator QgsMemoryProvider::getFeatures( const QgsFeatureRequest& requ
285285

286286
QgsRectangle QgsMemoryProvider::extent()
287287
{
288+
if ( mExtent.isEmpty() && !mFeatures.isEmpty() )
289+
{
290+
mExtent.setMinimal();
291+
Q_FOREACH ( const QgsFeature &feat, mFeatures )
292+
{
293+
if ( feat.constGeometry() )
294+
mExtent.unionRect( feat.constGeometry()->boundingBox() );
295+
}
296+
}
297+
288298
return mExtent;
289299
}
290300

@@ -328,6 +338,9 @@ QgsCoordinateReferenceSystem QgsMemoryProvider::crs()
328338

329339
bool QgsMemoryProvider::addFeatures( QgsFeatureList & flist )
330340
{
341+
// whether or not to update the layer extent on the fly as we add features
342+
bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
343+
331344
// TODO: sanity checks of fields and geometries
332345
for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
333346
{
@@ -336,15 +349,19 @@ bool QgsMemoryProvider::addFeatures( QgsFeatureList & flist )
336349

337350
mFeatures.insert( mNextFeatureId, *it );
338351

339-
// update spatial index
340-
if ( mSpatialIndex )
341-
mSpatialIndex->insertFeature( *it );
352+
if ( it->constGeometry() )
353+
{
354+
if ( updateExtent )
355+
mExtent.combineExtentWith( it->constGeometry()->boundingBox() );
356+
357+
// update spatial index
358+
if ( mSpatialIndex )
359+
mSpatialIndex->insertFeature( *it );
360+
}
342361

343362
mNextFeatureId++;
344363
}
345364

346-
updateExtent();
347-
348365
return true;
349366
}
350367

@@ -365,7 +382,7 @@ bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds & id )
365382
mFeatures.erase( fit );
366383
}
367384

368-
updateExtent();
385+
updateExtents();
369386

370387
return true;
371388
}
@@ -482,7 +499,7 @@ bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map
482499
mSpatialIndex->insertFeature( *fit );
483500
}
484501

485-
updateExtent();
502+
updateExtents();
486503

487504
return true;
488505
}
@@ -533,21 +550,9 @@ int QgsMemoryProvider::capabilities() const
533550
}
534551

535552

536-
void QgsMemoryProvider::updateExtent()
553+
void QgsMemoryProvider::updateExtents()
537554
{
538-
if ( mFeatures.isEmpty() )
539-
{
540-
mExtent = QgsRectangle();
541-
}
542-
else
543-
{
544-
mExtent.setMinimal();
545-
Q_FOREACH ( const QgsFeature& feat, mFeatures )
546-
{
547-
if ( feat.constGeometry() )
548-
mExtent.unionRect( feat.constGeometry()->boundingBox() );
549-
}
550-
}
555+
mExtent.setMinimal();
551556
}
552557

553558

‎src/providers/memory/qgsmemoryprovider.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,7 @@ class QgsMemoryProvider : public QgsVectorDataProvider
158158

159159
virtual QgsCoordinateReferenceSystem crs() override;
160160

161-
protected:
162-
163-
// called when added / removed features or geometries has been changed
164-
void updateExtent();
161+
void updateExtents() override;
165162

166163
private:
167164
// Coordinate reference system
@@ -170,7 +167,7 @@ class QgsMemoryProvider : public QgsVectorDataProvider
170167
// fields
171168
QgsFields mFields;
172169
QGis::WkbType mWkbType;
173-
QgsRectangle mExtent;
170+
mutable QgsRectangle mExtent;
174171

175172
// features
176173
QgsFeatureMap mFeatures;

0 commit comments

Comments
 (0)
Please sign in to comment.