diff --git a/python/core/auto_generated/qgsspatialindex.sip.in b/python/core/auto_generated/qgsspatialindex.sip.in index c59a4017efe..9e7de2d0f62 100644 --- a/python/core/auto_generated/qgsspatialindex.sip.in +++ b/python/core/auto_generated/qgsspatialindex.sip.in @@ -14,7 +14,7 @@ -class QgsSpatialIndex +class QgsSpatialIndex : QgsFeatureSink { %Docstring @@ -75,18 +75,49 @@ Copy constructor - bool insertFeature( const QgsFeature &feature ); + bool insertFeature( const QgsFeature &feature ) /Deprecated/; %Docstring Adds a ``feature`` to the index. + +.. deprecated:: Use addFeature() instead %End - bool insertFeature( QgsFeatureId id, const QgsRectangle &bounds ); + virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ); + +%Docstring +Adds a ``feature`` to the index. + +The ``flags`` argument is ignored. + +.. versionadded:: 3.4 +%End + + virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ); + +%Docstring +Adds a list of ``features`` to the index. + +The ``flags`` argument is ignored. + +.. seealso:: :py:func:`addFeature` +%End + + bool insertFeature( QgsFeatureId id, const QgsRectangle &bounds ) /Deprecated/; %Docstring Add a feature ``id`` to the index with a specified bounding box. :return: true if feature was successfully added to index. -.. versionadded:: 3.0 +.. deprecated:: Use addFeature() instead +%End + + bool addFeature( QgsFeatureId id, const QgsRectangle &bounds ); +%Docstring +Add a feature ``id`` to the index with a specified bounding box. + +:return: true if feature was successfully added to index. + +.. versionadded:: 3.4 %End bool deleteFeature( const QgsFeature &feature ); diff --git a/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py b/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py index 3e23f2d25a8..c5beb7f1dc2 100644 --- a/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py +++ b/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py @@ -28,6 +28,7 @@ __revision__ = '$Format:%H$' from qgis.core import (QgsFeatureRequest, QgsProcessingException, QgsFeatureSink, + QgsSpatialIndex, QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -71,11 +72,13 @@ class DeleteDuplicateGeometries(QgisAlgorithm): features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])) total = 100.0 / source.featureCount() if source.featureCount() else 0 geoms = dict() + index = QgsSpatialIndex() for current, f in enumerate(features): if feedback.isCanceled(): break geoms[f.id()] = f.geometry() + #index.insertFeature feedback.setProgress(int(current * total)) cleaned = dict(geoms) diff --git a/python/plugins/processing/algs/qgis/PointsDisplacement.py b/python/plugins/processing/algs/qgis/PointsDisplacement.py index 40158a6134c..bbbb251c492 100644 --- a/python/plugins/processing/algs/qgis/PointsDisplacement.py +++ b/python/plugins/processing/algs/qgis/PointsDisplacement.py @@ -116,7 +116,7 @@ class PointsDisplacement(QgisAlgorithm): other_features_within_radius = index.intersects(searchRect(point)) if not other_features_within_radius: - index.insertFeature(f) + index.addFeature(f) group = [f] clustered_groups.append(group) group_index[f.id()] = len(clustered_groups) - 1 diff --git a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py index d119df77871..c80fbd55e9e 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py +++ b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py @@ -163,7 +163,7 @@ class RandomPointsAlongLines(QgisAlgorithm): f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) - index.insertFeature(f) + index.addFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(int(nPoints * total)) diff --git a/python/plugins/processing/algs/qgis/RandomPointsExtent.py b/python/plugins/processing/algs/qgis/RandomPointsExtent.py index 896463008ff..4347112027b 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsExtent.py +++ b/python/plugins/processing/algs/qgis/RandomPointsExtent.py @@ -142,7 +142,7 @@ class RandomPointsExtent(QgisAlgorithm): f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) - index.insertFeature(f) + index.addFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(int(nPoints * total)) diff --git a/python/plugins/processing/algs/qgis/RandomPointsLayer.py b/python/plugins/processing/algs/qgis/RandomPointsLayer.py index c9f8d97b52c..47958488371 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsLayer.py +++ b/python/plugins/processing/algs/qgis/RandomPointsLayer.py @@ -151,7 +151,7 @@ class RandomPointsLayer(QgisAlgorithm): f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) - index.insertFeature(f) + index.addFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(int(nPoints * total)) diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygons.py b/python/plugins/processing/algs/qgis/RandomPointsPolygons.py index 6349d85932f..53d1defc494 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsPolygons.py +++ b/python/plugins/processing/algs/qgis/RandomPointsPolygons.py @@ -197,7 +197,7 @@ class RandomPointsPolygons(QgisAlgorithm): f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) - index.insertFeature(f) + index.addFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(current_progress + int(nPoints * feature_total)) diff --git a/python/plugins/processing/algs/qgis/TopoColors.py b/python/plugins/processing/algs/qgis/TopoColors.py index 0d24079e758..1afdd8c0b4c 100644 --- a/python/plugins/processing/algs/qgis/TopoColors.py +++ b/python/plugins/processing/algs/qgis/TopoColors.py @@ -190,7 +190,7 @@ class TopoColor(QgisAlgorithm): if id_graph: id_graph.add_edge(f.id(), f2.id()) - index.insertFeature(f) + index.addFeature(f) i += 1 feedback.setProgress(int(i * total)) diff --git a/src/analysis/processing/qgsalgorithmsplitwithlines.cpp b/src/analysis/processing/qgsalgorithmsplitwithlines.cpp index 3d1af0a88af..833882d60a1 100644 --- a/src/analysis/processing/qgsalgorithmsplitwithlines.cpp +++ b/src/analysis/processing/qgsalgorithmsplitwithlines.cpp @@ -118,7 +118,7 @@ QVariantMap QgsSplitWithLinesAlgorithm::processAlgorithm( const QVariantMap &par } splitGeoms.insert( aSplitFeature.id(), aSplitFeature.geometry() ); - spatialIndex.insertFeature( aSplitFeature ); + spatialIndex.addFeature( aSplitFeature ); } QgsFeature outFeat; diff --git a/src/analysis/processing/qgsoverlayutils.cpp b/src/analysis/processing/qgsoverlayutils.cpp index e7c070a8bb2..4ded0cc7be0 100644 --- a/src/analysis/processing/qgsoverlayutils.cpp +++ b/src/analysis/processing/qgsoverlayutils.cpp @@ -298,7 +298,7 @@ void QgsOverlayUtils::resolveOverlaps( const QgsFeatureSource &source, QgsFeatur std::unique_ptr< QgsGeometryEngine > g1engine; geometries.insert( fid1, g1 ); - index.insertFeature( f ); + index.addFeature( f ); QgsRectangle bbox( f.geometry().boundingBox() ); const QList ids = index.intersects( bbox ); @@ -335,7 +335,7 @@ void QgsOverlayUtils::resolveOverlaps( const QgsFeatureSource &source, QgsFeatur QgsFeature fx( newFid ); fx.setGeometry( geomIntersection ); - index.insertFeature( fx ); + index.addFeature( fx ); // figure out which feature IDs belong to this intersection. Some of the IDs can be of the newly // created geometries - in such case we need to retrieve original IDs @@ -365,7 +365,7 @@ void QgsOverlayUtils::resolveOverlaps( const QgsFeatureSource &source, QgsFeatur QgsFeature f1x( fid1 ); f1x.setGeometry( g12 ); - index.insertFeature( f1x ); + index.addFeature( f1x ); } // @@ -386,7 +386,7 @@ void QgsOverlayUtils::resolveOverlaps( const QgsFeatureSource &source, QgsFeatur QgsFeature f2x( fid2 ); f2x.setGeometry( g21 ); - index.insertFeature( f2x ); + index.addFeature( f2x ); } // update our temporary copy of the geometry to what is left from it diff --git a/src/analysis/vector/geometry_checker/qgsfeaturepool.cpp b/src/analysis/vector/geometry_checker/qgsfeaturepool.cpp index e5d8b81bd1c..1cb50573ead 100644 --- a/src/analysis/vector/geometry_checker/qgsfeaturepool.cpp +++ b/src/analysis/vector/geometry_checker/qgsfeaturepool.cpp @@ -57,7 +57,7 @@ bool QgsFeaturePool::getFeature( QgsFeatureId id, QgsFeature &feature ) } locker.changeMode( QgsReadWriteLocker::Write ); mFeatureCache.insert( id, new QgsFeature( feature ) ); - mIndex.insertFeature( feature ); + mIndex.addFeature( feature ); } return true; } @@ -90,7 +90,8 @@ void QgsFeaturePool::insertFeature( const QgsFeature &feature ) { QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write ); mFeatureCache.insert( feature.id(), new QgsFeature( feature ) ); - mIndex.insertFeature( feature ); + QgsFeature indexFeature( feature ); + mIndex.addFeature( indexFeature ); } void QgsFeaturePool::refreshCache( const QgsFeature &feature ) diff --git a/src/analysis/vector/qgsgeometrysnapper.cpp b/src/analysis/vector/qgsgeometrysnapper.cpp index d2aa866b54f..ec0d1da2ed5 100644 --- a/src/analysis/vector/qgsgeometrysnapper.cpp +++ b/src/analysis/vector/qgsgeometrysnapper.cpp @@ -768,7 +768,7 @@ QgsGeometry QgsInternalGeometrySnapper::snapFeature( const QgsFeature &feature ) } } mProcessedGeometries.insert( feat.id(), geometry ); - mProcessedIndex.insertFeature( feat ); + mProcessedIndex.addFeature( feat ); mFirstFeature = false; return geometry; } diff --git a/src/analysis/vector/qgsgeometrysnappersinglesource.cpp b/src/analysis/vector/qgsgeometrysnappersinglesource.cpp index a08eaddb24c..edcea9e93be 100644 --- a/src/analysis/vector/qgsgeometrysnappersinglesource.cpp +++ b/src/analysis/vector/qgsgeometrysnappersinglesource.cpp @@ -70,7 +70,7 @@ static void buildSnapIndex( QgsFeatureIterator &fi, QgsSpatialIndex &index, QVec if ( ids.isEmpty() ) { // add to tree and to structure - index.insertFeature( pntId, pt.boundingBox() ); + index.addFeature( pntId, pt.boundingBox() ); AnchorPoint xp; xp.x = pt.x(); diff --git a/src/core/providers/memory/qgsmemoryprovider.cpp b/src/core/providers/memory/qgsmemoryprovider.cpp index b242cbe3bd3..fd78e60a323 100644 --- a/src/core/providers/memory/qgsmemoryprovider.cpp +++ b/src/core/providers/memory/qgsmemoryprovider.cpp @@ -395,7 +395,7 @@ bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags ) // update spatial index if ( mSpatialIndex ) - mSpatialIndex->insertFeature( *it ); + mSpatialIndex->addFeature( *it ); } mNextFeatureId++; @@ -541,7 +541,7 @@ bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map // update spatial index if ( mSpatialIndex ) - mSpatialIndex->insertFeature( *fit ); + mSpatialIndex->addFeature( *fit ); } updateExtents(); @@ -583,9 +583,9 @@ bool QgsMemoryProvider::createSpatialIndex() mSpatialIndex = new QgsSpatialIndex(); // add existing features to index - for ( QgsFeatureMap::const_iterator it = mFeatures.constBegin(); it != mFeatures.constEnd(); ++it ) + for ( QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it ) { - mSpatialIndex->insertFeature( *it ); + mSpatialIndex->addFeature( *it ); } } return true; diff --git a/src/core/qgsspatialindex.cpp b/src/core/qgsspatialindex.cpp index e6041a48a62..65d8311a4f5 100644 --- a/src/core/qgsspatialindex.cpp +++ b/src/core/qgsspatialindex.cpp @@ -299,19 +299,41 @@ bool QgsSpatialIndex::featureInfo( const QgsFeature &f, QgsRectangle &rect, QgsF return true; } -bool QgsSpatialIndex::insertFeature( const QgsFeature &f ) +bool QgsSpatialIndex::addFeature( QgsFeature &feature, QgsFeatureSink::Flags ) { QgsRectangle rect; QgsFeatureId id; - if ( !featureInfo( f, rect, id ) ) + if ( !featureInfo( feature, rect, id ) ) return false; - return insertFeature( id, rect ); + return addFeature( id, rect ); } -bool QgsSpatialIndex::insertFeature( QgsFeatureId id, const QgsRectangle &rect ) +bool QgsSpatialIndex::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags ) { - SpatialIndex::Region r( rectToRegion( rect ) ); + QgsFeatureList::iterator fIt = features.begin(); + bool result = true; + for ( ; fIt != features.end(); ++fIt ) + { + result = result && addFeature( *fIt, flags ); + } + return result; +} + +bool QgsSpatialIndex::insertFeature( const QgsFeature &f ) +{ + QgsFeature feature( f ); + return addFeature( feature ); +} + +bool QgsSpatialIndex::insertFeature( QgsFeatureId id, const QgsRectangle &bounds ) +{ + return addFeature( id, bounds ); +} + +bool QgsSpatialIndex::addFeature( QgsFeatureId id, const QgsRectangle &bounds ) +{ + SpatialIndex::Region r( rectToRegion( bounds ) ); QMutexLocker locker( &d->mMutex ); @@ -324,16 +346,16 @@ bool QgsSpatialIndex::insertFeature( QgsFeatureId id, const QgsRectangle &rect ) catch ( Tools::Exception &e ) { Q_UNUSED( e ); - QgsDebugMsg( QString( "Tools::Exception caught: " ).arg( e.what().c_str() ) ); + QgsDebugMsg( QStringLiteral( "Tools::Exception caught: " ).arg( e.what().c_str() ) ); } catch ( const std::exception &e ) { Q_UNUSED( e ); - QgsDebugMsg( QString( "std::exception caught: " ).arg( e.what() ) ); + QgsDebugMsg( QStringLiteral( "std::exception caught: " ).arg( e.what() ) ); } catch ( ... ) { - QgsDebugMsg( "unknown spatial index exception caught" ); + QgsDebugMsg( QStringLiteral( "unknown spatial index exception caught" ) ); } return false; diff --git a/src/core/qgsspatialindex.h b/src/core/qgsspatialindex.h index a5e5a3c0df6..0611f6a493d 100644 --- a/src/core/qgsspatialindex.h +++ b/src/core/qgsspatialindex.h @@ -40,6 +40,7 @@ class QgsPointXY; #include "qgis_core.h" #include "qgis_sip.h" +#include "qgsfeaturesink.h" #include #include @@ -63,7 +64,7 @@ class QgsFeatureSource; * * \see QgsSpatialIndexKDBush, which is an optimised non-mutable index for point geometries only. */ -class CORE_EXPORT QgsSpatialIndex +class CORE_EXPORT QgsSpatialIndex : public QgsFeatureSink { public: @@ -104,7 +105,7 @@ class CORE_EXPORT QgsSpatialIndex QgsSpatialIndex( const QgsSpatialIndex &other ); //! Destructor finalizes work with spatial index - ~QgsSpatialIndex(); + ~QgsSpatialIndex() override; //! Implement assignment operator QgsSpatialIndex &operator=( const QgsSpatialIndex &other ); @@ -113,15 +114,41 @@ class CORE_EXPORT QgsSpatialIndex /** * Adds a \a feature to the index. + * \deprecated Use addFeature() instead */ - bool insertFeature( const QgsFeature &feature ); + Q_DECL_DEPRECATED bool insertFeature( const QgsFeature &feature ) SIP_DEPRECATED; + + /** + * Adds a \a feature to the index. + * + * The \a flags argument is ignored. + * + * \since QGIS 3.4 + */ + bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = nullptr ) override; + + /** + * Adds a list of \a features to the index. + * + * The \a flags argument is ignored. + * + * \see addFeature() + */ + bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = nullptr ) override; /** * Add a feature \a id to the index with a specified bounding box. * \returns true if feature was successfully added to index. - * \since QGIS 3.0 + * \deprecated Use addFeature() instead */ - bool insertFeature( QgsFeatureId id, const QgsRectangle &bounds ); + Q_DECL_DEPRECATED bool insertFeature( QgsFeatureId id, const QgsRectangle &bounds ) SIP_DEPRECATED; + + /** + * Add a feature \a id to the index with a specified bounding box. + * \returns true if feature was successfully added to index. + * \since QGIS 3.4 + */ + bool addFeature( QgsFeatureId id, const QgsRectangle &bounds ); /** * Removes a \a feature from the index. diff --git a/src/core/symbology/qgspointdistancerenderer.cpp b/src/core/symbology/qgspointdistancerenderer.cpp index 320d09321c9..66e48001407 100644 --- a/src/core/symbology/qgspointdistancerenderer.cpp +++ b/src/core/symbology/qgspointdistancerenderer.cpp @@ -94,7 +94,7 @@ bool QgsPointDistanceRenderer::renderFeature( const QgsFeature &feature, QgsRend QList intersectList = mSpatialIndex->intersects( searchRect( point, searchDistance ) ); if ( intersectList.empty() ) { - mSpatialIndex->insertFeature( transformedFeature ); + mSpatialIndex->addFeature( transformedFeature ); // create new group ClusteredGroup newGroup; newGroup << GroupedFeature( transformedFeature, symbol->clone(), selected, label ); diff --git a/src/plugins/topology/topolTest.cpp b/src/plugins/topology/topolTest.cpp index 3cb1886b4fd..423c29a3983 100644 --- a/src/plugins/topology/topolTest.cpp +++ b/src/plugins/topology/topolTest.cpp @@ -1369,7 +1369,7 @@ QgsSpatialIndex *topolTest::createIndex( QgsVectorLayer *layer, const QgsRectang if ( f.hasGeometry() ) { - index->insertFeature( f ); + index->addFeature( f ); mFeatureMap2[f.id()] = FeatureLayer( layer, f ); } } diff --git a/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp b/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp index d349a0b8a08..876c52cf613 100644 --- a/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp +++ b/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp @@ -446,7 +446,7 @@ void QgsDelimitedTextProvider::scanFile( bool buildIndexes ) QgsFeature f; f.setId( mFile->recordId() ); f.setGeometry( geom ); - mSpatialIndex->insertFeature( f ); + mSpatialIndex->addFeature( f ); } } else @@ -501,7 +501,7 @@ void QgsDelimitedTextProvider::scanFile( bool buildIndexes ) QgsFeature f; f.setId( mFile->recordId() ); f.setGeometry( QgsGeometry::fromPointXY( pt ) ); - mSpatialIndex->insertFeature( f ); + mSpatialIndex->addFeature( f ); } } else @@ -770,7 +770,7 @@ void QgsDelimitedTextProvider::rescanFile() const mExtent.combineExtentWith( bbox ); } if ( buildSpatialIndex ) - mSpatialIndex->insertFeature( f ); + mSpatialIndex->addFeature( f ); } if ( buildSubsetIndex ) mSubsetIndex.append( ( quintptr ) f.id() ); diff --git a/src/providers/wfs/qgswfsshareddata.cpp b/src/providers/wfs/qgswfsshareddata.cpp index be20b3cc1d8..623430e3c09 100644 --- a/src/providers/wfs/qgswfsshareddata.cpp +++ b/src/providers/wfs/qgswfsshareddata.cpp @@ -1037,7 +1037,7 @@ void QgsWFSSharedData::endOfDownload( bool success, int featureCount, f.initAttributes( 1 ); f.setAttribute( 0, QVariant( bDownloadLimit ) ); mRegions.push_back( f ); - mCachedRegions.insertFeature( f ); + mCachedRegions.addFeature( f ); } } diff --git a/tests/src/core/testqgsspatialindex.cpp b/tests/src/core/testqgsspatialindex.cpp index 0b4c1676b3e..0d6dddc89df 100644 --- a/tests/src/core/testqgsspatialindex.cpp +++ b/tests/src/core/testqgsspatialindex.cpp @@ -70,7 +70,10 @@ class TestQgsSpatialIndex : public QObject { QgsSpatialIndex index; Q_FOREACH ( const QgsFeature &f, _pointFeatures() ) - index.insertFeature( f ); + { + QgsFeature indexFeature( f ); + index.addFeature( indexFeature ); + } QList fids = index.intersects( QgsRectangle( 0, 0, 10, 10 ) ); QVERIFY( fids.count() == 1 ); @@ -85,9 +88,9 @@ class TestQgsSpatialIndex : public QObject void testQueryManualInsert() { QgsSpatialIndex index; - index.insertFeature( 1, QgsRectangle( 2, 3, 2, 3 ) ); - index.insertFeature( 2, QgsRectangle( 12, 13, 12, 13 ) ); - index.insertFeature( 3, QgsRectangle( 14, 13, 14, 13 ) ); + index.addFeature( 1, QgsRectangle( 2, 3, 2, 3 ) ); + index.addFeature( 2, QgsRectangle( 12, 13, 12, 13 ) ); + index.addFeature( 3, QgsRectangle( 14, 13, 14, 13 ) ); QList fids = index.intersects( QgsRectangle( 1, 2, 3, 4 ) ); QVERIFY( fids.count() == 1 ); @@ -110,7 +113,10 @@ class TestQgsSpatialIndex : public QObject { QgsSpatialIndex *index = new QgsSpatialIndex; Q_FOREACH ( const QgsFeature &f, _pointFeatures() ) - index->insertFeature( f ); + { + QgsFeature indexFeature( f ); + index->addFeature( indexFeature ); + } // create copy of the index QgsSpatialIndex indexCopy( *index ); @@ -154,7 +160,7 @@ class TestQgsSpatialIndex : public QObject QgsFeature f( i * 1000 + k ); QgsGeometry g = QgsGeometry::fromPointXY( QgsPointXY( i / 10, i % 10 ) ); f.setGeometry( g ); - index.insertFeature( f ); + index.addFeature( f ); } } @@ -207,7 +213,7 @@ class TestQgsSpatialIndex : public QObject QgsFeature f; indexInsert = new QgsSpatialIndex; while ( fi.nextFeature( f ) ) - indexInsert->insertFeature( f ); + indexInsert->addFeature( f ); } qDebug( "insert: %d ms", t.elapsed() );