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 );
102 if ( segments.isEmpty() )
105 QSet<QgsPointXY> endpoints;
108 QVector<QgsGeometry> geoms;
116 endpoints << pl[0] << pl[1];
123 QList<QgsPointXY> newPoints;
128 if ( !endpoints.contains( p ) )
138 if ( !endpoints.contains( p ) )
144 if ( newPoints.isEmpty() )
149 double minSqrDist = 1e20;
152 double sqrDist = pt.
sqrDist( p.
x(), p.
y() );
153 if ( sqrDist < minSqrDist )
155 minSqrDist = sqrDist;
167 if ( !candidateMatch.
isValid() || candidateMatch.
distance() > maxDistance )
178 bestMatch = candidateMatch;
185 _replaceIfBetter( bestMatch, loc->
nearestVertex( pointMap, tolerance, filter ), tolerance );
189 _replaceIfBetter( bestMatch, loc->
nearestEdge( pointMap, tolerance, filter ), tolerance );
196 _replaceIfBetter( bestMatch, loc->
nearestArea( pointMap, tolerance, filter ), tolerance );
225 return QgsRectangle( point.
x() - tolerance, point.
y() - tolerance,
226 point.
x() + tolerance, point.
y() + tolerance );
238 if ( !mCurrentLayer || mSnappingConfig.
type() == 0 )
243 QgsPointLocator::Types type = _snappingTypeToPointLocatorType( mSnappingConfig.
type() );
245 prepareIndex( QList<LayerAndAreaOfInterest>() << qMakePair( mCurrentLayer,
_areaOfInterest( pointMap, tolerance ) ) );
248 QgsPointLocator *loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
253 _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter );
257 QgsPointLocator *locEdges = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
259 _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), tolerance );
266 QList<LayerAndAreaOfInterest>
layers;
267 Q_FOREACH (
const LayerConfig &layerConfig, mLayers )
272 prepareIndex( layers );
276 double maxSnapIntTolerance = 0;
278 Q_FOREACH (
const LayerConfig &layerConfig, mLayers )
281 if (
QgsPointLocator *loc = locatorForLayerUsingStrategy( layerConfig.
layer, pointMap, tolerance ) )
283 _updateBestMatch( bestMatch, pointMap, loc, layerConfig.
type, tolerance, filter );
288 maxSnapIntTolerance = std::max( maxSnapIntTolerance, tolerance );
294 _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), maxSnapIntTolerance );
302 QgsPointLocator::Types type = _snappingTypeToPointLocatorType( mSnappingConfig.
type() );
305 QList<LayerAndAreaOfInterest>
layers;
307 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
308 layers << qMakePair( vl, aoi );
309 prepareIndex( layers );
314 Q_FOREACH (
const LayerAndAreaOfInterest &entry, layers )
317 if (
QgsPointLocator *loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance ) )
319 _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter );
327 _replaceIfBetter( bestMatch, _findClosestSegmentIntersection( pointMap, edges ), tolerance );
335 void QgsSnappingUtils::prepareIndex(
const QList<LayerAndAreaOfInterest> &
layers )
342 QList<LayerAndAreaOfInterest> layersToIndex;
343 Q_FOREACH (
const LayerAndAreaOfInterest &entry, layers )
350 if ( !isIndexPrepared( vl, entry.second ) )
351 layersToIndex << entry;
353 if ( !layersToIndex.isEmpty() )
360 Q_FOREACH (
const LayerAndAreaOfInterest &entry, layersToIndex )
368 if ( !mEnableSnappingForInvisibleFeature )
383 if ( !mHybridMaxAreaPerLayer.contains( vl->
id() ) )
386 if ( totalFeatureCount < mHybridPerLayerFeatureLimit )
389 mHybridMaxAreaPerLayer[vl->
id()] = -1;
396 double totalArea = layerExtent.
width() * layerExtent.
height();
397 mHybridMaxAreaPerLayer[vl->
id()] = totalArea * mHybridPerLayerFeatureLimit / totalFeatureCount / 4;
401 double indexReasonableArea = mHybridMaxAreaPerLayer[vl->
id()];
402 if ( indexReasonableArea == -1 )
411 double halfSide = std::sqrt( indexReasonableArea ) / 2;
413 c.
x() + halfSide, c.
y() + halfSide );
417 if ( !loc->
init( mHybridPerLayerFeatureLimit ) )
421 mHybridMaxAreaPerLayer[vl->
id()] /= 4;
429 QgsDebugMsg( QStringLiteral(
"Index init: %1 ms (%2)" ).arg( tt.elapsed() ).arg( vl->
id() ) );
432 QgsDebugMsg( QStringLiteral(
"Prepare index total: %1 ms" ).arg( t.elapsed() ) );
439 return mSnappingConfig;
444 mEnableSnappingForInvisibleFeature = enable;
449 if ( mSnappingConfig == config )
468 if ( !mCurrentLayer )
474 QgsPointLocator *loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
479 _updateBestMatch( bestMatch, pointMap, loc, type, tolerance, filter );
487 mMapSettings = settings;
489 if ( newDestCRS != oldDestCRS )
495 mCurrentLayer = layer;
500 QString msg = QStringLiteral(
"--- SNAPPING UTILS DUMP ---\n" );
504 msg += QLatin1String(
"invalid map settings!" );
508 QList<LayerConfig>
layers;
514 msg += QLatin1String(
"no current layer!" );
518 layers <<
LayerConfig( mCurrentLayer, _snappingTypeToPointLocatorType( mSnappingConfig.
type() ), mSnappingConfig.
tolerance(), mSnappingConfig.
units() );
524 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
525 layers <<
LayerConfig( vl, _snappingTypeToPointLocatorType( mSnappingConfig.
type() ), mSnappingConfig.
tolerance(), mSnappingConfig.
units() );
535 msg += QString(
"layer : %1\n" 536 "config: %2 tolerance %3 %4\n" )
544 QString extentStr, cachedGeoms, limit( QStringLiteral(
"no max area" ) );
547 extentStr = QStringLiteral(
" extent %1" ).arg( r->toString() );
550 extentStr = QStringLiteral(
"full extent" );
554 cachedGeoms = QStringLiteral(
"not initialized" );
557 if ( mHybridMaxAreaPerLayer.contains( layer.
layer->
id() ) )
559 double maxArea = mStrategy ==
IndexHybrid ? mHybridMaxAreaPerLayer[layer.
layer->
id()] : -1;
561 limit = QStringLiteral(
"max area %1" ).arg( maxArea );
564 limit = QStringLiteral(
"not evaluated" );
566 msg += QStringLiteral(
"index : YES | %1 | %2 | %3\n" ).arg( cachedGeoms, extentStr, limit );
569 msg += QStringLiteral(
"index : ???\n" );
572 msg += QLatin1String(
"index : NO\n" );
573 msg += QLatin1String(
"-\n" );
584 void QgsSnappingUtils::onIndividualLayerSettingsChanged(
const QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings> &layerSettings )
588 QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings>::const_iterator i;
590 for ( i = layerSettings.constBegin(); i != layerSettings.constEnd(); ++i )
594 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.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
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 the contents of the geometry as a multi-linestring.
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.
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...
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.
QgsRectangle extent() const FINAL
Returns the extent of the layer.
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 the contents of the geometry as a polyline.
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...
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
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
Transform device coordinates to map (world) coordinates.
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.