30 #include <spatialindex/SpatialIndex.h> 32 #include <QLinkedListIterator> 33 #include <QtConcurrent> 39 static SpatialIndex::Point point2point(
const QgsPointXY &point )
41 double plow[2] = { point.
x(), point.
y() };
42 return Point( plow, 2 );
46 static SpatialIndex::Region rect2region(
const QgsRectangle &rect )
50 return SpatialIndex::Region( pLow, pHigh, 2 );
58 static const double POINT_LOC_EPSILON = 1e-12;
72 : mDataList( dataList )
76 IData *
getNext()
override {
return mIt.next(); }
77 bool hasNext()
override {
return mIt.hasNext(); }
79 uint32_t
size()
override { Q_ASSERT(
false &&
"not available" );
return 0; }
80 void rewind()
override { Q_ASSERT(
false &&
"not available" ); }
83 QLinkedList<RTree::Data *> mDataList;
84 QLinkedListIterator<RTree::Data *> mIt;
102 , mSrcPoint( srcPoint )
106 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
107 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
113 int vertexIndex, beforeVertex, afterVertex;
122 if ( mFilter && !mFilter->acceptMatch( m ) )
125 if ( !mBest.isValid() || m.
distance() < mBest.distance() )
151 , mSrcPoint( srcPoint )
155 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
156 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
169 edgePoints[0] = geom->
vertexAt( afterVertex - 1 );
170 edgePoints[1] = geom->
vertexAt( afterVertex );
173 if ( mFilter && !mFilter->acceptMatch( m ) )
176 if ( !mBest.isValid() || m.
distance() < mBest.distance() )
205 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
206 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
232 static const int INSIDE = 0;
235 static const int BOTTOM = 4;
236 static const int TOP = 8;
242 OutCode code = INSIDE;
257 OutCode outcode0 = computeOutCode( x0, y0 );
258 OutCode outcode1 = computeOutCode( x1, y1 );
263 if ( !( outcode0 | outcode1 ) )
269 else if ( outcode0 & outcode1 )
281 OutCode outcodeOut = outcode0 ? outcode0 : outcode1;
285 if ( outcodeOut & TOP )
288 x = x0 + ( x1 - x0 ) * ( mRect.
yMaximum() - y0 ) / ( y1 - y0 );
291 else if ( outcodeOut & BOTTOM )
294 x = x0 + ( x1 - x0 ) * ( mRect.
yMinimum() - y0 ) / ( y1 - y0 );
297 else if ( outcodeOut & RIGHT )
300 y = y0 + ( y1 - y0 ) * ( mRect.
xMaximum() - x0 ) / ( x1 - x0 );
303 else if ( outcodeOut & LEFT )
306 y = y0 + ( y1 - y0 ) * ( mRect.
xMinimum() - x0 ) / ( x1 - x0 );
314 if ( outcodeOut == outcode0 )
318 outcode0 = computeOutCode( x0, y0 );
324 outcode1 = computeOutCode( x1, y1 );
359 if ( qgsgeometry_cast<QgsLineString *>( *part )->numPoints() < 2 )
365 while ( it != ( *part )->vertices_end() )
371 edgePoints[0] = prevPoint;
372 edgePoints[1] = thisPoint;
395 , mSrcRect( srcRect )
399 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
400 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
407 const auto segmentsInRect {_geometrySegmentsInRect( geom, mSrcRect, mLocator->mLayer,
id )};
411 if ( mFilter && !mFilter->acceptMatch( m ) )
440 , mSrcRect( srcRect )
444 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
445 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
450 const QgsGeometry *geom = mLocator->mGeoms.value(
id );
454 if ( mSrcRect.contains( *it ) )
459 if ( mFilter && !mFilter->acceptMatch( m ) )
490 void getNextEntry(
const IEntry &entry, id_type &nextEntry,
bool &hasNext )
override 492 const INode *n =
dynamic_cast<const INode *
>( &entry );
496 QgsDebugMsgLevel( QStringLiteral(
"NODE: %1" ).arg( n->getIdentifier() ), 4 );
497 if ( n->getLevel() > 0 )
500 for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
502 QgsDebugMsgLevel( QStringLiteral(
"- CH: %1" ).arg( n->getChildIdentifier( cChild ) ), 4 );
503 ids.push( n->getChildIdentifier( cChild ) );
509 for ( uint32_t cChild = 0; cChild < n->getChildrenCount(); cChild++ )
511 QgsDebugMsgLevel( QStringLiteral(
"- L: %1" ).arg( n->getChildIdentifier( cChild ) ), 4 );
517 nextEntry = ids.back();
539 mStorage.reset( StorageManager::createNewMemoryStorageManager() );
552 mIsDestroying =
true;
570 mExtent.reset( extent ?
new QgsRectangle( *extent ) :
nullptr );
584 mContext.reset(
nullptr );
588 mContext = std::unique_ptr<QgsRenderContext>(
new QgsRenderContext( *context ) );
594 void QgsPointLocator::onInitTaskFinished()
610 onFeatureAdded( fid );
611 mAddedFeatures.clear();
614 onFeatureDeleted( fid );
615 mDeletedFeatures.clear();
641 connect( mInitTask, &QgsPointLocatorInitTask::taskTerminated,
this, &QgsPointLocator::onInitTaskFinished );
642 connect( mInitTask, &QgsPointLocatorInitTask::taskCompleted,
this, &QgsPointLocator::onInitTaskFinished );
657 mInitTask->waitForFinished();
659 if ( !mIsDestroying )
660 onInitTaskFinished();
665 return mIsIndexing || mRTree || mIsEmptyLayer;
668 bool QgsPointLocator::prepare(
bool relaxed )
681 if ( ( relaxed && mIsIndexing ) || !mRTree )
693 QgsDebugMsg( QStringLiteral(
"RebuildIndex start : %1" ).arg( mSource->id() ) );
697 QLinkedList<RTree::Data *> dataList;
716 QgsDebugMsg( QStringLiteral(
"could not transform bounding box to map, skipping the snap filter (%1)" ).arg( e.
what() ) );
726 ctx = mContext.get();
730 mRenderer->startRender( *ctx, mSource->fields() );
737 int indexedCount = 0;
744 if ( filter && ctx && mRenderer )
747 if ( !mRenderer->willRenderFeature( f, *ctx ) )
758 transformedGeometry.
transform( mTransform );
765 QgsDebugMsg( QStringLiteral(
"could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.
what() ) );
773 SpatialIndex::Region r( rect2region( bbox ) );
774 dataList <<
new RTree::Data( 0,
nullptr, r, f.
id() );
776 if ( mGeoms.contains( f.
id() ) )
777 delete mGeoms.take( f.
id() );
782 if ( maxFeaturesToIndex != -1 && indexedCount > maxFeaturesToIndex )
784 qDeleteAll( dataList );
791 double fillFactor = 0.7;
792 unsigned long indexCapacity = 10;
793 unsigned long leafCapacity = 10;
794 unsigned long dimension = 2;
795 RTree::RTreeVariant variant = RTree::RV_RSTAR;
796 SpatialIndex::id_type indexId;
798 if ( dataList.isEmpty() )
800 mIsEmptyLayer =
true;
805 mRTree.reset( RTree::createAndBulkLoadNewRTree( RTree::BLM_STR, stream, *mStorage, fillFactor, indexCapacity,
806 leafCapacity, dimension, variant, indexId ) );
808 if ( ctx && mRenderer )
810 mRenderer->stopRender( *ctx );
813 QgsDebugMsg( QStringLiteral(
"RebuildIndex end : %1 ms (%2)" ).arg( t.elapsed() ).arg( mSource->id() ) );
823 mIsEmptyLayer =
false;
825 qDeleteAll( mGeoms );
830 void QgsPointLocator::onFeatureAdded(
QgsFeatureId fid )
835 mAddedFeatures << fid;
844 mIsEmptyLayer =
false;
858 std::unique_ptr< QgsFeatureRenderer > renderer( mLayer->
renderer() ? mLayer->
renderer()->
clone() : nullptr );
862 ctx = mContext.get();
863 if ( renderer && ctx )
866 renderer->startRender( *ctx, mLayer->
fields() );
868 ctx->expressionContext().setFeature( f );
869 if ( !renderer->willRenderFeature( f, *ctx ) )
874 renderer->stopRender( *ctx );
892 QgsDebugMsg( QStringLiteral(
"could not transform geometry to map, skipping the snap for it (%1)" ).arg( e.
what() ) );
900 SpatialIndex::Region r( rect2region( bbox ) );
901 mRTree->insertData( 0,
nullptr, r, f.
id() );
903 if ( mGeoms.contains( f.
id() ) )
904 delete mGeoms.take( f.
id() );
910 void QgsPointLocator::onFeatureDeleted(
QgsFeatureId fid )
914 if ( mAddedFeatures.contains( fid ) )
916 mAddedFeatures.remove( fid );
921 mDeletedFeatures << fid;
929 if ( mGeoms.contains( fid ) )
931 mRTree->deleteData( rect2region( mGeoms[fid]->boundingBox() ), fid );
932 delete mGeoms.take( fid );
940 onFeatureDeleted( fid );
941 onFeatureAdded( fid );
944 void QgsPointLocator::onAttributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
950 onFeatureDeleted( fid );
951 onFeatureAdded( fid );
958 if ( !prepare( relaxed ) )
963 QgsRectangle rect( point.
x() - tolerance, point.
y() - tolerance, point.
x() + tolerance, point.
y() + tolerance );
964 mRTree->intersectsWithQuery( rect2region( rect ), visitor );
972 if ( !prepare( relaxed ) )
981 QgsRectangle rect( point.
x() - tolerance, point.
y() - tolerance, point.
x() + tolerance, point.
y() + tolerance );
982 mRTree->intersectsWithQuery( rect2region( rect ), visitor );
990 if ( !prepare( relaxed ) )
994 if ( !mlist.isEmpty() && mlist.at( 0 ).isValid() )
996 return mlist.at( 0 );
999 if ( tolerance == 0 )
1020 if ( !prepare( relaxed ) )
1029 mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1036 QgsRectangle rect( point.
x() - tolerance, point.
y() - tolerance, point.
x() + tolerance, point.
y() + tolerance );
1042 if ( !prepare( relaxed ) )
1047 mRTree->intersectsWithQuery( rect2region( rect ), visitor );
1054 QgsRectangle rect( point.
x() - tolerance, point.
y() - tolerance, point.
x() + tolerance, point.
y() + tolerance );
1060 if ( !prepare( relaxed ) )
1069 mRTree->intersectsWithQuery( point2point( point ), visitor );
The class defines interface for querying point location:
Wrapper for iterator of features from vector data provider or vector layer.
void initFinished(bool ok)
Emitted whenever index has been built and initialization is finished.
double closestSegmentWithContext(const QgsPointXY &point, QgsPointXY &minDistPoint, int &afterVertex, int *leftOf=nullptr, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
void visitData(std::vector< const IData *> &v) override
A rectangle specified with double values.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
MatchList verticesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find vertices within a specified recangle This method is either blocking or non blocking according to...
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
Match nearestVertex(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest vertex to the specified point - up to distance specified by tolerance Optional filter ma...
void visitData(const IData &d) override
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
bool hasIndex() const
Indicate whether the data have been already indexed.
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ...
QgsPointLocator_VisitorArea(QgsPointLocator *pl, const QgsPointXY &origPt, QgsPointLocator::MatchList &list)
constructor
A class to represent a 2D point.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry...
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
MatchList pointInPolygon(const QgsPointXY &point, bool relaxed=false)
find out if the point is in any polygons This method is either blocking or non blocking according to ...
QgsCoordinateReferenceSystem destinationCrs() const
Gets destination CRS - may be an invalid QgsCoordinateReferenceSystem if not doing OTF reprojection...
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsPointLocator_VisitorVerticesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
Constructs the visitor.
class QList< QgsPointLocator::Match > MatchList
Helper class used when traversing the index looking for edges - builds a list of matches.
A geometry is the spatial representation of a feature.
bool rebuildIndex(int maxFeaturesToIndex=-1)
void visitNode(const INode &n) override
Match nearestEdge(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest edge to the specified point - up to distance specified by tolerance Optional filter may ...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Interface that allows rejection of some matches in intersection queries (e.g.
void waitForIndexingFinished()
If the point locator has been initialized relaxedly and is currently indexing, this methods waits for...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void visitData(std::vector< const IData *> &v) override
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type. ...
void styleChanged()
Signal emitted whenever a change affects the layer's style.
QgsPointLocator_Stream(const QLinkedList< RTree::Data *> &dataList)
QgsPointXY closestVertex(const QgsPointXY &point, int &atVertex, int &beforeVertex, int &afterVertex, double &sqrDist) const
Returns the vertex closest to the given point, the corresponding vertex index, squared distance snap ...
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling...
~QgsPointLocator() override
QgsFields fields() const FINAL
Returns the list of fields of this layer.
#define QgsDebugMsgLevel(str, level)
QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
OutCode computeOutCode(double x, double y)
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
void setRenderContext(const QgsRenderContext *context)
Configure render context - if not nullptr, it will use to index only visible feature.
Snapped to a vertex. Can be a vertex of the geometry or an intersection.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Helper class to dump the R-index nodes and their content.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool isSegmentInRect(double x0, double y0, double x1, double y1)
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
void visitNode(const INode &n) override
void setExtent(const QgsRectangle *extent)
Configure extent - if not nullptr, it will index only that area.
Helper class used when traversing the index with areas - builds a list of matches.
QgsFeatureRenderer * renderer()
Returns renderer.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
Contains information about the context in which a coordinate transform is executed.
The vertex_iterator class provides STL-style iterator for vertices.
void visitData(const IData &d) override
Helper class used when traversing the index looking for vertices - builds a list of matches...
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if nullptr then it caches the whole layer...
void visitData(std::vector< const IData *> &v) override
void visitNode(const INode &n) override
bool isFinite() const
Returns true if the rectangle has finite boundaries.
MatchList edgesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find edges within a specified recangle Optional filter may discard unwanted matches.
Partial snapshot of vector layer's state (only the members necessary for access to features) ...
IData * getNext() override
void visitData(std::vector< const IData *> &v) override
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QgsExpressionContext & expressionContext()
Gets the expression context.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
QgsPointLocator(QgsVectorLayer *layer, const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateTransformContext &transformContext=QgsCoordinateTransformContext(), const QgsRectangle *extent=nullptr)
Construct point locator for a layer.
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords...
Contains information about the context of a rendering operation.
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
void visitData(std::vector< const IData *> &v) override
QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)
Helper class for bulk loading of R-trees.
int vertexNrFromVertexId(QgsVertexId id) const
Returns the vertex number corresponding to a vertex id.
void visitData(const IData &d) override
void visitNode(const INode &n) override
bool init(int maxFeaturesToIndex=-1, bool relaxed=false)
Prepare the index for queries.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
_CohenSutherland(const QgsRectangle &rect)
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
void getNextEntry(const IEntry &entry, id_type &nextEntry, bool &hasNext) override
void visitData(const IData &d) override
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Match nearestArea(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest area to the specified point - up to distance specified by tolerance Optional filter may ...
friend class QgsPointLocatorInitTask
void dataChanged()
Data of layer changed.
Helper class used when traversing the index looking for vertices - builds a list of matches...
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units...
QgsGeometry convertToType(QgsWkbTypes::GeometryType destType, bool destMultipart=false) const
Try to convert the geometry to the requested type.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Helper class used when traversing the index looking for edges - builds a list of matches.
void visitNode(const INode &n) override
QgsWkbTypes::GeometryType type
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
QgsFeatureId featureId() const
The id of the feature to which the snapped geometry belongs.
bool nextFeature(QgsFeature &f)
Represents a vector layer which manages a vector based data sets.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry...
Defines a QGIS exception class.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
void visitData(const IData &d) override
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)
QgsCoordinateReferenceSystem crs
bool isValid() const
Returns whether this CRS is correctly initialized and usable.