Skip to content

Commit

Permalink
Add method for manually inserting features into spatial indexes
Browse files Browse the repository at this point in the history
i.e. inserting a feature with a different bounding box to that
feature's actual geometry
  • Loading branch information
nyalldawson committed Jun 1, 2017
1 parent 6eb3570 commit ff171ea
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 7 deletions.
21 changes: 21 additions & 0 deletions python/core/qgsspatialindex.sip
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ Add feature to index
:rtype: bool
%End

bool insertFeature( 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.0
:rtype: bool
%End

bool deleteFeature( const QgsFeature &f );
%Docstring
Remove feature from index
Expand Down Expand Up @@ -84,6 +92,19 @@ get reference count - just for debugging!
protected:


static bool featureInfo( const QgsFeature &f, QgsRectangle &rect, QgsFeatureId &id );
%Docstring
Calculates feature info to insert into index.
\param f input feature
\param rect will be set to feature's geometry bounding box
\param id will be set to feature's ID
:return: true if feature info was successfully retrieved and the feature can be added to
the index
.. versionadded:: 3.0
:rtype: bool
%End


};


Expand Down
26 changes: 20 additions & 6 deletions src/core/qgsspatialindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,24 +253,38 @@ SpatialIndex::Region QgsSpatialIndex::rectToRegion( const QgsRectangle &rect )

bool QgsSpatialIndex::featureInfo( const QgsFeature &f, SpatialIndex::Region &r, QgsFeatureId &id )
{
if ( !f.hasGeometry() )
QgsRectangle rect;
if ( !featureInfo( f, rect, id ) )
return false;

QgsGeometry g = f.geometry();
r = rectToRegion( rect );
return true;
}

bool QgsSpatialIndex::featureInfo( const QgsFeature &f, QgsRectangle &rect, QgsFeatureId &id )
{
if ( !f.hasGeometry() )
return false;

id = f.id();
r = rectToRegion( g.boundingBox() );
rect = f.geometry().boundingBox();
return true;
}


bool QgsSpatialIndex::insertFeature( const QgsFeature &f )
{
SpatialIndex::Region r;
QgsRectangle rect;
QgsFeatureId id;
if ( !featureInfo( f, r, id ) )
if ( !featureInfo( f, rect, id ) )
return false;

return insertFeature( id, rect );
}

bool QgsSpatialIndex::insertFeature( QgsFeatureId id, const QgsRectangle &rect )
{
SpatialIndex::Region r( rectToRegion( rect ) );

// TODO: handle possible exceptions correctly
try
{
Expand Down
27 changes: 26 additions & 1 deletion src/core/qgsspatialindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class CORE_EXPORT QgsSpatialIndex
//! Add feature to index
bool insertFeature( const QgsFeature &f );

/**
* 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
*/
bool insertFeature( QgsFeatureId id, const QgsRectangle &bounds );

//! Remove feature from index
bool deleteFeature( const QgsFeature &f );

Expand All @@ -101,9 +108,27 @@ class CORE_EXPORT QgsSpatialIndex
protected:
//! \note not available in Python bindings
static SpatialIndex::Region rectToRegion( const QgsRectangle &rect ) SIP_SKIP;
//! \note not available in Python bindings

/** Calculates feature info to insert into index.
* \param f input feature
* \param r will be set to spatial index region
* \param id will be set to feature's ID
* \returns true if feature info was successfully retrieved and the feature can be added to
* the index
* \note not available in Python bindings
*/
static bool featureInfo( const QgsFeature &f, SpatialIndex::Region &r, QgsFeatureId &id ) SIP_SKIP;

/** Calculates feature info to insert into index.
* \param f input feature
* \param rect will be set to feature's geometry bounding box
* \param id will be set to feature's ID
* \returns true if feature info was successfully retrieved and the feature can be added to
* the index
* \since QGIS 3.0
*/
static bool featureInfo( const QgsFeature &f, QgsRectangle &rect, QgsFeatureId &id );

friend class QgsFeatureIteratorDataStream; // for access to featureInfo()

private:
Expand Down
17 changes: 17 additions & 0 deletions tests/src/core/testqgsspatialindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ class TestQgsSpatialIndex : public QObject
QVERIFY( fids2.contains( 3 ) );
}

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 ) );

QList<QgsFeatureId> fids = index.intersects( QgsRectangle( 1, 2, 3, 4 ) );
QVERIFY( fids.count() == 1 );
QVERIFY( fids.at( 0 ) == 1 );

QList<QgsFeatureId> fids2 = index.intersects( QgsRectangle( 10, 12, 15, 14 ) );
QVERIFY( fids2.count() == 2 );
QVERIFY( fids2.contains( 2 ) );
QVERIFY( fids2.contains( 3 ) );
}

void testCopy()
{
QgsSpatialIndex *index = new QgsSpatialIndex;
Expand Down

0 comments on commit ff171ea

Please sign in to comment.