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 );
666 for ( LocatorsMap::iterator it = mLocators.
begin(); it != mLocators.
end(); )
668 if ( it.key()->id() == layerId )
671 it = mLocators.
erase( it );
679 for ( LocatorsMap::iterator it = mTemporaryLocators.
begin(); it != mTemporaryLocators.
end(); )
681 if ( it.key()->id() == layerId )
684 it = mTemporaryLocators.
erase( it );
The class defines interface for querying point location:
A rectangle specified with double values.
void setSnapOnIntersections(bool enabled)
Set whether to consider intersections of nearby segments for snapping.
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. ...
QString name() const
Get the display name of the layer.
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())
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
UnitType
Type of unit of tolerance value from settings.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *theLayer, QgsRectangle extent) const
transform bounding box from layer's CRS to output CRS
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
A geometry is the spatial representation of a feature.
const QgsMapToPixel & mapToPixel() const
Interface that allows rejection of some matches in intersection queries (e.g.
double sqrDist(double x, double y) const
Returns the squared distance between this point and x,y.
double x() const
Get the x value of the point.
void readConfigFromProject()
Read snapping configuration from the project.
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
The QgsMapSettings class contains configuration for rendering of the map.
QList< LayerConfig > layers() const
Query layers used for snapping.
const QgsRectangle * extent() const
Get extent of the area point locator covers - if null then it caches the whole layer.
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=nullptr) const
For all layers build index of full extent. Uses more memory, but queries are faster.
int count(const T &value) const
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)
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
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...
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
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)
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
QGis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
void setExtent(const QgsRectangle *extent)
Configure extent - if not null, it will index only that area.
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.
double distance() const
for vertex / edge match units depending on what class returns it (geom.cache: layer units...
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.
double tolerance
The range around snapping targets in which snapping should occur.
For all layers only create temporary indexes of small extent. Low memory usage, slower queries...
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
bool contains(const T &value) const
static QgsPointLocator::Match _findClosestSegmentIntersection(const QgsPoint &pt, const QgsPointLocator::MatchList &segments)
QgsPoint toMapCoordinates(int x, int y) const
static double vertexSearchRadius(const QgsMapSettings &mapSettings)
Static function to get vertex tolerance value.
double readDoubleEntry(const QString &scope, const QString &key, double 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...
long pendingFeatureCount() const
Returns feature count including changes which have not yet been committed Alias for featureCount()...
virtual void prepareIndexStarting(int count)
Called when starting to index - can be overridden and e.g. progress dialog can be provided...
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
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()
access to canonical QgsProject instance
Class for storing a coordinate reference system (CRS)
QString authid() const
Returns the authority identifier for the CRS, which includes both the authority (eg EPSG) and the CRS...
void edgePoints(QgsPoint &pt1, QgsPoint &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
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 y() const
Get the y value of the point.
QStringList layers() const
Get list of layer IDs for map rendering The layers are stored in the reverse order of how they are re...
QgsRectangle _areaOfInterest(const QgsPoint &point, double tolerance)
static QgsGeometry * unaryUnion(const QList< QgsGeometry * > &geometryList)
Compute the unary union on a list of geometries.
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
const_iterator constEnd() const
const_iterator constBegin() const
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr)
Snap to map according to the current configuration (mode).
bool hasIndex() const
Indicate whether the data have been already indexed.
double width() const
Width of the rectangle.
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...
void setLayers(const QList< LayerConfig > &layers)
Set layers which will be used for snapping.
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"