Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #4661 from nyalldawson/feature_index
Add method for manually inserting features into spatial indexes
  • Loading branch information
nyalldawson committed Jun 1, 2017
2 parents f359ffb + d8d1752 commit 2f9bfc5
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 13 deletions.
5 changes: 5 additions & 0 deletions doc/api_break.dox
Expand Up @@ -2060,6 +2060,11 @@ QgsSnapper {#qgis_api_break_3_0_QgsSnapper}
- Constructor variant with QgsMapRenderer has been removed. Use the variant with QgsMapSettings.
- Signature for snapPoint() has changed.

QgsSpatialIndex {#qgis_api_break_3_0_QgsSpatialIndex}
---------------

- The protected members were made private. QgsSpatialIndex is not designed to be subclassed.


QgsSublayersDialog {#qgis_api_break_3_0_QgsSublayersDialog}
------------------
Expand Down
11 changes: 8 additions & 3 deletions python/core/qgsspatialindex.sip
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 @@ -81,9 +89,6 @@ get reference count - just for debugging!
:rtype: QAtomicInt
%End

protected:


};


Expand Down
26 changes: 20 additions & 6 deletions src/core/qgsspatialindex.cpp
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
32 changes: 28 additions & 4 deletions src/core/qgsspatialindex.h
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 @@ -98,12 +105,29 @@ class CORE_EXPORT QgsSpatialIndex
//! get reference count - just for debugging!
QAtomicInt SIP_PYTYPE( int ) refs() const;

protected:
//! \note not available in Python bindings
static SpatialIndex::Region rectToRegion( const QgsRectangle &rect ) SIP_SKIP;
//! \note not available in Python bindings
private:

static SpatialIndex::Region rectToRegion( const QgsRectangle &rect );

/** 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
*/
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
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 2f9bfc5

Please sign in to comment.