26 , mCurrentLayer( nullptr )
27 , mSnapToMapMode( SnapCurrentLayer )
28 , mStrategy( IndexHybrid )
30 , mDefaultTolerance( 10 )
32 , mSnapOnIntersection( false )
33 , mHybridPerLayerFeatureLimit( 50000 )
34 , mIsIndexing( false )
53 mLocators.
insert( vl, vlpl );
55 return mLocators.
value( vl );
58 void QgsSnappingUtils::clearAllLocators()
66 mTemporaryLocators.
clear();
72 QgsRectangle aoi( pointMap.
x() - tolerance, pointMap.
y() - tolerance,
73 pointMap.
x() + tolerance, pointMap.
y() + tolerance );
74 if ( isIndexPrepared( vl, aoi ) )
77 return temporaryLocatorForLayer( vl, pointMap, tolerance );
82 if ( mTemporaryLocators.
contains( vl ) )
83 delete mTemporaryLocators.
take( vl );
85 QgsRectangle rect( pointMap.
x() - tolerance, pointMap.
y() - tolerance,
86 pointMap.
x() + tolerance, pointMap.
y() + tolerance );
88 mTemporaryLocators.
insert( vl, vlpl );
89 return mTemporaryLocators.
value( vl );
111 if ( segments.isEmpty() )
125 endpoints << pl[0] << pl[1];
160 double minSqrDist = 1e20;
161 Q_FOREACH (
const QgsPoint& p, newPoints )
163 double sqrDist = pt.
sqrDist( p.
x(), p.
y() );
164 if ( sqrDist < minSqrDist )
166 minSqrDist = sqrDist;
213 return QgsRectangle( point.
x() - tolerance, point.
y() - tolerance,
214 point.
x() + tolerance, point.
y() + tolerance );
224 if ( !mCurrentLayer || mDefaultType == 0 )
229 int type = mDefaultType;
234 QgsPointLocator* loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
241 if ( mSnapOnIntersection )
243 QgsPointLocator* locEdges = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
253 Q_FOREACH (
const LayerConfig& layerConfig, mLayers )
258 prepareIndex( layers );
262 double maxSnapIntTolerance = 0;
264 Q_FOREACH (
const LayerConfig& layerConfig, mLayers )
267 if (
QgsPointLocator* loc = locatorForLayerUsingStrategy( layerConfig.
layer, pointMap, tolerance ) )
271 if ( mSnapOnIntersection )
273 edges << loc->edgesInRect( pointMap, tolerance );
274 maxSnapIntTolerance = qMax( maxSnapIntTolerance, tolerance );
279 if ( mSnapOnIntersection )
288 int type = mDefaultType;
294 layers << qMakePair( vl, aoi );
295 prepareIndex( layers );
303 if (
QgsPointLocator* loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance ) )
307 if ( mSnapOnIntersection )
308 edges << loc->edgesInRect( pointMap, tolerance );
312 if ( mSnapOnIntersection )
336 if ( !isIndexPrepared( vl, entry.second ) )
337 layersToIndex << entry;
339 if ( !layersToIndex.
isEmpty() )
355 if ( !mHybridMaxAreaPerLayer.
contains( vl->
id() ) )
358 if ( totalFeatureCount < mHybridPerLayerFeatureLimit )
361 mHybridMaxAreaPerLayer[vl->
id()] = -1;
368 double totalArea = layerExtent.
width() * layerExtent.
height();
369 mHybridMaxAreaPerLayer[vl->
id()] = totalArea * mHybridPerLayerFeatureLimit / totalFeatureCount / 4;
373 double indexReasonableArea = mHybridMaxAreaPerLayer[vl->
id()];
374 if ( indexReasonableArea == -1 )
383 double halfSide = sqrt( indexReasonableArea ) / 2;
385 c.
x() + halfSide, c.
y() + halfSide );
389 if ( !loc->
init( mHybridPerLayerFeatureLimit ) )
393 mHybridMaxAreaPerLayer[vl->
id()] /= 4;
412 if ( !mCurrentLayer )
418 QgsPointLocator* loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
431 mMapSettings = settings;
433 if ( newDestCRS != oldDestCRS )
439 mCurrentLayer = layer;
444 if ( mSnapToMapMode == mode )
447 mSnapToMapMode = mode;
457 if ( mDefaultType == type && mDefaultTolerance == tolerance && mDefaultUnit == unit )
461 mDefaultTolerance = tolerance;
471 tolerance = mDefaultTolerance;
477 if ( mLayers == layers )
487 if ( mSnapOnIntersection == enabled )
490 mSnapOnIntersection = enabled;
496 QString msg =
"--- SNAPPING UTILS DUMP ---\n";
500 msg +=
"invalid map settings!";
510 msg +=
"no current layer!";
514 layers <<
LayerConfig( mCurrentLayer, QgsPointLocator::Types( mDefaultType ), mDefaultTolerance, mDefaultUnit );
521 layers <<
LayerConfig( vl, QgsPointLocator::Types( mDefaultType ), mDefaultTolerance, mDefaultUnit );
532 "config: %2 tolerance %3 %4\n" )
540 QString extentStr, cachedGeoms, limit(
"no max area" );
543 extentStr =
QString(
" extent %1" ).
arg( r->toString() );
546 extentStr =
"full extent";
547 if ( loc->hasIndex() )
548 cachedGeoms =
QString(
"%1 feats" ).
arg( loc->cachedGeometryCount() );
550 cachedGeoms =
"not initialized";
555 double maxArea = mStrategy ==
IndexHybrid ? mHybridMaxAreaPerLayer[layer.
layer->
id()] : -1;
557 limit =
QString(
"max area %1" ).
arg( maxArea );
560 limit =
"not evaluated";
562 msg +=
QString(
"index : YES | %1 | %2 | %3\n" ).
arg( cachedGeoms ).
arg( extentStr ).
arg( limit );
565 msg +=
QString(
"index : ???\n" );
568 msg +=
"index : NO\n";
590 if ( snapType ==
"to segment" )
592 else if ( snapType ==
"to vertex and segment" )
594 else if ( snapType ==
"to vertex" )
604 bool snappingDefinedInProject, ok;
612 if ( layerIdList.
size() != enabledList.
size() ||
613 layerIdList.
size() != toleranceList.
size() ||
614 layerIdList.
size() != toleranceUnitList.
size() ||
615 layerIdList.
size() != snapToList.
size() )
618 if ( !snappingDefinedInProject )
622 if ( snapMode ==
"current_layer" )
624 else if ( snapMode ==
"all_layers" )
637 for ( ; layerIt != layerIdList.
constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt )
640 if ( *enabledIt !=
"enabled" )
658 void QgsSnappingUtils::onLayersWillBeRemoved(
const QStringList& layerIds )
661 Q_FOREACH (
const QString& layerId, layerIds )
663 if ( mHybridMaxAreaPerLayer.
contains( layerId ) )
664 mHybridMaxAreaPerLayer.
remove( layerId );
668 if ( it.key()->id() == layerId )
671 it = mLocators.
erase( it );
681 if ( it.key()->id() == layerId )
684 it = mTemporaryLocators.
erase( it );
The class defines interface for querying point location:
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
A rectangle specified with double values.
void setSnapOnIntersections(bool enabled)
Set whether to consider intersections of nearby segments for snapping.
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=nullptr) const
QGis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
iterator erase(iterator pos)
bool contains(const Key &key) const
void setCurrentLayer(QgsVectorLayer *layer)
Set current layer so that if mode is SnapCurrentLayer we know which layer to use. ...
virtual void prepareIndexProgress(int index)
Called when finished indexing a layer. When index == count the indexing is complete.
snap to all rendered layers (tolerance and type from defaultSettings())
QList< LayerConfig > layers() const
Query layers used for snapping.
bool hasIndex() const
Indicate whether the data have been already indexed.
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *theLayer, QgsRectangle extent) const
transform bounding box from layer's CRS to output CRS
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
UnitType
Type of unit of tolerance value from settings.
QgsPoint toMapCoordinates(int x, int y) const
A geometry is the spatial representation of a feature.
Interface that allows rejection of some matches in intersection queries (e.g.
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
QgsPolyline asPolyline() const
Return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
void readConfigFromProject()
Read snapping configuration from the project.
double y() const
Get the y value of the point.
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
The QgsMapSettings class contains configuration for rendering of the map.
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
For all layers build index of full extent. Uses more memory, but queries are faster.
int count(const T &value) const
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
QgsRectangle extent() override
Return the extent of the layer.
QString dump()
Get extra information about the instance.
For "big" layers using IndexNeverFull, for the rest IndexAlwaysFull. Compromise between speed and mem...
void setSnapToMapMode(SnapToMapMode mode)
Set how the snapping to map is done.
static void _updateBestMatch(QgsPointLocator::Match &bestMatch, const QgsPoint &pointMap, QgsPointLocator *loc, int type, double tolerance, QgsPointLocator::MatchFilter *filter)
Match nearestEdge(const QgsPoint &point, double tolerance, MatchFilter *filter=nullptr)
Find nearest edges to the specified point - up to distance specified by tolerance Optional filter may...
double width() const
Width of the rectangle.
This is the class is providing tolerance value in map unit values.
QgsSnappingUtils(QObject *parent=nullptr)
static void _replaceIfBetter(QgsPointLocator::Match &mBest, const QgsPointLocator::Match &mNew, double maxDistance)
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
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.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QgsTolerance::UnitType unit
The units in which the tolerance is specified.
int remove(const Key &key)
snap according to the configuration set in setLayers()
void configChanged()
Emitted when snapping configuration has been changed.
void setMapSettings(const QgsMapSettings &settings)
Assign current map settings to the utils - used for conversion between screen coords to map coords...
class QList< Match > MatchList
A class to represent a point.
const QgsMapToPixel & mapToPixel() const
double tolerance
The range around snapping targets in which snapping should occur.
const QgsRectangle * extent() const
Get extent of the area point locator covers - if null then it caches the whole layer.
For all layers only create temporary indexes of small extent. Low memory usage, slower queries...
bool contains(const T &value) const
static QgsPointLocator::Match _findClosestSegmentIntersection(const QgsPoint &pt, const QgsPointLocator::MatchList &segments)
long pendingFeatureCount() const
Returns feature count including changes which have not yet been committed Alias for featureCount()...
static QgsGeometry * unaryUnion(const QList< QgsGeometry *> &geometryList)
Compute the unary union on a list of geometries.
static double vertexSearchRadius(const QgsMapSettings &mapSettings)
Static function to get vertex tolerance value.
virtual void prepareIndexStarting(int count)
Called when starting to index - can be overridden and e.g. progress dialog can be provided...
QgsPointLocator::Match snapToCurrentLayer(QPoint point, int type, QgsPointLocator::MatchFilter *filter=nullptr)
Snap to current layer.
QgsPointLocator * locatorForLayer(QgsVectorLayer *vl)
Get a point locator for the given layer.
QString name() const
Get the display name of the layer.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
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.
MatchList edgesInRect(const QgsRectangle &rect, MatchFilter *filter=nullptr)
Find edges within a specified recangle Optional filter may discard unwanted matches.
static QgsProject * instance()
access to canonical QgsProject instance
Class for storing a coordinate reference system (CRS)
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
Creates a new geometry from a QgsPolyline object.
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...
double readDoubleEntry(const QString &scope, const QString &key, double def=0, bool *ok=nullptr) const
QgsRectangle _areaOfInterest(const QgsPoint &point, double tolerance)
double sqrDist(double x, double y) const
Returns the squared distance between this point and x,y.
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
void edgePoints(QgsPoint &pt1, QgsPoint &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
const_iterator constEnd() const
const_iterator constBegin() const
QStringList layers() const
Get list of layer IDs for map rendering The layers are stored in the reverse order of how they are re...
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr)
Snap to map according to the current configuration (mode).
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
snap just to current layer (tolerance and type from defaultSettings())
Represents a vector layer which manages a vector based data sets.
void setDefaultSettings(int type, double tolerance, QgsTolerance::UnitType unit)
Configure options used when the mode is snap to current layer or to all layers.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Match nearestVertex(const QgsPoint &point, double tolerance, MatchFilter *filter=nullptr)
Find nearest vertex to the specified point - up to distance specified by tolerance Optional filter ma...
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void setLayers(const QList< LayerConfig > &layers)
Set layers which will be used for snapping.
QString authid() const
Returns the authority identifier for the CRS, which includes both the authority (eg EPSG) and the CRS...
double x() const
Get the x value of the point.
double height() const
Height of the rectangle.
const T value(const Key &key) const
void defaultSettings(int &type, double &tolerance, QgsTolerance::UnitType &unit)
Query options used when the mode is snap to current layer or to all layers.
SnapToMapMode
modes for "snap to background"