21 #include <spatialindex/SpatialIndex.h>
23 #include <QMutexLocker>
30 static 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 );
62 static 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 );
90 class 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
117 class 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;
148 class 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;
236 class QgsMeshSpatialIndexData :
public QSharedData
239 QgsMeshSpatialIndexData()
254 switch ( elementType )
256 case QgsMesh::ElementType::Edge:
258 QgsMeshIteratorDataStream fids( fi, fi.
edgeCount(), edgeToRegion, feedback );
262 case QgsMesh::ElementType::Face:
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 );
365 if (
this != &other )
373 QgisMeshVisitor visitor( list );
375 const SpatialIndex::Region r = rectToRegion( rect );
377 const QMutexLocker locker( &d->mMutex );
378 d->mRTree->intersectsWithQuery( r, visitor );
386 QgisMeshVisitor visitor( list );
388 double pt[2] = { point.
x(), point.
y() };
389 const Point p( pt, 2 );
391 const QMutexLocker locker( &d->mMutex );
392 d->mRTree->nearestNeighborQuery(
static_cast<uint32_t
>( neighbors ), p, visitor );
404 if ( mesh.
face( faceIndex ).isEmpty() )
408 const SpatialIndex::Region r( faceToRegion( mesh, faceIndex, ok ) );
412 const QMutexLocker locker( &d.constData()->mMutex );
416 d.constData()->mRTree->insertData( 0,
nullptr, r, faceIndex );
418 catch ( Tools::Exception &e )
421 QgsDebugMsg( QStringLiteral(
"Tools::Exception caught: " ).arg( e.what().c_str() ) );
423 catch (
const std::exception &e )
426 QgsDebugMsg( QStringLiteral(
"std::exception caught: " ).arg( e.what() ) );
430 QgsDebugMsg( QStringLiteral(
"unknown spatial index exception caught" ) );
436 if ( mesh.
face( faceIndex ).isEmpty() )
438 const QMutexLocker locker( &d.constData()->mMutex );
440 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)
Implement assignment operator.
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 yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
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.