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 {}
158 IData *getNext()
override
160 if ( mFeedback && mFeedback->isCanceled() )
163 RTree::Data *ret = mNextData.release();
169 bool hasNext()
override {
return nullptr != mNextData.get(); }
172 uint32_t size()
override {
return static_cast<uint32_t
>( mFeaturesCount ); }
175 void rewind()
override { mIterator = 0; }
180 SpatialIndex::Region r;
181 while ( mIterator < mFeaturesCount )
184 r = mFeatureToRegionFunction( mMesh, mIterator, ok );
187 mNextData = std::make_unique<RTree::Data>( 0,
nullptr, r, mIterator );
201 const QgsMesh &mMesh;
202 int mFeaturesCount = 0;
203 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> mFeatureToRegionFunction;
204 std::unique_ptr<RTree::Data> mNextData;
205 QgsFeedback *mFeedback =
nullptr;
214class QgsMeshSpatialIndexData :
public QSharedData
217 QgsMeshSpatialIndexData() { initTree(); }
227 explicit QgsMeshSpatialIndexData(
const QgsMesh &fi, QgsFeedback *feedback,
QgsMesh::ElementType elementType )
229 switch ( elementType )
233 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
239 QgsMeshIteratorDataStream fids( fi, fi.
faceCount(), faceToRegion, feedback );
250 QgsMeshSpatialIndexData(
const QgsMeshSpatialIndexData &other )
251 : QSharedData( other )
253 const QMutexLocker locker( &other.mMutex );
258 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
259 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
260 const SpatialIndex::Region query( low, high, 2 );
261 QgsMeshSpatialIndexCopyVisitor visitor( mRTree.get() );
262 other.mRTree->intersectsWithQuery( query, visitor );
265 ~QgsMeshSpatialIndexData() =
default;
267 QgsMeshSpatialIndexData &operator=(
const QgsMeshSpatialIndexData &rh ) =
delete;
269 void initTree( IDataStream *inputStream =
nullptr )
272 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
275 const double fillFactor = 0.7;
276 const unsigned int indexCapacity = 10;
277 const unsigned int leafCapacity = 10;
278 const unsigned int dimension = 2;
279 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
282 SpatialIndex::id_type indexId;
284 if ( inputStream && inputStream->hasNext() )
285 mRTree.reset( RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, *inputStream, *mStorage, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
287 mRTree.reset( RTree::createNewRTree( *mStorage, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
291 std::unique_ptr<SpatialIndex::IStorageManager> mStorage;
294 std::unique_ptr<SpatialIndex::ISpatialIndex> mRTree;
296 mutable QMutex mMutex;
303 d =
new QgsMeshSpatialIndexData;
309 d =
new QgsMeshSpatialIndexData( mesh, feedback,
elementType );
313 : mElementType( other.mElementType )
318 : mElementType( other.mElementType )
319 , d( std::move( other.d ) )
326 if (
this != &other )
328 mElementType = other.mElementType;
336 if (
this != &other )
338 mElementType = std::move( other.mElementType );
339 d = std::move( other.d );
350 QgisMeshVisitor visitor( list );
354 const QMutexLocker locker( &d->mMutex );
355 d->mRTree->intersectsWithQuery( r, visitor );
363 QgisMeshVisitor visitor( list );
365 double pt[2] = { point.
x(), point.
y() };
366 const Point p( pt, 2 );
368 const QMutexLocker locker( &d->mMutex );
369 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
381 if ( mesh.
face( faceIndex ).isEmpty() )
385 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
389 const QMutexLocker locker( &d.constData()->mMutex );
393 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
395 catch ( Tools::Exception &e )
398 QgsDebugError( u
"Tools::Exception caught: "_s.arg( e.what().c_str() ) );
400 catch (
const std::exception &e )
403 QgsDebugError( u
"std::exception caught: "_s.arg( e.what() ) );
407 QgsDebugError( u
"unknown spatial index exception caught"_s );
413 if ( mesh.
face( faceIndex ).isEmpty() )
415 const QMutexLocker locker( &d.constData()->mMutex );
417 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.