19#include <spatialindex/SpatialIndex.h>
27#include <QMutexLocker>
30using namespace Qt::StringLiterals;
36static Region faceToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
46 const QVector<QgsMeshVertex> &vertices = mesh.
vertices;
48 double xMinimum = vertices[face[0]].x();
49 double yMinimum = vertices[face[0]].y();
50 double xMaximum = vertices[face[0]].x();
51 double yMaximum = vertices[face[0]].y();
53 for (
int i = 1; i < face.size(); ++i )
55 xMinimum = std::min( vertices[face[i]].x(), xMinimum );
56 yMinimum = std::min( vertices[face[i]].y(), yMinimum );
57 xMaximum = std::max( vertices[face[i]].x(), xMaximum );
58 yMaximum = std::max( vertices[face[i]].y(), yMaximum );
61 double pt1[2] = { xMinimum, yMinimum };
62 double pt2[2] = { xMaximum, yMaximum };
65 return SpatialIndex::Region( pt1, pt2, 2 );
68static Region edgeToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
73 const double xMinimum = std::min( firstVertex.
x(), secondVertex.
x() );
74 const double yMinimum = std::min( firstVertex.
y(), secondVertex.
y() );
75 const double xMaximum = std::max( firstVertex.
x(), secondVertex.
x() );
76 const double yMaximum = std::max( firstVertex.
y(), secondVertex.
y() );
77 double pt1[2] = { xMinimum, yMinimum };
78 double pt2[2] = { xMaximum, yMaximum };
80 return SpatialIndex::Region( pt1, pt2, 2 );
89class QgisMeshVisitor :
public SpatialIndex::IVisitor
92 explicit QgisMeshVisitor( QList<int> &list )
96 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
98 void visitData(
const IData &d )
override { mList.append(
static_cast<int>( d.getIdentifier() ) ); }
100 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
112class QgsMeshSpatialIndexCopyVisitor :
public SpatialIndex::IVisitor
115 explicit QgsMeshSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex *newIndex )
116 : mNewIndex( newIndex )
119 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
121 void visitData(
const IData &d )
override
123 SpatialIndex::IShape *shape =
nullptr;
124 d.getShape( &shape );
125 mNewIndex->insertData( 0,
nullptr, *shape, d.getIdentifier() );
129 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
132 SpatialIndex::ISpatialIndex *mNewIndex =
nullptr;
142class QgsMeshIteratorDataStream :
public IDataStream
146 explicit QgsMeshIteratorDataStream(
const QgsMesh &mesh,
int featuresCount, std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> featureToRegionFunction, QgsFeedback *feedback =
nullptr )
148 , mFeaturesCount( featuresCount )
149 , mFeatureToRegionFunction( std::move( featureToRegionFunction ) )
150 , mFeedback( feedback )
155 ~QgsMeshIteratorDataStream()
override {
delete mNextData; }
158 IData *getNext()
override
160 if ( mFeedback && mFeedback->isCanceled() )
163 RTree::Data *ret = mNextData;
170 bool hasNext()
override {
return nullptr != mNextData; }
173 uint32_t size()
override {
return static_cast<uint32_t
>( mFeaturesCount ); }
176 void rewind()
override { mIterator = 0; }
181 SpatialIndex::Region r;
182 while ( mIterator < mFeaturesCount )
185 r = mFeatureToRegionFunction( mMesh, mIterator, ok );
188 mNextData =
new RTree::Data( 0,
nullptr, r, mIterator );
202 const QgsMesh &mMesh;
203 int mFeaturesCount = 0;
204 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> mFeatureToRegionFunction;
205 RTree::Data *mNextData =
nullptr;
206 QgsFeedback *mFeedback =
nullptr;
215class QgsMeshSpatialIndexData :
public QSharedData
218 QgsMeshSpatialIndexData() { initTree(); }
228 explicit QgsMeshSpatialIndexData(
const QgsMesh &fi, QgsFeedback *feedback,
QgsMesh::ElementType elementType )
230 switch ( elementType )
234 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
240 QgsMeshIteratorDataStream fids( fi, fi.
faceCount(), faceToRegion, feedback );
251 QgsMeshSpatialIndexData(
const QgsMeshSpatialIndexData &other )
252 : QSharedData( other )
254 const QMutexLocker locker( &other.mMutex );
259 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
260 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
261 const SpatialIndex::Region query( low, high, 2 );
262 QgsMeshSpatialIndexCopyVisitor visitor( mRTree.get() );
263 other.mRTree->intersectsWithQuery( query, visitor );
266 ~QgsMeshSpatialIndexData() =
default;
268 QgsMeshSpatialIndexData &operator=(
const QgsMeshSpatialIndexData &rh ) =
delete;
270 void initTree( IDataStream *inputStream =
nullptr )
273 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
276 const double fillFactor = 0.7;
277 const unsigned int indexCapacity = 10;
278 const unsigned int leafCapacity = 10;
279 const unsigned int dimension = 2;
280 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
283 SpatialIndex::id_type indexId;
285 if ( inputStream && inputStream->hasNext() )
286 mRTree.reset( RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, *inputStream, *mStorage, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
288 mRTree.reset( RTree::createNewRTree( *mStorage, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
292 std::unique_ptr<SpatialIndex::IStorageManager> mStorage;
295 std::unique_ptr<SpatialIndex::ISpatialIndex> mRTree;
297 mutable QMutex mMutex;
304 d =
new QgsMeshSpatialIndexData;
310 d =
new QgsMeshSpatialIndexData( mesh, feedback,
elementType );
314 : mElementType( other.mElementType )
319 : mElementType( other.mElementType )
320 , d( std::move( other.d ) )
327 if (
this != &other )
329 mElementType = other.mElementType;
337 if (
this != &other )
339 mElementType = std::move( other.mElementType );
340 d = std::move( other.d );
351 QgisMeshVisitor visitor( list );
355 const QMutexLocker locker( &d->mMutex );
356 d->mRTree->intersectsWithQuery( r, visitor );
364 QgisMeshVisitor visitor( list );
366 double pt[2] = { point.
x(), point.
y() };
367 const Point p( pt, 2 );
369 const QMutexLocker locker( &d->mMutex );
370 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
382 if ( mesh.
face( faceIndex ).isEmpty() )
386 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
390 const QMutexLocker locker( &d.constData()->mMutex );
394 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
396 catch ( Tools::Exception &e )
399 QgsDebugError( u
"Tools::Exception caught: "_s.arg( e.what().c_str() ) );
401 catch (
const std::exception &e )
404 QgsDebugError( u
"std::exception caught: "_s.arg( e.what() ) );
408 QgsDebugError( u
"unknown spatial index exception caught"_s );
414 if ( mesh.
face( faceIndex ).isEmpty() )
416 const QMutexLocker locker( &d.constData()->mMutex );
418 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.