Make operations on the feature selection more memory friendly

This commit is contained in:
Matthias Kuhn 2014-09-22 16:14:52 +02:00
parent 30ada2833a
commit e613c8b35c
7 changed files with 51 additions and 88 deletions

View File

@ -120,7 +120,10 @@ void QgsMapToolMoveFeature::canvasPressEvent( QMouseEvent * e )
mMovedFeatures = vlayer->selectedFeaturesIds(); mMovedFeatures = vlayer->selectedFeaturesIds();
mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand = createRubberBand( vlayer->geometryType() );
Q_FOREACH( const QgsFeature& feat, vlayer->selectedFeatures() ) QgsFeature feat;
QgsFeatureIterator it = vlayer->selectedFeaturesIterator( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
while ( it.nextFeature( feat ) )
{ {
mRubberBand->addGeometry( feat.geometry(), vlayer ); mRubberBand->addGeometry( feat.geometry(), vlayer );
} }

View File

@ -163,9 +163,12 @@ void QgsMapToolRotateFeature::canvasPressEvent( QMouseEvent * e )
mRotatedFeatures = vlayer->selectedFeaturesIds(); mRotatedFeatures = vlayer->selectedFeaturesIds();
mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand = createRubberBand( vlayer->geometryType() );
for ( int i = 0; i < vlayer->selectedFeatureCount(); i++ )
QgsFeature feat;
QgsFeatureIterator it = vlayer->selectedFeaturesIterator();
while ( it.nextFeature( feat ) )
{ {
mRubberBand->addGeometry( vlayer->selectedFeatures()[i].geometry(), vlayer ); mRubberBand->addGeometry( feat.geometry(), vlayer );
} }
} }

View File

@ -2301,13 +2301,7 @@ QgsFeatureList QgsVectorLayer::selectedFeatures()
{ {
QgsFeatureList features; QgsFeatureList features;
QgsFeatureRequest req; QgsFeatureIterator it = selectedFeaturesIterator();
if ( geometryType() == QGis::NoGeometry )
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setFilterFids( mSelectedFeatureIds );
QgsFeatureIterator it = getFeatures( req );
QgsFeature f; QgsFeature f;
while ( it.nextFeature( f ) ) while ( it.nextFeature( f ) )
@ -2318,6 +2312,16 @@ QgsFeatureList QgsVectorLayer::selectedFeatures()
return features; return features;
} }
QgsFeatureIterator QgsVectorLayer::selectedFeaturesIterator( QgsFeatureRequest request )
{
if ( geometryType() == QGis::NoGeometry )
request.setFlags( QgsFeatureRequest::NoGeometry );
request.setFilterFids( mSelectedFeatureIds );
return getFeatures( request );
}
bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected ) bool QgsVectorLayer::addFeatures( QgsFeatureList features, bool makeSelected )
{ {
if ( !mEditBuffer || !mDataProvider ) if ( !mEditBuffer || !mDataProvider )

View File

@ -734,6 +734,18 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/ */
QgsFeatureList selectedFeatures(); QgsFeatureList selectedFeatures();
/**
* Get an iterator of the selected features
*
* @param request You may specify a request, e.g. to limit the set of requested attributes.
* Any filter on the request will be discarded.
*
* @return Iterator over the selected features
*
* @see selectedFeaturesIds()
*/
QgsFeatureIterator selectedFeaturesIterator( QgsFeatureRequest request = QgsFeatureRequest() );
/** /**
* Return reference to identifiers of selected features * Return reference to identifiers of selected features
* *

View File

@ -198,12 +198,12 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
int numberOfSplittedFeatures = 0; int numberOfSplittedFeatures = 0;
QgsFeatureList featureList; QgsFeatureIterator features;
const QgsFeatureIds selectedIds = L->selectedFeaturesIds(); const QgsFeatureIds selectedIds = L->selectedFeaturesIds();
if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection
{ {
featureList = L->selectedFeatures(); features = L->selectedFeaturesIterator();
} }
else //else consider all the feature that intersect the bounding box of the split line else //else consider all the feature that intersect the bounding box of the split line
{ {
@ -243,28 +243,24 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
} }
} }
QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
QgsFeature f;
while ( fit.nextFeature( f ) )
featureList << QgsFeature( f );
} }
QgsFeatureList::iterator select_it = featureList.begin(); QgsFeature feat;
for ( ; select_it != featureList.end(); ++select_it ) while ( features.nextFeature( feat ) )
{ {
if ( !select_it->geometry() ) if ( !feat.geometry() )
{ {
continue; continue;
} }
QList<QgsGeometry*> newGeometries; QList<QgsGeometry*> newGeometries;
QList<QgsPoint> topologyTestPoints; QList<QgsPoint> topologyTestPoints;
QgsGeometry* newGeometry = 0; QgsGeometry* newGeometry = 0;
splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); splitFunctionReturn = feat.geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
if ( splitFunctionReturn == 0 ) if ( splitFunctionReturn == 0 )
{ {
//change this geometry //change this geometry
L->editBuffer()->changeGeometry( select_it->id(), select_it->geometry() ); L->editBuffer()->changeGeometry( feat.id(), feat.geometry() );
//insert new features //insert new features
for ( int i = 0; i < newGeometries.size(); ++i ) for ( int i = 0; i < newGeometries.size(); ++i )
@ -275,7 +271,7 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
//use default value where possible for primary key (e.g. autoincrement), //use default value where possible for primary key (e.g. autoincrement),
//and use the value from the original (split) feature if not primary key //and use the value from the original (split) feature if not primary key
QgsAttributes newAttributes = select_it->attributes(); QgsAttributes newAttributes = feat.attributes();
foreach ( int pkIdx, L->dataProvider()->pkAttributeIndexes() ) foreach ( int pkIdx, L->dataProvider()->pkAttributeIndexes() )
{ {
const QVariant defaultValue = L->dataProvider()->defaultValue( pkIdx ); const QVariant defaultValue = L->dataProvider()->defaultValue( pkIdx );
@ -335,12 +331,11 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool
int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
int numberOfSplittedParts = 0; int numberOfSplittedParts = 0;
QgsFeatureList featureList; QgsFeatureIterator fit;
const QgsFeatureIds selectedIds = L->selectedFeaturesIds();
if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection if ( L->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
{ {
featureList = L->selectedFeatures(); fit = L->selectedFeaturesIterator();
} }
else //else consider all the feature that intersect the bounding box of the split line else //else consider all the feature that intersect the bounding box of the split line
{ {
@ -380,15 +375,13 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool
} }
} }
QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
QgsFeature f;
while ( fit.nextFeature( f ) )
featureList << QgsFeature( f );
} }
int addPartRet = 0; int addPartRet = 0;
foreach ( const QgsFeature& feat, featureList )
QgsFeature feat;
while ( fit.nextFeature( feat ) )
{ {
QList<QgsGeometry*> newGeometries; QList<QgsGeometry*> newGeometries;
QList<QgsPoint> topologyTestPoints; QList<QgsPoint> topologyTestPoints;
@ -448,7 +441,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool
qDeleteAll( newGeometries ); qDeleteAll( newGeometries );
} }
if ( numberOfSplittedParts == 0 && selectedIds.size() > 0 && returnCode == 0 ) if ( numberOfSplittedParts == 0 && L->selectedFeatureCount() > 0 && returnCode == 0 )
{ {
//There is a selection but no feature has been split. //There is a selection but no feature has been split.
//Maybe user forgot that only the selected features are split //Maybe user forgot that only the selected features are split

View File

@ -28,49 +28,19 @@ QgsReaderFeatures::QgsReaderFeatures( QgsVectorLayer *layer, bool useSelection )
} // QgsReaderFeatures::QgsReaderFeatures(QgsVectorLayer *layer, bool useSelection) } // QgsReaderFeatures::QgsReaderFeatures(QgsVectorLayer *layer, bool useSelection)
QgsReaderFeatures::~QgsReaderFeatures()
{
if ( mListSelectedFeature.count() > 0 )
{
mListSelectedFeature.clear();
}
} // QgsReaderFeatures::~QgsReaderFeatures()
bool QgsReaderFeatures::nextFeature( QgsFeature & feature ) bool QgsReaderFeatures::nextFeature( QgsFeature & feature )
{ {
return ( this->*mFuncNextFeature )( feature ); return mFit.nextFeature( feature );
} // bool QgsReaderFeatures::nextFeature(QgsFeature & feature) } // bool QgsReaderFeatures::nextFeature(QgsFeature & feature)
void QgsReaderFeatures::initReader( bool useSelection ) void QgsReaderFeatures::initReader( bool useSelection )
{ {
if ( useSelection ) if ( useSelection )
{ {
mListSelectedFeature = mLayer->selectedFeatures(); mFit = mLayer->selectedFeaturesIterator( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
mIterSelectedFeature = mListSelectedFeature.begin();
mFuncNextFeature = &QgsReaderFeatures::nextFeatureSelected;
} }
else else
{ {
mFit = mLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ); mFit = mLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
mFuncNextFeature = &QgsReaderFeatures::nextFeatureTotal;
} }
} // void QgsReaderFeatures::initReader() } // void QgsReaderFeatures::initReader()
bool QgsReaderFeatures::nextFeatureTotal( QgsFeature & feature )
{
return mFit.nextFeature( feature );
} // bool QgsReaderFeatures::nextFeatureTotal ( QgsFeature & feature )
bool QgsReaderFeatures::nextFeatureSelected( QgsFeature & feature )
{
if ( mIterSelectedFeature == mListSelectedFeature.end() )
return false;
feature = *mIterSelectedFeature;
++mIterSelectedFeature;
return true;
} // bool QgsReaderFeatures::nextFeatureSelected( QgsFeature &feature )

View File

@ -35,11 +35,6 @@ class QgsReaderFeatures
*/ */
QgsReaderFeatures( QgsVectorLayer *layer, bool useSelection ); QgsReaderFeatures( QgsVectorLayer *layer, bool useSelection );
/**
* \brief Destructor
*/
~QgsReaderFeatures();
/** /**
* \brief Next feature * \brief Next feature
* \param feature reference to next Feature. * \param feature reference to next Feature.
@ -54,24 +49,7 @@ class QgsReaderFeatures
*/ */
void initReader( bool useSelection ); void initReader( bool useSelection );
/**
* \brief Next feature, not using the features selected
* \param feature reference to next Feature.
* \returns True if has next feature.
*/
bool nextFeatureTotal( QgsFeature & feature );
/**
* \brief Next feature, using the features selected
* \param feature reference to next Feature.
* \returns True if has next feature.
*/
bool nextFeatureSelected( QgsFeature & feature );
QgsVectorLayer * mLayer; QgsVectorLayer * mLayer;
QgsFeatureList mListSelectedFeature;
QList<QgsFeature>::iterator mIterSelectedFeature;
bool ( QgsReaderFeatures::* mFuncNextFeature )( QgsFeature & );
QgsFeatureIterator mFit; QgsFeatureIterator mFit;
}; };