mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
[api] Add constructor for QgsSpatialIndex which allows for a callback
function during bulk index load from a feature iterator Allows single-iteration of a source for dual purposes simultaneously, e.g. doing other feature-based operations while still gaining the full advantage of the bulk loaded spatial index without having to do multiple feature iterations
This commit is contained in:
parent
a25f8b970f
commit
fe6abba251
@ -63,6 +63,7 @@ that of the spatial index construction.
|
||||
.. versionadded:: 2.8
|
||||
%End
|
||||
|
||||
|
||||
explicit QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback = 0, QgsSpatialIndex::Flags flags = 0 );
|
||||
%Docstring
|
||||
Constructor - creates R-tree and bulk loads it with features from the source.
|
||||
|
@ -163,10 +163,12 @@ class QgsFeatureIteratorDataStream : public IDataStream
|
||||
{
|
||||
public:
|
||||
//! constructor - needs to load all data to a vector for later access when bulk loading
|
||||
explicit QgsFeatureIteratorDataStream( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr, QgsSpatialIndex::Flags flags = nullptr )
|
||||
explicit QgsFeatureIteratorDataStream( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr, QgsSpatialIndex::Flags flags = nullptr,
|
||||
const std::function< bool( const QgsFeature & ) > *callback = nullptr )
|
||||
: mFi( fi )
|
||||
, mFeedback( feedback )
|
||||
, mFlags( flags )
|
||||
, mCallback( callback )
|
||||
{
|
||||
readNextEntry();
|
||||
}
|
||||
@ -207,6 +209,15 @@ class QgsFeatureIteratorDataStream : public IDataStream
|
||||
QgsFeatureId id;
|
||||
while ( mFi.nextFeature( f ) )
|
||||
{
|
||||
if ( mCallback )
|
||||
{
|
||||
bool res = ( *mCallback )( f );
|
||||
if ( !res )
|
||||
{
|
||||
mNextData = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( QgsSpatialIndex::featureInfo( f, r, id ) )
|
||||
{
|
||||
mNextData = new RTree::Data( 0, nullptr, r, id );
|
||||
@ -222,6 +233,7 @@ class QgsFeatureIteratorDataStream : public IDataStream
|
||||
RTree::Data *mNextData = nullptr;
|
||||
QgsFeedback *mFeedback = nullptr;
|
||||
QgsSpatialIndex::Flags mFlags = nullptr;
|
||||
const std::function< bool( const QgsFeature & ) > *mCallback = nullptr;
|
||||
|
||||
};
|
||||
|
||||
@ -253,10 +265,11 @@ class QgsSpatialIndexData : public QSharedData
|
||||
* of \a feedback is not transferred, and callers must take care that the lifetime of feedback exceeds
|
||||
* that of the spatial index construction.
|
||||
*/
|
||||
explicit QgsSpatialIndexData( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr, QgsSpatialIndex::Flags flags = nullptr )
|
||||
explicit QgsSpatialIndexData( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr, QgsSpatialIndex::Flags flags = nullptr,
|
||||
const std::function< bool( const QgsFeature & ) > *callback = nullptr )
|
||||
: mFlags( flags )
|
||||
{
|
||||
QgsFeatureIteratorDataStream fids( fi, feedback, mFlags );
|
||||
QgsFeatureIteratorDataStream fids( fi, feedback, mFlags, callback );
|
||||
initTree( &fids );
|
||||
if ( flags & QgsSpatialIndex::FlagStoreFeatureGeometries )
|
||||
mGeometries = fids.geometries;
|
||||
@ -335,6 +348,11 @@ QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *fee
|
||||
d = new QgsSpatialIndexData( fi, feedback, flags );
|
||||
}
|
||||
|
||||
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureIterator &fi, const std::function< bool( const QgsFeature & )> &callback, QgsSpatialIndex::Flags flags )
|
||||
{
|
||||
d = new QgsSpatialIndexData( fi, nullptr, flags, &callback );
|
||||
}
|
||||
|
||||
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback, QgsSpatialIndex::Flags flags )
|
||||
{
|
||||
d = new QgsSpatialIndexData( source.getFeatures( QgsFeatureRequest().setNoAttributes() ), feedback, flags );
|
||||
|
@ -95,6 +95,23 @@ class CORE_EXPORT QgsSpatialIndex : public QgsFeatureSink
|
||||
*/
|
||||
explicit QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr, QgsSpatialIndex::Flags flags = nullptr );
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* Constructor - creates R-tree and bulk loads it with features from the iterator.
|
||||
* This is much faster approach than creating an empty index and then inserting features one by one.
|
||||
*
|
||||
* This construct and bulk load variant allows for a \a callback function to be specified, which is
|
||||
* called for each added feature in turn. It allows for bulk spatial index load along with other feature
|
||||
* based operations on a single iteration through a feature source. If \a callback returns FALSE, the
|
||||
* load and iteration is canceled.
|
||||
*
|
||||
* \note Not available in Python bindings
|
||||
* \since QGIS 2.12
|
||||
*/
|
||||
explicit QgsSpatialIndex( const QgsFeatureIterator &fi, const std::function< bool( const QgsFeature & ) > &callback, QgsSpatialIndex::Flags flags = nullptr );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructor - creates R-tree and bulk loads it with features from the source.
|
||||
* This is much faster approach than creating an empty index and then inserting features one by one.
|
||||
|
@ -234,6 +234,51 @@ class TestQgsSpatialIndex : public QObject
|
||||
delete indexInsert;
|
||||
}
|
||||
|
||||
void bulkLoadWithCallback()
|
||||
{
|
||||
std::unique_ptr< QgsVectorLayer > vl = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "Point" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
|
||||
QList< QgsFeatureId > addedIds;
|
||||
for ( int i = 0; i < 10; ++i )
|
||||
{
|
||||
QgsFeature f( i );
|
||||
QgsGeometry g = QgsGeometry::fromPointXY( QgsPointXY( i, 1 ) );
|
||||
f.setGeometry( g );
|
||||
vl->dataProvider()->addFeature( f );
|
||||
addedIds.append( f.id() );
|
||||
}
|
||||
QCOMPARE( vl->featureCount(), 10L );
|
||||
|
||||
QgsFeatureIds ids;
|
||||
QgsSpatialIndex i( vl->getFeatures(), [ & ]( const QgsFeature & f )->bool
|
||||
{
|
||||
ids.insert( f.id() );
|
||||
return true;
|
||||
} );
|
||||
|
||||
QCOMPARE( ids.size(), 10 );
|
||||
for ( int i = 0; i < 10; ++i )
|
||||
QVERIFY( ids.contains( addedIds.at( i ) ) );
|
||||
|
||||
QList<QgsFeatureId> res = i.intersects( QgsRectangle( 1.5, 0, 3.5, 10 ) );
|
||||
QCOMPARE( res.size(), 2 );
|
||||
QVERIFY( res.contains( addedIds.at( 2 ) ) );
|
||||
QVERIFY( res.contains( addedIds.at( 3 ) ) );
|
||||
|
||||
// try canceling
|
||||
ids.clear();
|
||||
QgsSpatialIndex i2( vl->getFeatures(), [ & ]( const QgsFeature & f )->bool
|
||||
{
|
||||
ids.insert( f.id() );
|
||||
return false;
|
||||
} );
|
||||
|
||||
QCOMPARE( ids.size(), 1 );
|
||||
QVERIFY( ids.contains( addedIds.at( 0 ) ) );
|
||||
|
||||
res = i2.intersects( QgsRectangle( 1.5, 0, 3.5, 10 ) );
|
||||
QVERIFY( res.isEmpty() );
|
||||
}
|
||||
|
||||
void testRetrieveGeometries()
|
||||
{
|
||||
QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
|
||||
|
Loading…
x
Reference in New Issue
Block a user