Handle updates of the layer in the point locator

This currently just invalidates the whole trees. It would be more sophisticated to do just the updates
to the existing trees - but I run into various issues with the spatial index library when doing that.
So resorting to this for the moment.
This commit is contained in:
Martin Dobias 2014-12-12 15:31:33 +07:00
parent 83770dfd9e
commit e05de3f9c6
2 changed files with 66 additions and 50 deletions

View File

@ -426,6 +426,49 @@ class EdgeNNComparator : public INearestNeighborComparator
};
////////////////////////////////////////////////////////////////////////////
#include <QStack>
/** Helper class to dump the R-index nodes and their content */
class QgsPointLocator_DumpTree : public SpatialIndex::IQueryStrategy
{
private:
QStack<id_type> ids;
public:
void getNextEntry( const IEntry& entry, id_type& nextEntry, bool& hasNext )
{
const INode* n = dynamic_cast<const INode*>( &entry );
qDebug( "NODE: %ld", n->getIdentifier() );
if ( n->getLevel() > 0 )
{
// inner nodes
for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
{
qDebug( "- CH: %ld", n->getChildIdentifier( cChild ) );
ids.push( n->getChildIdentifier( cChild ) );
}
}
else
{
// leaves
for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
{
qDebug( "- L: %ld", n->getChildIdentifier( cChild ) );
}
}
if ( ! ids.empty() )
{
nextEntry = ids.back(); ids.pop();
hasNext = true;
}
else
hasNext = false;
}
};
////////////////////////////////////////////////////////////////////////////
@ -585,57 +628,21 @@ void QgsPointLocator::destroyIndex( int types )
void QgsPointLocator::onFeatureAdded( QgsFeatureId fid )
{
QgsFeature f;
QgsFeatureRequest request;
request.setFilterFid( fid );
request.setSubsetOfAttributes( QgsAttributeList() );
QgsFeatureIterator fi = mLayer->getFeatures( request );
if ( fi.nextFeature( f ) && f.geometry() )
{
QGis::GeometryType geomType = f.geometry()->type();
if ( mTransform )
f.geometry()->transform( *mTransform );
if ( mRTreeVertex && ( geomType == QGis::Polygon || geomType == QGis::Line || geomType == QGis::Point ) )
{
QLinkedList<RTree::Data*> vertexDataList;
addVertexData( vertexDataList, f );
foreach ( RTree::Data* d, vertexDataList )
{
mRTreeVertex->insertData( d->m_dataLength, d->m_pData, d->m_region, d->m_id );
delete d;
}
}
// TODO: edge, area
}
Q_UNUSED( fid );
destroyIndex( All );
}
void QgsPointLocator::onFeatureDeleted( QgsFeatureId fid )
{
#if 0
if ( mRTreeVertex )
{
MyQueryStrategy qq( fid );
mRTreeVertex->queryStrategy( qq );
foreach ( const SpatialIndex::Region& r, qq.regions )
{
bool res = mRTreeVertex->deleteData( r, fid );
qDebug( "del: %d %f,%f - %f,%f", res, r.m_pLow[0], r.m_pLow[1], r.m_pHigh[0], r.m_pHigh[1] );
}
qDebug( "isvalid %d", mRTreeVertex->isIndexValid() );
}
// TODO: edge, area
#endif
Q_UNUSED( fid );
destroyIndex( All );
}
void QgsPointLocator::onGeometryChanged( QgsFeatureId fid, QgsGeometry& geom )
{
Q_UNUSED( fid );
Q_UNUSED( geom );
onFeatureDeleted( fid );
onFeatureAdded( fid );
destroyIndex( All );
}

View File

@ -116,21 +116,20 @@ class TestQgsPointLocator : public QObject
void testLayerUpdates()
{
QgsPointLocator loc( mVL );
mVL->startEditing();
QgsPointLocator loc( mVL );
QgsPointLocator::Match mAddV0 = loc.nearestVertex( QgsPoint( 12, 12 ) );
QVERIFY( mAddV0.isValid() );
QCOMPARE( mAddV0.point(), QgsPoint( 1, 1 ) );
mVL->startEditing();
// add a new feature
QgsFeature ff( 0 );
QgsPolygon polygon;
QgsPolyline polyline;
polyline << QgsPoint( 10, 11 ) << QgsPoint( 11, 10 ) << QgsPoint( 11, 11 ) << QgsPoint( 10, 11 );
polyline << QgsPoint( 101, 11 ) << QgsPoint( 111, 10 ) << QgsPoint( 111, 11 ) << QgsPoint( 110, 11 );
polyline << QgsPoint( 10, 111 ) << QgsPoint( 11, 110 ) << QgsPoint( 11, 111 ) << QgsPoint( 10, 111 );
polygon << polyline;
ff.setGeometry( QgsGeometry::fromPolygon( polygon ) );
QgsFeatureList flist;
@ -141,7 +140,6 @@ class TestQgsPointLocator : public QObject
// verify it is added in the point locator
QgsPointLocator::Match mAddV = loc.nearestVertex( QgsPoint( 12, 12 ) );
QVERIFY( mAddV.isValid() );
qDebug( "%f,%f", mAddV.point().x(), mAddV.point().y() );
QCOMPARE( mAddV.point(), QgsPoint( 11, 11 ) );
QgsPointLocator::Match mAddE = loc.nearestEdge( QgsPoint( 11.1, 10.5 ) );
QVERIFY( mAddE.isValid() );
@ -149,7 +147,20 @@ class TestQgsPointLocator : public QObject
QgsPointLocator::MatchList mAddA = loc.pointInPolygon( QgsPoint( 10.8, 10.8 ) );
QVERIFY( mAddA.count() == 1 );
#if 0
// change geometry
QgsGeometry* newGeom = new QgsGeometry( *ff.geometry() );
newGeom->moveVertex( 10, 10, 2 ); // change 11,11 to 10,10
mVL->changeGeometry( ff.id(), newGeom );
delete newGeom;
// verify it is changed in the point locator
QgsPointLocator::Match mChV = loc.nearestVertex( QgsPoint( 12, 12 ) );
QVERIFY( mChV.isValid() );
QVERIFY( mChV.point() != QgsPoint( 11, 11 ) ); // that point does not exist anymore
mChV = loc.nearestVertex( QgsPoint( 9, 9 ) );
QVERIFY( mChV.isValid() );
QVERIFY( mChV.point() == QgsPoint( 10, 10 ) ); // updated point
// delete feature
bool resD = mVL->deleteFeature( ff.id() );
QVERIFY( resD );
@ -157,9 +168,7 @@ class TestQgsPointLocator : public QObject
// verify it is deleted from the point locator
QgsPointLocator::Match mDelV = loc.nearestVertex( QgsPoint( 12, 12 ) );
QVERIFY( mDelV.isValid() );
qDebug( "%f,%f", mDelV.point().x(), mDelV.point().y() );
QCOMPARE( mDelV.point(), QgsPoint( 1, 1 ) );
#endif
mVL->rollBack();
}