Fix #11965 - improve performance of selectedFeatures()

The slowness of merge / split features tools was caused by the change in the logic
in selectedFeatures(): instead of fetching individual features one by one by ID,
the whole layer is traversed. Such approach makes sense when many features are selected,
but with few features there is considerable delay when dealing with big layers.

The implementation is not ideal, but for some common cases the performance is much better.

Merging of features now does not request selected features when not necessary.

When rendering, avoid using layer's extent() method that may force expensive
calculation of layer's extent.
This commit is contained in:
Martin Dobias 2015-02-17 19:53:19 +07:00
parent ffd7f8a85d
commit 255cbd2c2a
3 changed files with 34 additions and 14 deletions

View File

@ -5911,6 +5911,7 @@ void QgisApp::mergeSelectedFeatures()
}
//get initial selection (may be altered by attribute merge dialog later)
QgsFeatureIds featureIds = vl->selectedFeaturesIds();
QgsFeatureList featureList = vl->selectedFeatures(); //get QList<QgsFeature>
bool canceled;
QgsGeometry* unionGeom = unionGeometries( vl, featureList, canceled );
@ -5939,9 +5940,9 @@ void QgisApp::mergeSelectedFeatures()
return;
}
QgsFeatureList featureListAfter = vl->selectedFeatures();
QgsFeatureIds featureIdsAfter = vl->selectedFeaturesIds();
if ( featureListAfter.size() < 2 )
if ( featureIdsAfter.size() < 2 )
{
QMessageBox::information( 0, tr( "Not enough features selected" ), tr( "The merge tool requires at least two selected features" ) );
delete unionGeom;
@ -5949,10 +5950,11 @@ void QgisApp::mergeSelectedFeatures()
}
//if the user changed the feature selection in the merge dialog, we need to repeat the union and check the type
if ( featureList.size() != featureListAfter.size() )
if ( featureIds.size() != featureIdsAfter.size() )
{
delete unionGeom;
bool canceled;
QgsFeatureList featureListAfter = vl->selectedFeatures();
unionGeom = unionGeometries( vl, featureListAfter, canceled );
if ( !unionGeom )
{
@ -5978,10 +5980,10 @@ void QgisApp::mergeSelectedFeatures()
newFeature.setGeometry( unionGeom );
newFeature.setAttributes( d.mergedAttributes() );
QgsFeatureList::const_iterator feature_it = featureListAfter.constBegin();
for ( ; feature_it != featureListAfter.constEnd(); ++feature_it )
QgsFeatureIds::const_iterator feature_it = featureIdsAfter.constBegin();
for ( ; feature_it != featureIdsAfter.constEnd(); ++feature_it )
{
vl->deleteFeature( feature_it->id() );
vl->deleteFeature( *feature_it );
}
vl->addFeature( newFeature, false );

View File

@ -166,12 +166,11 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin
continue;
}
QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 extent:%5 blendmode:%6" )
QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5" )
.arg( ml->name() )
.arg( ml->minimumScale() )
.arg( ml->maximumScale() )
.arg( ml->hasScaleBasedVisibility() )
.arg( ml->extent().toString() )
.arg( ml->blendMode() )
);

View File

@ -2327,13 +2327,26 @@ const QgsFeatureIds& QgsVectorLayer::selectedFeaturesIds() const
QgsFeatureList QgsVectorLayer::selectedFeatures()
{
QgsFeatureList features;
QgsFeatureIterator it = selectedFeaturesIterator();
QgsFeature f;
while ( it.nextFeature( f ) )
if ( mSelectedFeatureIds.count() <= 8 )
{
features.push_back( f );
// for small amount of selected features, fetch them directly
// because request with FilterFids would go iterate over the whole layer
foreach ( int fid, mSelectedFeatureIds )
{
getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f );
features << f;
}
}
else
{
QgsFeatureIterator it = selectedFeaturesIterator();
while ( it.nextFeature( f ) )
{
features.push_back( f );
}
}
return features;
@ -2341,10 +2354,16 @@ QgsFeatureList QgsVectorLayer::selectedFeatures()
QgsFeatureIterator QgsVectorLayer::selectedFeaturesIterator( QgsFeatureRequest request )
{
if ( mSelectedFeatureIds.count() == 0 )
return QgsFeatureIterator();
if ( geometryType() == QGis::NoGeometry )
request.setFlags( QgsFeatureRequest::NoGeometry );
request.setFilterFids( mSelectedFeatureIds );
if ( mSelectedFeatureIds.count() == 1 )
request.setFilterFid( *mSelectedFeatureIds.constBegin() );
else
request.setFilterFids( mSelectedFeatureIds );
return getFeatures( request );
}