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 )
95 void visitNode(
const INode &n )
override
98 void visitData(
const IData &d )
override
100 mList.append(
static_cast<int>( d.getIdentifier() ) );
103 void visitData( std::vector<const IData *> &v )
override
116class QgsMeshSpatialIndexCopyVisitor :
public SpatialIndex::IVisitor
119 explicit QgsMeshSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex *newIndex )
120 : mNewIndex( newIndex ) {}
122 void visitNode(
const INode &n )
override
125 void visitData(
const IData &d )
override
127 SpatialIndex::IShape *shape =
nullptr;
128 d.getShape( &shape );
129 mNewIndex->insertData( 0,
nullptr, *shape, d.getIdentifier() );
133 void visitData( std::vector<const IData *> &v )
override
137 SpatialIndex::ISpatialIndex *mNewIndex =
nullptr;
147class QgsMeshIteratorDataStream :
public IDataStream
151 explicit QgsMeshIteratorDataStream(
const QgsMesh &mesh,
153 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> featureToRegionFunction,
154 QgsFeedback *feedback =
nullptr )
156 , mFeaturesCount( featuresCount )
157 , mFeatureToRegionFunction( std::move( featureToRegionFunction ) )
158 , mFeedback( feedback )
163 ~QgsMeshIteratorDataStream()
override
169 IData *getNext()
override
171 if ( mFeedback && mFeedback->isCanceled() )
174 RTree::Data *ret = mNextData;
181 bool hasNext()
override
183 return nullptr != mNextData;
187 uint32_t size()
override
189 return static_cast<uint32_t
>( mFeaturesCount );
193 void rewind()
override
201 SpatialIndex::Region r;
202 while ( mIterator < mFeaturesCount )
205 r = mFeatureToRegionFunction( mMesh, mIterator, ok );
208 mNextData =
new RTree::Data( 0,
nullptr, r, mIterator );
222 const QgsMesh &mMesh;
223 int mFeaturesCount = 0;
224 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> mFeatureToRegionFunction;
225 RTree::Data *mNextData =
nullptr;
226 QgsFeedback *mFeedback =
nullptr;
235class QgsMeshSpatialIndexData :
public QSharedData
238 QgsMeshSpatialIndexData()
251 explicit QgsMeshSpatialIndexData(
const QgsMesh &fi, QgsFeedback *feedback,
QgsMesh::ElementType elementType )
253 switch ( elementType )
257 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
263 QgsMeshIteratorDataStream fids( fi, fi.
faceCount(), faceToRegion, feedback );
274 QgsMeshSpatialIndexData(
const QgsMeshSpatialIndexData &other )
275 : QSharedData( other )
277 const QMutexLocker locker( &other.mMutex );
282 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
283 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
284 const SpatialIndex::Region query( low, high, 2 );
285 QgsMeshSpatialIndexCopyVisitor visitor( mRTree.get() );
286 other.mRTree->intersectsWithQuery( query, visitor );
289 ~QgsMeshSpatialIndexData() =
default;
291 QgsMeshSpatialIndexData &operator=(
const QgsMeshSpatialIndexData &rh ) =
delete;
293 void initTree( IDataStream *inputStream =
nullptr )
296 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
299 const double fillFactor = 0.7;
300 const unsigned int indexCapacity = 10;
301 const unsigned int leafCapacity = 10;
302 const unsigned int dimension = 2;
303 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
306 SpatialIndex::id_type indexId;
308 if ( inputStream && inputStream->hasNext() )
310 RTree::createAndBulkLoadNewRTree(
313 *mStorage, fillFactor,
322 RTree::createNewRTree(
334 std::unique_ptr<SpatialIndex::IStorageManager> mStorage;
337 std::unique_ptr<SpatialIndex::ISpatialIndex> mRTree;
339 mutable QMutex mMutex;
346 d =
new QgsMeshSpatialIndexData;
352 d =
new QgsMeshSpatialIndexData( mesh, feedback,
elementType );
356 : mElementType( other.mElementType )
362 : mElementType( other.mElementType )
363 , d( std::move( other.d ) )
371 if (
this != &other )
373 mElementType = other.mElementType;
381 if (
this != &other )
383 mElementType = std::move( other.mElementType );
384 d = std::move( other.d );
392 QgisMeshVisitor visitor( list );
396 const QMutexLocker locker( &d->mMutex );
397 d->mRTree->intersectsWithQuery( r, visitor );
405 QgisMeshVisitor visitor( list );
407 double pt[2] = { point.
x(), point.
y() };
408 const Point p( pt, 2 );
410 const QMutexLocker locker( &d->mMutex );
411 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
423 if ( mesh.
face( faceIndex ).isEmpty() )
427 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
431 const QMutexLocker locker( &d.constData()->mMutex );
435 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
437 catch ( Tools::Exception &e )
440 QgsDebugError( u
"Tools::Exception caught: "_s.arg( e.what().c_str() ) );
442 catch (
const std::exception &e )
445 QgsDebugError( u
"std::exception caught: "_s.arg( e.what() ) );
449 QgsDebugError( u
"unknown spatial index exception caught"_s );
455 if ( mesh.
face( faceIndex ).isEmpty() )
457 const QMutexLocker locker( &d.constData()->mMutex );
459 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.