21#include <spatialindex/SpatialIndex.h>
23#include <QMutexLocker>
30static 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 );
62static 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 );
90class 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
117class 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;
148class 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;
236class QgsMeshSpatialIndexData :
public QSharedData
239 QgsMeshSpatialIndexData()
254 switch ( elementType )
258 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
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 );
357 : mElementType( other.mElementType )
366 if (
this != &other )
368 mElementType = other.mElementType;
377 QgisMeshVisitor visitor( list );
379 const SpatialIndex::Region r = rectToRegion( rect );
381 const QMutexLocker locker( &d->mMutex );
382 d->mRTree->intersectsWithQuery( r, visitor );
390 QgisMeshVisitor visitor( list );
392 double pt[2] = { point.
x(), point.
y() };
393 const Point p( pt, 2 );
395 const QMutexLocker locker( &d->mMutex );
396 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
408 if ( mesh.
face( faceIndex ).isEmpty() )
412 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
416 const QMutexLocker locker( &d.constData()->mMutex );
420 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
422 catch ( Tools::Exception &e )
425 QgsDebugError( QStringLiteral(
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
427 catch (
const std::exception &e )
430 QgsDebugError( QStringLiteral(
"std::exception caught: " ).arg( e.what() ) );
434 QgsDebugError( QStringLiteral(
"unknown spatial index exception caught" ) );
440 if ( mesh.
face( faceIndex ).isEmpty() )
442 const QMutexLocker locker( &d.constData()->mMutex );
444 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.
A spatial index for QgsMeshFace or QgsMeshEdge objects.
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 class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
#define QgsDebugError(str)
QVector< int > QgsMeshFace
List of vertex indexes.
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
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.