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 );
113 if ( segments.isEmpty() )
127 endpoints << pl[0] << pl[1];
162 double minSqrDist = 1e20;
163 Q_FOREACH (
const QgsPoint& p, newPoints )
165 double sqrDist = pt.
sqrDist( p.
x(), p.
y() );
166 if ( sqrDist < minSqrDist )
168 minSqrDist = sqrDist;
215 return QgsRectangle( point.
x() - tolerance, point.
y() - tolerance,
216 point.
x() + tolerance, point.
y() + tolerance );
226 if ( !mCurrentLayer || mDefaultType == 0 )
231 int type = mDefaultType;
236 QgsPointLocator* loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
243 if ( mSnapOnIntersection )
245 QgsPointLocator* locEdges = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
255 Q_FOREACH (
const LayerConfig& layerConfig, mLayers )
260 prepareIndex( layers );
264 double maxSnapIntTolerance = 0;
266 Q_FOREACH (
const LayerConfig& layerConfig, mLayers )
269 if (
QgsPointLocator* loc = locatorForLayerUsingStrategy( layerConfig.
layer, pointMap, tolerance ) )
273 if ( mSnapOnIntersection )
275 edges << loc->edgesInRect( pointMap, tolerance );
276 maxSnapIntTolerance = qMax( maxSnapIntTolerance, tolerance );
281 if ( mSnapOnIntersection )
290 int type = mDefaultType;
296 layers << qMakePair( vl, aoi );
297 prepareIndex( layers );
305 if (
QgsPointLocator* loc = locatorForLayerUsingStrategy( vl, pointMap, tolerance ) )
309 if ( mSnapOnIntersection )
310 edges << loc->edgesInRect( pointMap, tolerance );
314 if ( mSnapOnIntersection )
338 if ( !isIndexPrepared( vl, entry.second ) )
339 layersToIndex << entry;
341 if ( !layersToIndex.
isEmpty() )
363 if ( !mHybridMaxAreaPerLayer.
contains( vl->
id() ) )
366 if ( totalFeatureCount < mHybridPerLayerFeatureLimit )
369 mHybridMaxAreaPerLayer[vl->
id()] = -1;
376 double totalArea = layerExtent.
width() * layerExtent.
height();
377 mHybridMaxAreaPerLayer[vl->
id()] = totalArea * mHybridPerLayerFeatureLimit / totalFeatureCount / 4;
381 double indexReasonableArea = mHybridMaxAreaPerLayer[vl->
id()];
382 if ( indexReasonableArea == -1 )
391 double halfSide = sqrt( indexReasonableArea ) / 2;
393 c.
x() + halfSide, c.
y() + halfSide );
397 if ( !loc->
init( mHybridPerLayerFeatureLimit ) )
401 mHybridMaxAreaPerLayer[vl->
id()] /= 4;
420 if ( !mCurrentLayer )
426 QgsPointLocator* loc = locatorForLayerUsingStrategy( mCurrentLayer, pointMap, tolerance );
439 mMapSettings = settings;
441 if ( newDestCRS != oldDestCRS )
447 mCurrentLayer = layer;
452 if ( mSnapToMapMode == mode )
455 mSnapToMapMode = mode;
465 if ( mDefaultType == type && mDefaultTolerance == tolerance && mDefaultUnit == unit )
469 mDefaultTolerance = tolerance;
479 tolerance = mDefaultTolerance;
485 if ( mLayers == layers )
495 if ( mSnapOnIntersection == enabled )
498 mSnapOnIntersection = enabled;
504 QString msg =
"--- SNAPPING UTILS DUMP ---\n";
508 msg +=
"invalid map settings!";
518 msg +=
"no current layer!";
522 layers <<
LayerConfig( mCurrentLayer, QgsPointLocator::Types( mDefaultType ), mDefaultTolerance, mDefaultUnit );
529 layers <<
LayerConfig( vl, QgsPointLocator::Types( mDefaultType ), mDefaultTolerance, mDefaultUnit );
540 "config: %2 tolerance %3 %4\n" )
548 QString extentStr, cachedGeoms, limit(
"no max area" );
551 extentStr =
QString(
" extent %1" ).
arg( r->toString() );
554 extentStr =
"full extent";
555 if ( loc->hasIndex() )
556 cachedGeoms =
QString(
"%1 feats" ).
arg( loc->cachedGeometryCount() );
558 cachedGeoms =
"not initialized";
563 double maxArea = mStrategy ==
IndexHybrid ? mHybridMaxAreaPerLayer[layer.
layer->
id()] : -1;
565 limit =
QString(
"max area %1" ).
arg( maxArea );
568 limit =
"not evaluated";
570 msg +=
QString(
"index : YES | %1 | %2 | %3\n" ).
arg( cachedGeoms, extentStr, limit );
573 msg +=
QString(
"index : ???\n" );
576 msg +=
"index : NO\n";
598 if ( snapType ==
"to segment" )
600 else if ( snapType ==
"to vertex and segment" )
602 else if ( snapType ==
"to vertex" )
612 bool snappingDefinedInProject =
false;
621 if ( layerIdList.
size() != enabledList.
size() ||
622 layerIdList.
size() != toleranceList.
size() ||
623 layerIdList.
size() != toleranceUnitList.
size() ||
624 layerIdList.
size() != snapToList.
size() )
627 if ( !snappingDefinedInProject )
631 if ( snapMode ==
"current_layer" )
633 else if ( snapMode ==
"all_layers" )
646 for ( ; layerIt != layerIdList.
constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt )
649 if ( *enabledIt !=
"enabled" )
667 void QgsSnappingUtils::onLayersWillBeRemoved(
const QStringList& layerIds )
670 Q_FOREACH (
const QString& layerId, layerIds )
672 if ( mHybridMaxAreaPerLayer.
contains( layerId ) )
673 mHybridMaxAreaPerLayer.
remove( layerId );
677 if ( it.key()->id() == layerId )
680 it = mLocators.
erase( it );
690 if ( it.key()->id() == layerId )
693 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.
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
For all layer build index of extent given in map settings.
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *theLayer, QgsRectangle extent) const
transform bounding box from layer's CRS to output CRS
void scale(double scaleFactor, const QgsPoint *c=nullptr)
Scale the rectangle around its center point.
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.
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
QgsRectangle extent() const
Return geographical coordinates of the rectangle that should be rendered.
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)
Snapped to a vertex. Can be a vertex of the geometry or an intersection.
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.
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()
Returns the QgsProject singleton 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)
QString name
Read property of QString layerName.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
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"