27   , mEnableSnappingForInvisibleFeature( enableSnappingForInvisibleFeature )
 
   42   if ( !mLocators.contains( vl ) )
 
   46     mLocators.insert( vl, vlpl );
 
   48   return mLocators.value( vl );
 
   53   qDeleteAll( mLocators );
 
   56   qDeleteAll( mTemporaryLocators );
 
   57   mTemporaryLocators.clear();
 
   66   QgsRectangle aoi( pointMap.
x() - tolerance, pointMap.
y() - tolerance,
 
   67                     pointMap.
x() + tolerance, pointMap.
y() + tolerance );
 
   71   if ( loc->
isIndexing() || isIndexPrepared( loc, aoi ) )
 
   74     return temporaryLocatorForLayer( vl, pointMap, tolerance );
 
   79   if ( mTemporaryLocators.contains( vl ) )
 
   80     delete mTemporaryLocators.take( vl );
 
   82   QgsRectangle rect( pointMap.
x() - tolerance, pointMap.
y() - tolerance,
 
   83                      pointMap.
x() + tolerance, pointMap.
y() + tolerance );
 
   88   mTemporaryLocators.insert( vl, vlpl );
 
   89   return mTemporaryLocators.value( vl );
 
  107   if ( segments.isEmpty() )
 
  110   QSet<QgsPointXY> endpoints;
 
  113   QVector<QgsGeometry> geoms;
 
  114   const auto constSegments = segments;
 
  120       m.edgePoints( pl[0], pl[1] );
 
  122       endpoints << pl[0] << pl[1];
 
  129   QList<QgsPointXY> newPoints;
 
  135       if ( !endpoints.contains( p ) )
 
  144       const auto constPl = pl;
 
  147         if ( !endpoints.contains( p ) )
 
  153   if ( newPoints.isEmpty() )
 
  158   double minSqrDist = 1e20;  
 
  159   const auto constNewPoints = newPoints;
 
  162     double sqrDist = pt.
sqrDist( p.x(), p.y() );
 
  163     if ( sqrDist < minSqrDist )
 
  165       minSqrDist = sqrDist;
 
  176   if ( !candidateMatch.
isValid() || candidateMatch.
distance() > maxDistance )
 
  196     bestMatch = candidateMatch;
 
  205     bestMatch = candidateMatch;
 
  217   bestMatch = candidateMatch; 
 
  224     _replaceIfBetter( bestMatch, loc->
nearestVertex( pointMap, tolerance, filter, relaxed ), tolerance );
 
  228     _replaceIfBetter( bestMatch, loc->
nearestEdge( pointMap, tolerance, filter, relaxed ), tolerance );
 
  235     _replaceIfBetter( bestMatch, loc->
nearestArea( pointMap, tolerance, filter, relaxed ), tolerance );
 
  239     _replaceIfBetter( bestMatch, loc->
nearestCentroid( pointMap, tolerance, filter ), tolerance );
 
  247     _replaceIfBetter( bestMatch, loc->
nearestLineEndpoints( pointMap, tolerance, filter ), tolerance );
 
  252 static QgsPointLocator::Types _snappingTypeToPointLocatorType( QgsSnappingConfig::SnappingTypeFlag type )
 
  254   return QgsPointLocator::Types( 
static_cast<int>( type ) );
 
  264   return QgsRectangle( point.
x() - tolerance, point.
y() - tolerance,
 
  265                        point.
x() + tolerance, point.
y() + tolerance );
 
  282     QgsPointLocator::Types type = _snappingTypeToPointLocatorType( mSnappingConfig.
typeFlag() );
 
  284     prepareIndex( QList<LayerAndAreaOfInterest>() << qMakePair( mCurrentLayer, 
_areaOfInterest( pointMap, tolerance ) ), relaxed );
 
  287     QgsPointLocator *loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
 
  293     _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter, relaxed );
 
  297       QgsPointLocator *locEdges = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
 
  300       edges = locEdges->
edgesInRect( pointMap, tolerance );
 
  305       QgsPointLocator *loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance );
 
  306       _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter, 
false );
 
  313       _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), tolerance );
 
  320     QList<LayerAndAreaOfInterest> 
layers;
 
  321     QList<LayerConfig> filteredConfigs;
 
  329     for ( 
const LayerConfig &layerConfig : std::as_const( mLayers ) )
 
  344         filteredConfigs << layerConfig;
 
  347     prepareIndex( 
layers, relaxed );
 
  351     double maxTolerance = 0;
 
  354     for ( 
const LayerConfig &layerConfig : std::as_const( filteredConfigs ) )
 
  357       if ( 
QgsPointLocator *loc = locatorForLayerUsingStrategy( layerConfig.layer, pointMap, tolerance ) )
 
  359         _updateBestMatch( bestMatch, pointMap, loc, layerConfig.type, tolerance, filter, relaxed );
 
  366         maxTolerance = std::max( maxTolerance, tolerance );
 
  374       QgsPointLocator *loc = locatorForLayerUsingStrategy( vl, pointMap, maxTolerance );
 
  375       _updateBestMatch( bestMatch, pointMap, loc, maxTypes, maxTolerance, filter, 
false );
 
  377         edges << loc->
edgesInRect( pointMap, maxTolerance );
 
  381       _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), maxTolerance );
 
  389     QgsPointLocator::Types type = _snappingTypeToPointLocatorType( mSnappingConfig.
typeFlag() );
 
  392     QList<LayerAndAreaOfInterest> 
layers;
 
  393     const auto constLayers = mMapSettings.
layers( 
true );
 
  395       if ( 
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
 
  396         layers << qMakePair( vl, aoi );
 
  397     prepareIndex( 
layers, relaxed );
 
  402     for ( 
const LayerAndAreaOfInterest &entry : std::as_const( 
layers ) )
 
  405       if ( 
QgsPointLocator *loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance ) )
 
  407         _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter, relaxed );
 
  416       QgsPointLocator *loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance );
 
  417       _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter, 
false );
 
  423       _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), tolerance );
 
  431 void QgsSnappingUtils::onInitFinished( 
bool ok )
 
  439     mHybridMaxAreaPerLayer[loc->
layer()->
id()] /= 4;
 
  443 void QgsSnappingUtils::prepareIndex( 
const QList<LayerAndAreaOfInterest> &layers, 
bool relaxed )
 
  446   QList<LayerAndAreaOfInterest> layersToIndex;
 
  447   const auto constLayers = 
layers;
 
  448   for ( 
const LayerAndAreaOfInterest &entry : constLayers )
 
  457     if ( !loc->
isIndexing() && !isIndexPrepared( loc, entry.second ) )
 
  458       layersToIndex << entry;
 
  460   if ( !layersToIndex.isEmpty() )
 
  472     for ( 
const LayerAndAreaOfInterest &entry : layersToIndex )
 
  483       if ( !mEnableSnappingForInvisibleFeature )
 
  493         loc->
init( -1, relaxed );
 
  498         if ( !mHybridMaxAreaPerLayer.contains( vl->
id() ) )
 
  501           if ( totalFeatureCount < mHybridPerLayerFeatureLimit )
 
  504             mHybridMaxAreaPerLayer[vl->
id()] = -1;
 
  511             double totalArea = layerExtent.
width() * layerExtent.
height();
 
  512             mHybridMaxAreaPerLayer[vl->
id()] = totalArea * mHybridPerLayerFeatureLimit / totalFeatureCount / 4;
 
  516         double indexReasonableArea = mHybridMaxAreaPerLayer[vl->
id()];
 
  517         if ( indexReasonableArea == -1 )
 
  520           loc->
init( -1, relaxed );
 
  526           double halfSide = std::sqrt( indexReasonableArea ) / 2;
 
  528                              c.x() + halfSide, 
c.y() + halfSide );
 
  532           loc->
init( mHybridPerLayerFeatureLimit, relaxed );
 
  537         loc->
init( relaxed );
 
  545       QgsDebugMsg( QStringLiteral( 
"Prepare index total: %1 ms" ).arg( t.elapsed() ) );
 
  552   return mSnappingConfig;
 
  557   mEnableSnappingForInvisibleFeature = enable;
 
  562   if ( mSnappingConfig == 
config )
 
  581   if ( !mCurrentLayer )
 
  587   QgsPointLocator *loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
 
  592   _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter, 
false );
 
  600   mMapSettings = settings;
 
  602   if ( newDestCRS != oldDestCRS )
 
  608   mCurrentLayer = layer;
 
  613   QString msg = QStringLiteral( 
"--- SNAPPING UTILS DUMP ---\n" );
 
  617     msg += QLatin1String( 
"invalid map settings!" );
 
  621   QList<LayerConfig> 
layers;
 
  627       msg += QLatin1String( 
"no current layer!" );
 
  635     const auto constLayers = mMapSettings.
layers( 
true );
 
  638       if ( 
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
 
  647   const auto constLayers = 
layers;
 
  650     msg += QString( 
"layer : %1\n" 
  651                     "config: %2   tolerance %3 %4\n" )
 
  652            .arg( layer.layer->name() )
 
  653            .arg( layer.type ).arg( layer.tolerance ).arg( layer.unit );
 
  659         QString extentStr, cachedGeoms, limit( QStringLiteral( 
"no max area" ) );
 
  662           extentStr = QStringLiteral( 
" extent %1" ).arg( r->toString() );
 
  665           extentStr = QStringLiteral( 
"full extent" );
 
  669           cachedGeoms = QStringLiteral( 
"not initialized" );
 
  672           if ( mHybridMaxAreaPerLayer.contains( layer.layer->id() ) )
 
  674             double maxArea = mStrategy == 
IndexHybrid ? mHybridMaxAreaPerLayer[layer.layer->id()] : -1;
 
  676               limit = QStringLiteral( 
"max area %1" ).arg( maxArea );
 
  679             limit = QStringLiteral( 
"not evaluated" );
 
  681         msg += QStringLiteral( 
"index : YES | %1 | %2 | %3\n" ).arg( cachedGeoms, extentStr, limit );
 
  684         msg += QLatin1String( 
"index : ???\n" ); 
 
  687       msg += QLatin1String( 
"index : NO\n" );
 
  688     msg += QLatin1String( 
"-\n" );
 
  699 void QgsSnappingUtils::onIndividualLayerSettingsChanged( 
const QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings> &layerSettings )
 
  703   QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings>::const_iterator i;
 
  705   for ( i = layerSettings.constBegin(); i != layerSettings.constEnd(); ++i )
 
  709       mLayers.append( LayerConfig( i.key(), _snappingTypeToPointLocatorType( 
static_cast<QgsSnappingConfig::SnappingTypeFlag
>( i->typeFlag() ) ), i->tolerance(), i->units() ) );
 
This class represents a coordinate reference system (CRS).
 
A geometry is the spatial representation of a feature.
 
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
 
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
 
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
 
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
 
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
 
Base class for all map layer types.
 
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
 
The QgsMapSettings class contains configuration for rendering of the map.
 
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
 
double scale() const
Returns the calculated map scale.
 
QgsRectangle layerExtentToOutputExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from layer's CRS to output CRS
 
const QgsMapToPixel & mapToPixel() const
 
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
 
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
 
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
 
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
 
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
 
The class defines interface for querying point location:
 
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if nullptr then it caches the whole layer.
 
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 ...
 
void setRenderContext(const QgsRenderContext *context)
Configure render context - if not nullptr, it will use to index only visible feature.
 
int cachedGeometryCount() const
Returns how many geometries are cached in the index.
 
void setExtent(const QgsRectangle *extent)
Configure extent - if not nullptr, it will index only that area.
 
bool init(int maxFeaturesToIndex=-1, bool relaxed=false)
Prepare the index for queries.
 
class QList< QgsPointLocator::Match > MatchList
 
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...
 
QgsVectorLayer * layer() const
Gets associated layer.
 
bool isIndexing() const
Returns true if the point locator is currently indexing the data.
 
MatchList edgesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find edges within a specified rectangle Optional filter may discard unwanted matches.
 
bool hasIndex() const
Indicate whether the data have been already indexed.
 
Match nearestMiddleOfSegment(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest middle of segment to the specified point - up to distance specified by tolerance Optiona...
 
void waitForIndexingFinished()
If the point locator has been initialized relaxedly and is currently indexing, this methods waits for...
 
Match nearestCentroid(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest centroid to the specified point - up to distance specified by tolerance Optional filter ...
 
void initFinished(bool ok)
Emitted whenever index has been built and initialization is finished.
 
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 ...
 
Type
The type of a snap result or the filter type for a snap request.
 
@ Area
Snapped to an area.
 
@ MiddleOfSegment
Snapped to the middle of a segment.
 
@ Vertex
Snapped to a vertex. Can be a vertex of the geometry or an intersection.
 
@ Centroid
Snapped to a centroid.
 
@ Edge
Snapped to an edge.
 
@ LineEndpoint
Start or end points of lines only (since QGIS 3.20)
 
Match nearestLineEndpoints(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Find nearest line endpoint (start or end vertex) to the specified point - up to distance specified by...
 
A class to represent a 2D point.
 
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
 
A rectangle specified with double values.
 
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
 
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
 
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
 
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
 
Contains information about the context of a rendering operation.
 
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
 
This is a container of advanced configuration (per layer) of the snapping of the project.
 
double maximumScale() const
Returns max scale on which snapping is limited.
 
double minimumScale() const
Returns minimum scale on which snapping is limited.
 
This is a container for configuration of the snapping of the project.
 
@ ActiveLayer
On the active layer.
 
@ AdvancedConfiguration
On a per layer configuration basis.
 
@ AllLayers
On all vector layers.
 
QgsTolerance::UnitType units() const
Returns the type of units.
 
bool intersectionSnapping() const
Returns if the snapping on intersection is enabled.
 
@ PerLayer
Scale dependency using min max range per layer.
 
@ Disabled
No scale dependency.
 
@ Global
Scale dependency using global min max range.
 
double minimumScale() const
Returns the min scale (i.e.
 
double tolerance() const
Returns the tolerance.
 
double maximumScale() const
Returns the max scale (i.e.
 
SnappingMode mode() const
Returns the mode (all layers, active layer, per layer settings)
 
QgsSnappingConfig::SnappingTypeFlag typeFlag() const
Returns the flags type (vertices | segments | area | centroid | middle)
 
QHash< QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings > individualLayerSettings() const
Returns individual snapping settings for all layers.
 
ScaleDependencyMode scaleDependencyMode() const
Returns the scale dependency mode.
 
void setEnabled(bool enabled)
enables the snapping
 
bool enabled() const
Returns if snapping is enabled.
 
QgsPointLocator::Match snapToCurrentLayer(QPoint point, QgsPointLocator::Types type, QgsPointLocator::MatchFilter *filter=nullptr)
Snap to current layer.
 
void setMapSettings(const QgsMapSettings &settings)
Assign current map settings to the utils - used for conversion between screen coords to map coords.
 
void toggleEnabled()
Toggles the state of snapping.
 
@ IndexAlwaysFull
For all layers build index of full extent. Uses more memory, but queries are faster.
 
@ IndexHybrid
For "big" layers using IndexNeverFull, for the rest IndexAlwaysFull. Compromise between speed and mem...
 
@ IndexExtent
For all layer build index of extent given in map settings.
 
@ IndexNeverFull
For all layers only create temporary indexes of small extent. Low memory usage, slower queries.
 
QList< QgsSnappingUtils::LayerConfig > layers() const
Query layers used for snapping.
 
QgsPointLocator * locatorForLayer(QgsVectorLayer *vl)
Gets a point locator for the given layer.
 
virtual void prepareIndexProgress(int index)
Called when finished indexing a layer with snapToMap. When index == count the indexing is complete.
 
QString dump()
Gets extra information about the instance.
 
void configChanged(const QgsSnappingConfig &snappingConfig)
Emitted when the snapping settings object changes.
 
~QgsSnappingUtils() override
 
void clearAllLocators()
Deletes all existing locators (e.g. when destination CRS has changed and we need to reindex)
 
void setCurrentLayer(QgsVectorLayer *layer)
Sets current layer so that if mode is SnapCurrentLayer we know which layer to use.
 
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
 
QgsSnappingUtils(QObject *parent=nullptr, bool enableSnappingForInvisibleFeature=true)
Constructor for QgsSnappingUtils.
 
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
 
void setEnableSnappingForInvisibleFeature(bool enable)
Set if invisible features must be snapped or not.
 
virtual void prepareIndexStarting(int count)
Called when starting to index with snapToMap - can be overridden and e.g. progress dialog can be prov...
 
static double vertexSearchRadius(const QgsMapSettings &mapSettings)
Static function to get vertex tolerance value.
 
static double toleranceInProjectUnits(double tolerance, QgsMapLayer *layer, const QgsMapSettings &mapSettings, QgsTolerance::UnitType units)
Static function to translate tolerance value into map units.
 
Represents a vector layer which manages a vector based data sets.
 
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
 
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
 
QgsRectangle extent() const FINAL
Returns the extent of the layer.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
 
QgsRectangle _areaOfInterest(const QgsPointXY &point, double tolerance)
 
Interface that allows rejection of some matches in intersection queries (e.g.
 
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units,...
 
QgsPointLocator::Type type() const
 
Configures how a certain layer should be handled in a snapping operation.