Skip to content

Commit

Permalink
Stop fighting with templates and take the shortcut approach
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Dec 10, 2019
1 parent c4a28a2 commit e521829
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 160 deletions.
1 change: 0 additions & 1 deletion src/core/CMakeLists.txt
Expand Up @@ -252,7 +252,6 @@ SET(QGIS_CORE_SRCS
qgsfileutils.cpp
qgsfontutils.cpp
qgsgdalutils.cpp
qgsgenericspatialindex.cpp
qgsgeometrysimplifier.cpp
qgsgeometryvalidator.cpp
qgsgeometryoptions.cpp
Expand Down
153 changes: 0 additions & 153 deletions src/core/qgsgenericspatialindex.cpp

This file was deleted.

113 changes: 107 additions & 6 deletions src/core/qgsgenericspatialindex.h
Expand Up @@ -18,13 +18,16 @@

#include "qgis_core.h"
#include "qgsspatialindexutils.h"
#include "qgslogger.h"

#include <memory>
#include <QMutex>
#include <QString>

#define SIP_NO_FILE

#include <functional>
#include <spatialindex/SpatialIndex.h>

class QgsRectangle;

Expand All @@ -45,35 +48,106 @@ class CORE_EXPORT QgsGenericSpatialIndex
/**
* Constructor for QgsGenericSpatialIndex.
*/
QgsGenericSpatialIndex();

~QgsGenericSpatialIndex();
QgsGenericSpatialIndex()
: mMutex( QMutex::Recursive )
{
mStorageManager.reset( SpatialIndex::StorageManager::createNewMemoryStorageManager() );
mRTree = createSpatialIndex( *mStorageManager );
}

/**
* Inserts new \a data into the spatial index, with the specified \a bounds.
*
* Ownership of \a data is not transferred, and it is the caller's responsibility to ensure that
* it exists for the lifetime of the spatial index.
*/
bool insert( T *data, const QgsRectangle &bounds );
bool insert( T *data, const QgsRectangle &bounds )
{
SpatialIndex::Region r( QgsSpatialIndexUtils::rectangleToRegion( bounds ) );

QMutexLocker locker( &mMutex );

qint64 id = mNextId++;
mIdToData.insert( id, data );
mDataToId.insert( data, id );
try
{
mRTree->insertData( 0, nullptr, r, static_cast< qint64 >( id ) );
return true;
}
catch ( Tools::Exception &e )
{
Q_UNUSED( e )
QgsDebugMsg( QStringLiteral( "Tools::Exception caught: " ).arg( e.what().c_str() ) );
}
catch ( const std::exception &e )
{
Q_UNUSED( e )
QgsDebugMsg( QStringLiteral( "std::exception caught: " ).arg( e.what() ) );
}
catch ( ... )
{
QgsDebugMsg( QStringLiteral( "unknown spatial index exception caught" ) );
}

return false;
}

/**
* Removes existing \a data from the spatial index, with the specified \a bounds.
*
* \a data is not deleted, and it is the caller's responsibility to ensure that
* it is appropriately cleaned up.
*/
bool remove( T *data, const QgsRectangle &bounds );
bool remove( T *data, const QgsRectangle &bounds )
{
SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );

QMutexLocker locker( &mMutex );

const qint64 id = mDataToId.value( data, 0 );
if ( id == 0 )
return false;

// TODO: handle exceptions
bool res = mRTree->deleteData( r, id );
mDataToId.remove( data );
mIdToData.remove( id );
return res;
}

/**
* Performs an intersection check against the index, for data intersecting the specified \a bounds.
*
* The \a callback function will be called once for each matching data object encountered.
*/
bool intersects( const QgsRectangle &bounds, const std::function< bool( T *data )> &callback ) const;
bool intersects( const QgsRectangle &bounds, const std::function< bool( T *data )> &callback ) const
{
GenericIndexVisitor<T> visitor( callback, mIdToData );
SpatialIndex::Region r = QgsSpatialIndexUtils::rectangleToRegion( bounds );

QMutexLocker locker( &mMutex );
mRTree->intersectsWithQuery( r, visitor );
return true;
}

private:

std::unique_ptr< SpatialIndex::ISpatialIndex > createSpatialIndex( SpatialIndex::IStorageManager &storageManager )
{
// R-Tree parameters
constexpr double fillFactor = 0.7;
constexpr unsigned long indexCapacity = 10;
constexpr unsigned long leafCapacity = 10;
constexpr unsigned long dimension = 2;
constexpr SpatialIndex::RTree::RTreeVariant variant = SpatialIndex::RTree::RV_RSTAR;

// create R-tree
SpatialIndex::id_type indexId;
return std::unique_ptr< SpatialIndex::ISpatialIndex >( SpatialIndex::RTree::createNewRTree( storageManager, fillFactor, indexCapacity,
leafCapacity, dimension, variant, indexId ) );
}

std::unique_ptr< SpatialIndex::IStorageManager > mStorageManager;
std::unique_ptr< SpatialIndex::ISpatialIndex > mRTree;

Expand All @@ -83,6 +157,33 @@ class CORE_EXPORT QgsGenericSpatialIndex
QHash< qint64, T * > mIdToData;
QHash< T *, qint64 > mDataToId;

template <typename TT>
class GenericIndexVisitor : public SpatialIndex::IVisitor
{
public:
explicit GenericIndexVisitor( const std::function< bool( TT *data )> &callback, const QHash< qint64, TT * > &data )
: mCallback( callback )
, mData( data )
{}

void visitNode( const SpatialIndex::INode &n ) override
{ Q_UNUSED( n ) }

void visitData( const SpatialIndex::IData &d ) override
{
qint64 id = d.getIdentifier();
T *data = mData.value( id );
mCallback( data );
}

void visitData( std::vector<const SpatialIndex::IData *> &v ) override
{ Q_UNUSED( v ) }

private:
const std::function< bool( TT *data )> &mCallback;
QHash< qint64, TT * > mData;
};

};

#endif // QGSGENERICSPATIALINDEX_H

0 comments on commit e521829

Please sign in to comment.