Skip to content

Commit

Permalink
Merge pull request #31648 from troopa81/fix_snaptocurrentlayer
Browse files Browse the repository at this point in the history
Parallelize snap caching
  • Loading branch information
Hugo Mercier committed Oct 31, 2019
2 parents 3e5af46 + 340651b commit e86c2af
Show file tree
Hide file tree
Showing 25 changed files with 724 additions and 189 deletions.
66 changes: 52 additions & 14 deletions python/core/auto_generated/qgspointlocator.sip.in
Expand Up @@ -92,12 +92,19 @@ Configure render context - if not ``None``, it will use to index only visible f
typedef QFlags<QgsPointLocator::Type> Types;


bool init( int maxFeaturesToIndex = -1 );
bool init( int maxFeaturesToIndex = -1, bool relaxed = false );
%Docstring
Prepare the index for queries. Does nothing if the index already exists.
If the number of features is greater than the value of maxFeaturesToIndex, creation of index is stopped
to make sure we do not run out of memory. If maxFeaturesToIndex is -1, no limits are used. Returns
``False`` if the creation of index has been prematurely stopped due to the limit of features, otherwise ``True``
to make sure we do not run out of memory. If maxFeaturesToIndex is -1, no limits are used.

This method is either blocking or non blocking according to ``relaxed`` parameter passed
in the constructor. if ``True``, index building will be done in another thread and init() method returns
immediately. initFinished() signal will be emitted once the initialization is over.

Returns false if the creation of index is blocking and has been prematurely stopped due to the limit of features, otherwise true

.. seealso:: :py:class:`QgsPointLocator`
%End

bool hasIndex() const;
Expand Down Expand Up @@ -176,58 +183,64 @@ interpolation of the Z value.
};


Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0 );
Match nearestVertex( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Find nearest vertex to the specified point - up to distance specified by tolerance
Optional filter may discard unwanted matches.
This method is either blocking or non blocking according to ``relaxed`` parameter passed
%End

Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0 );
Match nearestEdge( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Find nearest edge to the specified point - up to distance specified by tolerance
Optional filter may discard unwanted matches.
This method is either blocking or non blocking according to ``relaxed`` parameter passed
%End

Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0 );
Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Find nearest area to the specified point - up to distance specified by tolerance
Optional filter may discard unwanted matches.
This will first perform a pointInPolygon and return first result.
If no match is found and tolerance is not 0, it will return nearestEdge.
This method is either blocking or non blocking according to ``relaxed`` parameter passed

.. versionadded:: 3.0
%End

MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = 0 );
MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Find edges within a specified recangle
Optional filter may discard unwanted matches.
This method is either blocking or non blocking according to ``relaxed`` parameter passed
%End
MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0 );

MatchList edgesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Override of edgesInRect that construct rectangle from a center point and tolerance
This method is either blocking or non blocking according to ``relaxed`` parameter passed
%End

MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = 0 );
MatchList verticesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Find vertices within a specified recangle
This method is either blocking or non blocking according to ``relaxed`` parameter passed
Optional filter may discard unwanted matches.

.. versionadded:: 3.6
%End

MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0 );
MatchList verticesInRect( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Override of verticesInRect that construct rectangle from a center point and tolerance
This method is either blocking or non blocking according to ``relaxed`` parameter passed

.. versionadded:: 3.6
%End


MatchList pointInPolygon( const QgsPointXY &point );
%Docstring
find out if the point is in any polygons
%End

MatchList pointInPolygon( const QgsPointXY &point, bool relaxed = false );

int cachedGeometryCount() const;
%Docstring
Expand All @@ -236,8 +249,33 @@ Returns how many geometries are cached in the index
.. versionadded:: 2.14
%End

bool isIndexing() const;
%Docstring
Returns ``True`` if the point locator is currently indexing the data.
This method is useful if constructor parameter ``relaxed`` is ``True``

.. seealso:: :py:class:`QgsPointLocator`
%End

void waitForIndexingFinished();
%Docstring
If the point locator has been initialized relaxedly and is currently indexing,
this methods waits for the indexing to be finished
%End

signals:

void initFinished( bool ok );
%Docstring
Emitted whenever index has been built and initialization is finished

:param ok: ``False`` if the creation of index has been prematurely stopped due to the limit of
features, otherwise ``True``
%End

protected:
bool rebuildIndex( int maxFeaturesToIndex = -1 );

protected slots:
void destroyIndex();
};
Expand Down
27 changes: 22 additions & 5 deletions python/core/auto_generated/qgssnappingutils.sip.in
Expand Up @@ -38,21 +38,37 @@ which keeps the configuration in sync with map canvas (e.g. current view, active
QgsSnappingUtils( QObject *parent /TransferThis/ = 0, bool enableSnappingForInvisibleFeature = true );
%Docstring
Constructor for QgsSnappingUtils

:param parent: parent object
:param enableSnappingForInvisibleFeature: ``True`` if we want to snap feature even if there are not visible
%End
~QgsSnappingUtils();


QgsPointLocator *locatorForLayer( QgsVectorLayer *vl );
%Docstring
Gets a point locator for the given layer. If such locator does not exist, it will be created

:param vl: the vector layer
%End

QgsPointLocator::Match snapToMap( QPoint point, QgsPointLocator::MatchFilter *filter = 0 );
QgsPointLocator::Match snapToMap( QPoint point, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Snap to map according to the current configuration. Optional filter allows discarding unwanted matches.
Snap to map according to the current configuration.

:param point: point in canvas coordinates
:param filter: allows discarding unwanted matches.
:param relaxed: ``True`` if this method is non blocking and the matching result can be invalid while indexing
%End
QgsPointLocator::Match snapToMap( const QgsPointXY &pointMap, QgsPointLocator::MatchFilter *filter = 0 );

QgsPointLocator::Match snapToMap( const QgsPointXY &pointMap, QgsPointLocator::MatchFilter *filter = 0, bool relaxed = false );
%Docstring
Snap to map according to the current configuration.

:param pointMap: point in map coordinates
:param filter: allows discarding unwanted matches.
:param relaxed: ``True`` if this method is non blocking and the matching result can be invalid while indexing
%End

QgsPointLocator::Match snapToCurrentLayer( QPoint point, QgsPointLocator::Types type, QgsPointLocator::MatchFilter *filter = 0 );
%Docstring
Expand Down Expand Up @@ -172,13 +188,14 @@ Emitted when the snapping settings object changes.
%End

protected:

virtual void prepareIndexStarting( int count );
%Docstring
Called when starting to index - can be overridden and e.g. progress dialog can be provided
Called when starting to index with snapToMap - can be overridden and e.g. progress dialog can be provided
%End
virtual void prepareIndexProgress( int index );
%Docstring
Called when finished indexing a layer. When index == count the indexing is complete
Called when finished indexing a layer with snapToMap. When index == count the indexing is complete
%End

void clearAllLocators();
Expand Down
8 changes: 8 additions & 0 deletions python/gui/auto_generated/qgsmapcanvassnappingutils.sip.in
Expand Up @@ -23,7 +23,15 @@ Snapping utils instance that is connected to a canvas and updates the configurat
#include "qgsmapcanvassnappingutils.h"
%End
public:

QgsMapCanvasSnappingUtils( QgsMapCanvas *canvas, QObject *parent = 0 );
%Docstring
Construct map canvas snapping utils object

:param canvas: map canvas
:param parent: parent object
if ``False`` it will block until indexing is done
%End

protected:
virtual void prepareIndexStarting( int count );
Expand Down
9 changes: 4 additions & 5 deletions src/app/qgsmaptooltrimextendfeature.cpp
Expand Up @@ -86,7 +86,7 @@ void QgsMapToolTrimExtendFeature::canvasMoveEvent( QgsMapMouseEvent *e )
{
case StepLimit:

match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter );
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter, true );
if ( match.isValid() )
{
mIs3DLayer = QgsWkbTypes::hasZ( match.layer()->wkbType() );
Expand Down Expand Up @@ -128,7 +128,7 @@ void QgsMapToolTrimExtendFeature::canvasMoveEvent( QgsMapMouseEvent *e )
}

filter.setLayer( mVlayer );
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter );
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter, true );

if ( match.isValid() )
{
Expand Down Expand Up @@ -234,7 +234,7 @@ void QgsMapToolTrimExtendFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
switch ( mStep )
{
case StepLimit:
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter );
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter, true );
if ( mRubberBandLimit && mRubberBandLimit->isVisible() )
{
if ( getPoints( match, pLimit1, pLimit2 ) )
Expand All @@ -248,7 +248,7 @@ void QgsMapToolTrimExtendFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
if ( mIsModified )
{
filter.setLayer( mVlayer );
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter );
match = mCanvas->snappingUtils()->snapToMap( mMapPoint, &filter, true );

if ( match.layer() )
{
Expand Down Expand Up @@ -308,4 +308,3 @@ void QgsMapToolTrimExtendFeature::deactivate()
mVlayer = nullptr;
mLimitLayer = nullptr;
}

14 changes: 7 additions & 7 deletions src/app/vertextool/qgsvertextool.cpp
Expand Up @@ -760,7 +760,7 @@ QgsPointLocator::Match QgsVertexTool::snapToEditableLayer( QgsMapMouseEvent *e )

snapUtils->setConfig( config );
SelectedMatchFilter filter( tol, mLockedFeature.get() );
m = snapUtils->snapToMap( mapPoint, &filter );
m = snapUtils->snapToMap( mapPoint, &filter, true );

// we give priority to snap matches that are from selected features
if ( filter.hasSelectedMatch() )
Expand All @@ -787,7 +787,7 @@ QgsPointLocator::Match QgsVertexTool::snapToEditableLayer( QgsMapMouseEvent *e )

snapUtils->setConfig( config );
SelectedMatchFilter filter( tol, mLockedFeature.get() );
m = snapUtils->snapToMap( mapPoint, &filter );
m = snapUtils->snapToMap( mapPoint, &filter, true );

// we give priority to snap matches that are from selected features
if ( filter.hasSelectedMatch() )
Expand All @@ -802,7 +802,7 @@ QgsPointLocator::Match QgsVertexTool::snapToEditableLayer( QgsMapMouseEvent *e )
if ( mLastSnap )
{
OneFeatureFilter filterLast( mLastSnap->layer(), mLastSnap->featureId() );
QgsPointLocator::Match lastMatch = snapUtils->snapToMap( mapPoint, &filterLast );
QgsPointLocator::Match lastMatch = snapUtils->snapToMap( mapPoint, &filterLast, true );
// but skip the the previously used feature if it would only snap to segment, while now we have snap to vertex
// so that if there is a point on a line, it gets priority (as is usual with combined vertex+segment snapping)
bool matchHasVertexLastHasEdge = m.hasVertex() && lastMatch.hasEdge();
Expand Down Expand Up @@ -834,7 +834,7 @@ QgsPointLocator::Match QgsVertexTool::snapToPolygonInterior( QgsMapMouseEvent *e
{
if ( currentVlayer->isEditable() && currentVlayer->geometryType() == QgsWkbTypes::PolygonGeometry )
{
QgsPointLocator::MatchList matchList = snapUtils->locatorForLayer( currentVlayer )->pointInPolygon( mapPoint );
QgsPointLocator::MatchList matchList = snapUtils->locatorForLayer( currentVlayer )->pointInPolygon( mapPoint, true );
if ( !matchList.isEmpty() )
{
m = matchList.first();
Expand All @@ -854,7 +854,7 @@ QgsPointLocator::Match QgsVertexTool::snapToPolygonInterior( QgsMapMouseEvent *e

if ( vlayer->isEditable() && vlayer->geometryType() == QgsWkbTypes::PolygonGeometry )
{
QgsPointLocator::MatchList matchList = snapUtils->locatorForLayer( vlayer )->pointInPolygon( mapPoint );
QgsPointLocator::MatchList matchList = snapUtils->locatorForLayer( vlayer )->pointInPolygon( mapPoint, true );
if ( !matchList.isEmpty() )
{
m = matchList.first();
Expand Down Expand Up @@ -886,7 +886,7 @@ QList<QgsPointLocator::Match> QgsVertexTool::findEditableLayerMatches( const Qgs

if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
{
matchList << locator->pointInPolygon( mapPoint );
matchList << locator->pointInPolygon( mapPoint, true );
}

double tolerance = QgsTolerance::vertexSearchRadius( canvas()->mapSettings() );
Expand Down Expand Up @@ -1773,7 +1773,7 @@ QList<QgsPointLocator::Match> QgsVertexTool::layerVerticesSnappedToPoint( QgsVec
{
MatchCollectingFilter myfilter( this );
QgsPointLocator *loc = canvas()->snappingUtils()->locatorForLayer( layer );
loc->nearestVertex( mapPoint, 0, &myfilter );
loc->nearestVertex( mapPoint, 0, &myfilter, true );
return myfilter.matches;
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -317,6 +317,7 @@ SET(QGIS_CORE_SRCS
qgspluginlayerregistry.cpp
qgspointxy.cpp
qgspointlocator.cpp
qgspointlocatorinittask.cpp
qgsproject.cpp
qgsprojectbadlayerhandler.cpp
qgsprojectfiletransform.cpp
Expand Down Expand Up @@ -713,6 +714,7 @@ SET(QGIS_CORE_MOC_HDRS
qgspluginlayer.h
qgspointxy.h
qgspointlocator.h
qgspointlocatorinittask.h
qgsproject.h
qgsprojectviewsettings.h
qgsproxyprogresstask.h
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgscadutils.cpp
Expand Up @@ -41,13 +41,13 @@ QgsCadUtils::AlignMapPointOutput QgsCadUtils::alignMapPoint( const QgsPointXY &o
res.softLockCommonAngle = -1;

// try to snap to anything
QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint );
QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint, nullptr, true );
QgsPointXY point = snapMatch.isValid() ? snapMatch.point() : originalMapPoint;

// try to snap explicitly to a segment - useful for some constraints
QgsPointXY edgePt0, edgePt1;
EdgesOnlyFilter edgesOnlyFilter;
QgsPointLocator::Match edgeMatch = ctx.snappingUtils->snapToMap( originalMapPoint, &edgesOnlyFilter );
QgsPointLocator::Match edgeMatch = ctx.snappingUtils->snapToMap( originalMapPoint, &edgesOnlyFilter, true );
if ( edgeMatch.hasEdge() )
edgeMatch.edgePoints( edgePt0, edgePt1 );

Expand Down

0 comments on commit e86c2af

Please sign in to comment.