21 #include <spatialindex/SpatialIndex.h>
23 #include <QMutexLocker>
30 static Region faceToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
40 const QVector<QgsMeshVertex> &vertices = mesh.
vertices;
42 double xMinimum = vertices[face[0]].x();
43 double yMinimum = vertices[face[0]].y();
44 double xMaximum = vertices[face[0]].x();
45 double yMaximum = vertices[face[0]].y();
47 for (
int i = 1; i < face.size(); ++i )
49 xMinimum = std::min( vertices[face[i]].x(), xMinimum );
50 yMinimum = std::min( vertices[face[i]].y(), yMinimum );
51 xMaximum = std::max( vertices[face[i]].x(), xMaximum );
52 yMaximum = std::max( vertices[face[i]].y(), yMaximum );
55 double pt1[2] = { xMinimum, yMinimum };
56 double pt2[2] = { xMaximum, yMaximum };
59 return SpatialIndex::Region( pt1, pt2, 2 );
62 static Region edgeToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
67 const double xMinimum = std::min( firstVertex.
x(), secondVertex.
x() );
68 const double yMinimum = std::min( firstVertex.
y(), secondVertex.
y() );
69 const double xMaximum = std::max( firstVertex.
x(), secondVertex.
x() );
70 const double yMaximum = std::max( firstVertex.
y(), secondVertex.
y() );
71 double pt1[2] = { xMinimum, yMinimum };
72 double pt2[2] = { xMaximum, yMaximum };
74 return SpatialIndex::Region( pt1, pt2, 2 );
81 return SpatialIndex::Region( pt1, pt2, 2 );
90 class QgisMeshVisitor :
public SpatialIndex::IVisitor
93 explicit QgisMeshVisitor( QList<int> &list )
96 void visitNode(
const INode &n )
override
99 void visitData(
const IData &d )
override
101 mList.append(
static_cast<int>( d.getIdentifier() ) );
104 void visitData( std::vector<const IData *> &v )
override
117 class QgsMeshSpatialIndexCopyVisitor :
public SpatialIndex::IVisitor
120 explicit QgsMeshSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex *newIndex )
121 : mNewIndex( newIndex ) {}
123 void visitNode(
const INode &n )
override
126 void visitData(
const IData &d )
override
128 SpatialIndex::IShape *shape =
nullptr;
129 d.getShape( &shape );
130 mNewIndex->insertData( 0,
nullptr, *shape, d.getIdentifier() );
134 void visitData( std::vector<const IData *> &v )
override
138 SpatialIndex::ISpatialIndex *mNewIndex =
nullptr;
148 class QgsMeshIteratorDataStream :
public IDataStream
152 explicit QgsMeshIteratorDataStream(
const QgsMesh &mesh,
154 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> featureToRegionFunction,
157 , mFeaturesCount( featuresCount )
158 , mFeatureToRegionFunction( featureToRegionFunction )
159 , mFeedback( feedback )
164 ~QgsMeshIteratorDataStream()
override
170 IData *getNext()
override
172 if ( mFeedback && mFeedback->isCanceled() )
175 RTree::Data *ret = mNextData;
182 bool hasNext()
override
184 return nullptr != mNextData;
188 uint32_t size()
override
190 return static_cast<uint32_t
>( mFeaturesCount );
194 void rewind()
override
202 SpatialIndex::Region r;
203 while ( mIterator < mFeaturesCount )
206 r = mFeatureToRegionFunction( mMesh, mIterator, ok );
209 mNextData =
new RTree::Data( 0,
nullptr, r, mIterator );
224 int mFeaturesCount = 0;
225 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> mFeatureToRegionFunction;
226 RTree::Data *mNextData =
nullptr;
236 class QgsMeshSpatialIndexData :
public QSharedData
239 QgsMeshSpatialIndexData()
254 switch ( elementType )
256 case QgsMesh::ElementType::Edge:
258 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
262 case QgsMesh::ElementType::Face:
264 QgsMeshIteratorDataStream fids( fi, fi.
faceCount(), faceToRegion, feedback );
275 QgsMeshSpatialIndexData(
const QgsMeshSpatialIndexData &other )
276 : QSharedData( other )
278 const QMutexLocker locker( &other.mMutex );
283 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
284 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
285 const SpatialIndex::Region query( low, high, 2 );
286 QgsMeshSpatialIndexCopyVisitor visitor( mRTree.get() );
287 other.mRTree->intersectsWithQuery( query, visitor );
290 ~QgsMeshSpatialIndexData() =
default;
292 QgsMeshSpatialIndexData &operator=(
const QgsMeshSpatialIndexData &rh ) =
delete;
294 void initTree( IDataStream *inputStream =
nullptr )
297 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
300 const double fillFactor = 0.7;
301 const unsigned int indexCapacity = 10;
302 const unsigned int leafCapacity = 10;
303 const unsigned int dimension = 2;
304 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
307 SpatialIndex::id_type indexId;
309 if ( inputStream && inputStream->hasNext() )
311 RTree::createAndBulkLoadNewRTree(
314 *mStorage, fillFactor,
323 RTree::createNewRTree(
335 std::unique_ptr<SpatialIndex::IStorageManager> mStorage;
338 std::unique_ptr<SpatialIndex::ISpatialIndex> mRTree;
340 mutable QMutex mMutex;
347 d =
new QgsMeshSpatialIndexData;
351 : mElementType( elementType )
353 d =
new QgsMeshSpatialIndexData( mesh, feedback,
elementType );
365 if (
this != &other )
373 QgisMeshVisitor visitor( list );
375 const SpatialIndex::Region r = rectToRegion( rect );
377 const QMutexLocker locker( &d->mMutex );
378 d->mRTree->intersectsWithQuery( r, visitor );
386 QgisMeshVisitor visitor( list );
388 double pt[2] = { point.
x(), point.
y() };
389 const Point p( pt, 2 );
391 const QMutexLocker locker( &d->mMutex );
392 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
404 if ( mesh.
face( faceIndex ).isEmpty() )
408 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
412 const QMutexLocker locker( &d.constData()->mMutex );
416 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
418 catch ( Tools::Exception &e )
421 QgsDebugMsg( QStringLiteral(
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
423 catch (
const std::exception &e )
426 QgsDebugMsg( QStringLiteral(
"std::exception caught: " ).arg( e.what() ) );
430 QgsDebugMsg( QStringLiteral(
"unknown spatial index exception caught" ) );
436 if ( mesh.
face( faceIndex ).isEmpty() )
438 const QMutexLocker locker( &d.constData()->mMutex );
440 d.constData()->mRTree->deleteData( faceToRegion( mesh, faceIndex, ok ), faceIndex );