22#include <spatialindex/SpatialIndex.h>
24#include <QMutexLocker>
31static Region faceToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
41 const QVector<QgsMeshVertex> &vertices = mesh.
vertices;
43 double xMinimum = vertices[face[0]].x();
44 double yMinimum = vertices[face[0]].y();
45 double xMaximum = vertices[face[0]].x();
46 double yMaximum = vertices[face[0]].y();
48 for (
int i = 1; i < face.size(); ++i )
50 xMinimum = std::min( vertices[face[i]].x(), xMinimum );
51 yMinimum = std::min( vertices[face[i]].y(), yMinimum );
52 xMaximum = std::max( vertices[face[i]].x(), xMaximum );
53 yMaximum = std::max( vertices[face[i]].y(), yMaximum );
56 double pt1[2] = { xMinimum, yMinimum };
57 double pt2[2] = { xMaximum, yMaximum };
60 return SpatialIndex::Region( pt1, pt2, 2 );
63static Region edgeToRegion(
const QgsMesh &mesh,
int id,
bool &ok )
68 const double xMinimum = std::min( firstVertex.
x(), secondVertex.
x() );
69 const double yMinimum = std::min( firstVertex.
y(), secondVertex.
y() );
70 const double xMaximum = std::max( firstVertex.
x(), secondVertex.
x() );
71 const double yMaximum = std::max( firstVertex.
y(), secondVertex.
y() );
72 double pt1[2] = { xMinimum, yMinimum };
73 double pt2[2] = { xMaximum, yMaximum };
75 return SpatialIndex::Region( pt1, pt2, 2 );
84class QgisMeshVisitor :
public SpatialIndex::IVisitor
87 explicit QgisMeshVisitor( QList<int> &list )
90 void visitNode(
const INode &n )
override
93 void visitData(
const IData &d )
override
95 mList.append(
static_cast<int>( d.getIdentifier() ) );
98 void visitData( std::vector<const IData *> &v )
override
111class QgsMeshSpatialIndexCopyVisitor :
public SpatialIndex::IVisitor
114 explicit QgsMeshSpatialIndexCopyVisitor( SpatialIndex::ISpatialIndex *newIndex )
115 : mNewIndex( newIndex ) {}
117 void visitNode(
const INode &n )
override
120 void visitData(
const IData &d )
override
122 SpatialIndex::IShape *shape =
nullptr;
123 d.getShape( &shape );
124 mNewIndex->insertData( 0,
nullptr, *shape, d.getIdentifier() );
128 void visitData( std::vector<const IData *> &v )
override
132 SpatialIndex::ISpatialIndex *mNewIndex =
nullptr;
142class QgsMeshIteratorDataStream :
public IDataStream
146 explicit QgsMeshIteratorDataStream(
const QgsMesh &mesh,
148 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> featureToRegionFunction,
151 , mFeaturesCount( featuresCount )
152 , mFeatureToRegionFunction( featureToRegionFunction )
153 , mFeedback( feedback )
158 ~QgsMeshIteratorDataStream()
override
164 IData *getNext()
override
166 if ( mFeedback && mFeedback->isCanceled() )
169 RTree::Data *ret = mNextData;
176 bool hasNext()
override
178 return nullptr != mNextData;
182 uint32_t size()
override
184 return static_cast<uint32_t
>( mFeaturesCount );
188 void rewind()
override
196 SpatialIndex::Region r;
197 while ( mIterator < mFeaturesCount )
200 r = mFeatureToRegionFunction( mMesh, mIterator, ok );
203 mNextData =
new RTree::Data( 0,
nullptr, r, mIterator );
218 int mFeaturesCount = 0;
219 std::function<Region(
const QgsMesh &mesh,
int id,
bool &ok )> mFeatureToRegionFunction;
220 RTree::Data *mNextData =
nullptr;
230class QgsMeshSpatialIndexData :
public QSharedData
233 QgsMeshSpatialIndexData()
248 switch ( elementType )
252 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
258 QgsMeshIteratorDataStream fids( fi, fi.
faceCount(), faceToRegion, feedback );
269 QgsMeshSpatialIndexData(
const QgsMeshSpatialIndexData &other )
270 : QSharedData( other )
272 const QMutexLocker locker( &other.mMutex );
277 double low[] = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
278 double high[] = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
279 const SpatialIndex::Region query( low, high, 2 );
280 QgsMeshSpatialIndexCopyVisitor visitor( mRTree.get() );
281 other.mRTree->intersectsWithQuery( query, visitor );
284 ~QgsMeshSpatialIndexData() =
default;
286 QgsMeshSpatialIndexData &operator=(
const QgsMeshSpatialIndexData &rh ) =
delete;
288 void initTree( IDataStream *inputStream =
nullptr )
291 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
294 const double fillFactor = 0.7;
295 const unsigned int indexCapacity = 10;
296 const unsigned int leafCapacity = 10;
297 const unsigned int dimension = 2;
298 const RTree::RTreeVariant variant = RTree::RV_RSTAR;
301 SpatialIndex::id_type indexId;
303 if ( inputStream && inputStream->hasNext() )
305 RTree::createAndBulkLoadNewRTree(
308 *mStorage, fillFactor,
317 RTree::createNewRTree(
329 std::unique_ptr<SpatialIndex::IStorageManager> mStorage;
332 std::unique_ptr<SpatialIndex::ISpatialIndex> mRTree;
334 mutable QMutex mMutex;
341 d =
new QgsMeshSpatialIndexData;
345 : mElementType( elementType )
347 d =
new QgsMeshSpatialIndexData( mesh, feedback,
elementType );
351 : mElementType( other.mElementType )
360 if (
this != &other )
362 mElementType = other.mElementType;
371 QgisMeshVisitor visitor( list );
375 const QMutexLocker locker( &d->mMutex );
376 d->mRTree->intersectsWithQuery( r, visitor );
384 QgisMeshVisitor visitor( list );
386 double pt[2] = { point.
x(), point.
y() };
387 const Point p( pt, 2 );
389 const QMutexLocker locker( &d->mMutex );
390 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
402 if ( mesh.
face( faceIndex ).isEmpty() )
406 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
410 const QMutexLocker locker( &d.constData()->mMutex );
414 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
416 catch ( Tools::Exception &e )
419 QgsDebugError( QStringLiteral(
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
421 catch (
const std::exception &e )
424 QgsDebugError( QStringLiteral(
"std::exception caught: " ).arg( e.what() ) );
428 QgsDebugError( QStringLiteral(
"unknown spatial index exception caught" ) );
434 if ( mesh.
face( faceIndex ).isEmpty() )
436 const QMutexLocker locker( &d.constData()->mMutex );
438 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.
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.
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.