27 , mEnableSnappingForInvisibleFeature( enableSnappingForInvisibleFeature )
42 if ( !mLocators.contains( vl ) )
45 mLocators.insert( vl, vlpl );
47 return mLocators.value( vl );
52 qDeleteAll( mLocators );
55 qDeleteAll( mTemporaryLocators );
56 mTemporaryLocators.clear();
62 QgsRectangle aoi( pointMap.
x() - tolerance, pointMap.
y() - tolerance,
63 pointMap.
x() + tolerance, pointMap.
y() + tolerance );
64 if ( isIndexPrepared( vl, aoi ) )
67 return temporaryLocatorForLayer( vl, pointMap, tolerance );
72 if ( mTemporaryLocators.contains( vl ) )
73 delete mTemporaryLocators.take( vl );
75 QgsRectangle rect( pointMap.
x() - tolerance, pointMap.
y() - tolerance,
76 pointMap.
x() + tolerance, pointMap.
y() + tolerance );
78 mTemporaryLocators.insert( vl, vlpl );
79 return mTemporaryLocators.value( vl );
99 if ( segments.isEmpty() )
102 QSet<QgsPointXY> endpoints;
105 QVector<QgsGeometry> geoms;
113 endpoints << pl[0] << pl[1];
120 QList<QgsPointXY> newPoints;
125 if ( !endpoints.contains( p ) )
135 if ( !endpoints.contains( p ) )
141 if ( newPoints.isEmpty() )
146 double minSqrDist = 1e20;
149 double sqrDist = pt.
sqrDist( p.
x(), p.
y() );
150 if ( sqrDist < minSqrDist )
152 minSqrDist = sqrDist;
164 if ( !candidateMatch.
isValid() || candidateMatch.
distance() > maxDistance )
175 bestMatch = candidateMatch;
182 _replaceIfBetter( bestMatch, loc->
nearestVertex( pointMap, tolerance, filter ), tolerance );
186 _replaceIfBetter( bestMatch, loc->
nearestEdge( pointMap, tolerance, filter ), tolerance );
193 _replaceIfBetter( bestMatch, loc->
nearestArea( pointMap, tolerance, filter ), tolerance );
222 return QgsRectangle( point.
x() - tolerance, point.
y() - tolerance,
223 point.
x() + tolerance, point.
y() + tolerance );
235 if ( !mCurrentLayer || mSnappingConfig.
type() == 0 )
240 QgsPointLocator::Types type = _snappingTypeToPointLocatorType( mSnappingConfig.
type() );
242 prepareIndex( QList<LayerAndAreaOfInterest>() << qMakePair( mCurrentLayer,
_areaOfInterest( pointMap, tolerance ) ) );
245 QgsPointLocator *loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
250 _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter );
254 QgsPointLocator *locEdges = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
256 _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), tolerance );
263 QList<LayerAndAreaOfInterest>
layers;
264 Q_FOREACH (
const LayerConfig &layerConfig, mLayers )
269 prepareIndex( layers );
273 double maxSnapIntTolerance = 0;
275 Q_FOREACH (
const LayerConfig &layerConfig, mLayers )
278 if (
QgsPointLocator *loc = locatorForLayerUsingStrategy( layerConfig.
layer, pointMap, tolerance ) )
280 _updateBestMatch( bestMatch, pointMap, loc, layerConfig.
type, tolerance, filter );
285 maxSnapIntTolerance = std::max( maxSnapIntTolerance, tolerance );
291 _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), maxSnapIntTolerance );
299 QgsPointLocator::Types type = _snappingTypeToPointLocatorType( mSnappingConfig.
type() );
302 QList<LayerAndAreaOfInterest>
layers;
304 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
305 layers << qMakePair( vl, aoi );
306 prepareIndex( layers );
311 Q_FOREACH (
const LayerAndAreaOfInterest &entry, layers )
314 if (
QgsPointLocator *loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance ) )
316 _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter );
324 _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), tolerance );
332 void QgsSnappingUtils::prepareIndex(
const QList<LayerAndAreaOfInterest> &
layers )
339 QList<LayerAndAreaOfInterest> layersToIndex;
340 Q_FOREACH (
const LayerAndAreaOfInterest &entry, layers )
347 if ( !isIndexPrepared( vl, entry.second ) )
348 layersToIndex << entry;
350 if ( !layersToIndex.isEmpty() )
357 Q_FOREACH (
const LayerAndAreaOfInterest &entry, layersToIndex )
365 if ( !mEnableSnappingForInvisibleFeature )
380 if ( !mHybridMaxAreaPerLayer.contains( vl->
id() ) )
383 if ( totalFeatureCount < mHybridPerLayerFeatureLimit )
386 mHybridMaxAreaPerLayer[vl->
id()] = -1;
393 double totalArea = layerExtent.
width() * layerExtent.
height();
394 mHybridMaxAreaPerLayer[vl->
id()] = totalArea * mHybridPerLayerFeatureLimit / totalFeatureCount / 4;
398 double indexReasonableArea = mHybridMaxAreaPerLayer[vl->
id()];
399 if ( indexReasonableArea == -1 )
408 double halfSide = std::sqrt( indexReasonableArea ) / 2;
410 c.
x() + halfSide, c.
y() + halfSide );
414 if ( !loc->
init( mHybridPerLayerFeatureLimit ) )
418 mHybridMaxAreaPerLayer[vl->
id()] /= 4;
426 QgsDebugMsg( QString(
"Index init: %1 ms (%2)" ).arg( tt.elapsed() ).arg( vl->
id() ) );
429 QgsDebugMsg( QString(
"Prepare index total: %1 ms" ).arg( t.elapsed() ) );
436 return mSnappingConfig;
441 mEnableSnappingForInvisibleFeature = enable;
446 if ( mSnappingConfig == config )
465 if ( !mCurrentLayer )
471 QgsPointLocator *loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
476 _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter );
484 mMapSettings = settings;
486 if ( newDestCRS != oldDestCRS )
492 mCurrentLayer = layer;
497 QString msg = QStringLiteral(
"--- SNAPPING UTILS DUMP ---\n" );
501 msg += QLatin1String(
"invalid map settings!" );
505 QList<LayerConfig>
layers;
511 msg += QLatin1String(
"no current layer!" );
515 layers <<
LayerConfig( mCurrentLayer, _snappingTypeToPointLocatorType( mSnappingConfig.
type() ), mSnappingConfig.
tolerance(), mSnappingConfig.
units() );
521 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
522 layers <<
LayerConfig( vl, _snappingTypeToPointLocatorType( mSnappingConfig.
type() ), mSnappingConfig.
tolerance(), mSnappingConfig.
units() );
532 msg += QString(
"layer : %1\n" 533 "config: %2 tolerance %3 %4\n" )
541 QString extentStr, cachedGeoms, limit( QStringLiteral(
"no max area" ) );
544 extentStr = QStringLiteral(
" extent %1" ).arg( r->toString() );
547 extentStr = QStringLiteral(
"full extent" );
551 cachedGeoms = QStringLiteral(
"not initialized" );
554 if ( mHybridMaxAreaPerLayer.contains( layer.
layer->
id() ) )
556 double maxArea = mStrategy ==
IndexHybrid ? mHybridMaxAreaPerLayer[layer.
layer->
id()] : -1;
558 limit = QStringLiteral(
"max area %1" ).arg( maxArea );
561 limit = QStringLiteral(
"not evaluated" );
563 msg += QStringLiteral(
"index : YES | %1 | %2 | %3\n" ).arg( cachedGeoms, extentStr, limit );
566 msg += QStringLiteral(
"index : ???\n" );
569 msg += QLatin1String(
"index : NO\n" );
570 msg += QLatin1String(
"-\n" );
581 void QgsSnappingUtils::onIndividualLayerSettingsChanged(
const QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings> &layerSettings )
585 QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings>::const_iterator i;
587 for ( i = layerSettings.constBegin(); i != layerSettings.constEnd(); ++i )
591 mLayers.append(
LayerConfig( i.key(), _snappingTypeToPointLocatorType( i->type() ), i->tolerance(), i->units() ) );
void setEnabled(bool enabled)
enables the snapping
The class defines interface for querying point location:
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
A rectangle specified with double values.
Base class for all map layer types.
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
SnappingType type() const
Returns the type (vertices and/or segments)
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
SnappingMode mode() const
Returns the mode (all layers, active layer, per layer settings)
void setCurrentLayer(QgsVectorLayer *layer)
Sets current layer so that if mode is SnapCurrentLayer we know which layer to use.
~QgsSnappingUtils() override
virtual void prepareIndexProgress(int index)
Called when finished indexing a layer. When index == count the indexing is complete.
QgsPointLocator::Type type() const
Both on vertices and segments.
bool enabled() const
Returns if snapping is enabled.
bool hasIndex() const
Indicate whether the data have been already indexed.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
For all layer build index of extent given in map settings.
A class to represent a 2D point.
Match nearestEdge(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr)
Find nearest edge to the specified point - up to distance specified by tolerance Optional filter may ...
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
class QList< QgsPointLocator::Match > MatchList
A geometry is the spatial representation of a feature.
QgsTolerance::UnitType units() const
Returns the type of units.
Match nearestArea(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr)
Find nearest area to the specified point - up to distance specified by tolerance Optional filter may ...
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
Interface that allows rejection of some matches in intersection queries (e.g.
void setEnableSnappingForInvisibleFeature(bool enable)
Set if invisible features must be snapped or not.
bool intersectionSnapping() const
Returns if the snapping on intersection is enabled.
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
The QgsMapSettings class contains configuration for rendering of the map.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
QgsMultiPolylineXY asMultiPolyline() const
Returns contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
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
For all layers build index of full extent. Uses more memory, but queries are faster.
QgsRectangle extent() const
Returns geographical coordinates of the rectangle that should be rendered.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QString dump()
Gets extra information about the instance.
For "big" layers using IndexNeverFull, for the rest IndexAlwaysFull. Compromise between speed and mem...
QgsRectangle extent() const override
Returns the extent of the layer.
void clearAllLocators()
Deletes all existing locators (e.g. when destination CRS has changed and we need to reindex) ...
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void setRenderContext(const QgsRenderContext *context)
Configure render context - if not null, it will use to index only visible feature.
double width() const
Returns the width of the rectangle.
QList< QgsSnappingUtils::LayerConfig > layers() const
Query layers used for snapping.
Snapped to a vertex. Can be a vertex of the geometry or an intersection.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
QgsRectangle layerExtentToOutputExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from layer's CRS to output CRS
Reads and writes project states.
On a per layer configuration basis.
void setExtent(const QgsRectangle *extent)
Configure extent - if not null, it will index only that area.
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
QgsTolerance::UnitType unit
The units in which the tolerance is specified.
void toggleEnabled()
Toggles the state of snapping.
void setMapSettings(const QgsMapSettings &settings)
Assign current map settings to the utils - used for conversion between screen coords to map coords...
const QgsMapToPixel & mapToPixel() const
double tolerance
The range around snapping targets in which snapping should occur.
const QgsRectangle * extent() const
Gets extent of the area point locator covers - if null then it caches the whole layer.
QgsSnappingConfig config() const
The snapping configuration controls the behavior of this object.
For all layers only create temporary indexes of small extent. Low memory usage, slower queries...
void configChanged(const QgsSnappingConfig &snappingConfig)
Emitted when the snapping settings object changes.
static double vertexSearchRadius(const QgsMapSettings &mapSettings)
Static function to get vertex tolerance value.
int cachedGeometryCount() const
Returns how many geometries are cached in the index.
virtual void prepareIndexStarting(int count)
Called when starting to index - can be overridden and e.g. progress dialog can be provided...
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Contains information about the context of a rendering operation.
QgsPointLocator * locatorForLayer(QgsVectorLayer *vl)
Gets a point locator for the given layer. If such locator does not exist, it will be created...
SnappingType
SnappingType defines on what object the snapping is performed.
static double toleranceInProjectUnits(double tolerance, QgsMapLayer *layer, const QgsMapSettings &mapSettings, QgsTolerance::UnitType units)
Static function to translate tolerance value into map units.
QgsVectorLayer * layer
The layer to configure.
Configures how a certain layer should be handled in a snapping operation.
bool init(int maxFeaturesToIndex=-1)
Prepare the index for queries.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
This class represents a coordinate reference system (CRS).
Match nearestVertex(const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter=nullptr)
Find nearest vertex to the specified point - up to distance specified by tolerance Optional filter ma...
QgsPointLocator::Types type
To which geometry properties of this layers a snapping should happen.
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units...
QgsPolylineXY asPolyline() const
Returns contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
double tolerance() const
Returns the tolerance.
MatchList edgesInRect(const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter=nullptr)
Find edges within a specified recangle Optional filter may discard unwanted matches.
This is a container for configuration of the snapping of the project.
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr)
Snap to map according to the current configuration. Optional filter allows discarding unwanted matche...
QHash< QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings > individualLayerSettings() const
Returns individual snapping settings for all layers.
Represents a vector layer which manages a vector based data sets.
QgsRectangle _areaOfInterest(const QgsPointXY &point, double tolerance)
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
QgsSnappingUtils(QObject *parent=nullptr, bool enableSnappingForInvisibleFeature=true)
Constructor for QgsSnappingUtils.
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
QgsPointXY toMapCoordinates(int x, int y) const
QString authid() const
Returns the authority identifier for the CRS.
double height() const
Returns the height of the rectangle.
QgsPointLocator::Match snapToCurrentLayer(QPoint point, QgsPointLocator::Types type, QgsPointLocator::MatchFilter *filter=nullptr)
Snap to current layer.