19#include <spatialindex/SpatialIndex.h>
27#include <QMutexLocker>
33static Region faceToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
43 const QVector<QgsMeshVertex> &vertices = mesh.
vertices;
45 double xMinimum = vertices[face[0]].x();
46 double yMinimum = vertices[face[0]].y();
47 double xMaximum = vertices[face[0]].x();
48 double yMaximum = vertices[face[0]].y();
50 for (
int i = 1; i < face.size(); ++i )
52 xMinimum = std::min( vertices[face[i]].x(), xMinimum );
53 yMinimum = std::min( vertices[face[i]].y(), yMinimum );
54 xMaximum = std::max( vertices[face[i]].x(), xMaximum );
55 yMaximum = std::max( vertices[face[i]].y(), yMaximum );
58 double pt1[2] = { xMinimum, yMinimum };
59 double pt2[2] = { xMaximum, yMaximum };
62 return SpatialIndex::Region( pt1, pt2, 2 );
65static Region edgeToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
70 const double xMinimum = std::min( firstVertex.
x(), secondVertex.
x() );
71 const double yMinimum = std::min( firstVertex.
y(), secondVertex.
y() );
72 const double xMaximum = std::max( firstVertex.
x(), secondVertex.
x() );
73 const double yMaximum = std::max( firstVertex.
y(), secondVertex.
y() );
74 double pt1[2] = { xMinimum, yMinimum };
75 double pt2[2] = { xMaximum, yMaximum };
77 return SpatialIndex::Region( pt1, pt2, 2 );
86class QgisMeshVisitor :
public SpatialIndex::IVisitor
89 explicit QgisMeshVisitor( QList<int> &list )
92 void visitNode(
const INode &n )
override
95 void visitData(
const IData &d )
override
97 mList.append(
static_cast<int>( d.getIdentifier() ) );
100 void visitData( std::vector<const IData *> &v )
override
113class QgsMeshSpatialIndexCopyVisitor :
public SpatialIndex::IVisitor
116 explicit QgsMeshSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex *newIndex )
117 : mNewIndex( newIndex ) {}
119 void visitNode(
const INode &n )
override
122 void visitData(
const IData &d )
override
124 SpatialIndex::IShape *shape =
nullptr;
125 d.getShape( &shape );
126 mNewIndex->insertData( 0,
nullptr, *shape, d.getIdentifier() );
130 void visitData( std::vector<const IData *> &v )
override
134 SpatialIndex::ISpatialIndex *mNewIndex =
nullptr;
144class QgsMeshIteratorDataStream :
public IDataStream
148 explicit QgsMeshIteratorDataStream(
const QgsMesh &mesh,
150 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> featureToRegionFunction,
151 QgsFeedback *feedback =
nullptr )
153 , mFeaturesCount( featuresCount )
154 , mFeatureToRegionFunction( std::move( featureToRegionFunction ) )
155 , mFeedback( feedback )
160 ~QgsMeshIteratorDataStream()
override
166 IData *getNext()
override
168 if ( mFeedback && mFeedback->isCanceled() )
171 RTree::Data *ret = mNextData;
178 bool hasNext()
override
180 return nullptr != mNextData;
184 uint32_t size()
override
186 return static_cast<uint32_t
>( mFeaturesCount );
190 void rewind()
override
198 SpatialIndex::Region r;
199 while ( mIterator < mFeaturesCount )
202 r = mFeatureToRegionFunction( mMesh, mIterator, ok );
205 mNextData =
new RTree::Data( 0,
nullptr, r, mIterator );
219 const QgsMesh &mMesh;
220 int mFeaturesCount = 0;
221 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> mFeatureToRegionFunction;
222 RTree::Data *mNextData =
nullptr;
223 QgsFeedback *mFeedback =
nullptr;
232class QgsMeshSpatialIndexData :
public QSharedData
235 QgsMeshSpatialIndexData()
248 explicit QgsMeshSpatialIndexData(
const QgsMesh &fi, QgsFeedback *feedback,
QgsMesh::ElementType elementType )
250 switch ( elementType )
254 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
260 QgsMeshIteratorDataStream fids( fi, fi.
faceCount(), faceToRegion, feedback );
271 QgsMeshSpatialIndexData(
const QgsMeshSpatialIndexData &other )
272 : QSharedData( other )
274 const QMutexLocker locker( &other.mMutex );
279 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
280 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
281 const SpatialIndex::Region query( low, high, 2 );
282 QgsMeshSpatialIndexCopyVisitor visitor( mRTree.get() );
283 other.mRTree->intersectsWithQuery( query, visitor );
286 ~QgsMeshSpatialIndexData() =
default;
288 QgsMeshSpatialIndexData &operator=(
const QgsMeshSpatialIndexData &rh ) =
delete;
290 void initTree( IDataStream *inputStream =
nullptr )
293 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
296 const double fillFactor = 0.7;
297 const unsigned int indexCapacity = 10;
298 const unsigned int leafCapacity = 10;
299 const unsigned int dimension = 2;
300 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
303 SpatialIndex::id_type indexId;
305 if ( inputStream && inputStream->hasNext() )
307 RTree::createAndBulkLoadNewRTree(
310 *mStorage, fillFactor,
319 RTree::createNewRTree(
331 std::unique_ptr<SpatialIndex::IStorageManager> mStorage;
334 std::unique_ptr<SpatialIndex::ISpatialIndex> mRTree;
336 mutable QMutex mMutex;
343 d =
new QgsMeshSpatialIndexData;
349 d =
new QgsMeshSpatialIndexData( mesh, feedback,
elementType );
353 : mElementType( other.mElementType )
359 : mElementType( other.mElementType )
360 , d( std::move( other.d ) )
368 if (
this != &other )
370 mElementType = other.mElementType;
378 if (
this != &other )
380 mElementType = std::move( other.mElementType );
381 d = std::move( other.d );
389 QgisMeshVisitor visitor( list );
393 const QMutexLocker locker( &d->mMutex );
394 d->mRTree->intersectsWithQuery( r, visitor );
402 QgisMeshVisitor visitor( list );
404 double pt[2] = { point.
x(), point.
y() };
405 const Point p( pt, 2 );
407 const QMutexLocker locker( &d->mMutex );
408 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
420 if ( mesh.
face( faceIndex ).isEmpty() )
424 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
428 const QMutexLocker locker( &d.constData()->mMutex );
432 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
434 catch ( Tools::Exception &e )
437 QgsDebugError( QStringLiteral(
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
439 catch (
const std::exception &e )
442 QgsDebugError( QStringLiteral(
"std::exception caught: " ).arg( e.what() ) );
446 QgsDebugError( QStringLiteral(
"unknown spatial index exception caught" ) );
452 if ( mesh.
face( faceIndex ).isEmpty() )
454 const QMutexLocker locker( &d.constData()->mMutex );
456 d.constData()->mRTree->deleteData( faceToRegion( mesh, faceIndex, ok ), faceIndex );
Base class for feedback objects to be used for cancellation of something running in a worker thread.
QList< int > intersects(const QgsRectangle &rectangle) const
Returns a list of face ids with a bounding box which intersects the specified rectangle.
QgsMesh::ElementType elementType() const
Returns the type of mesh elements that are indexed.
QgsMeshSpatialIndex()
Constructor for QgsSpatialIndex.
void addFace(int faceIndex, const QgsMesh &mesh)
Adds a face with faceIndex from the mesh in the spatial index.
void removeFace(int faceIndex, const QgsMesh &mesh)
Removes a face with faceIndex from the mesh in the spatial index.
QgsMeshSpatialIndex & operator=(const QgsMeshSpatialIndex &other)
QList< int > nearestNeighbor(const QgsPointXY &point, int neighbors) const
Returns nearest neighbors to a point.
~QgsMeshSpatialIndex()
Destructor finalizes work with spatial index.
A rectangle specified with double values.
static SpatialIndex::Region rectangleToRegion(const QgsRectangle &rectangle)
Converts a QGIS rectangle to a SpatialIndex region.
#define QgsDebugError(str)
QVector< int > QgsMeshFace
List of vertex indexes.
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
QgsPoint QgsMeshVertex
xyz coords of vertex
Mesh - vertices, edges and faces.
QVector< QgsMeshVertex > vertices
QgsMeshFace face(int index) const
Returns a face at the index.
int faceCount() const
Returns number of faces.
ElementType
Defines type of mesh elements.
QgsMeshEdge edge(int index) const
Returns an edge at the index.
int edgeCount() const
Returns number of edge.