Skip to content

Commit

Permalink
snapToCurrentLayer correctly handles Area type
Browse files Browse the repository at this point in the history
  • Loading branch information
3nids committed Feb 19, 2018
1 parent 965a4e8 commit 9e2e99f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
10 changes: 10 additions & 0 deletions python/core/qgspointlocator.sip.in
Expand Up @@ -171,6 +171,16 @@ Optional filter may discard unwanted matches.
%Docstring
Find nearest edge to the specified point - up to distance specified by tolerance
Optional filter may discard unwanted matches.
%End

Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = 0 );
%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.

.. versionadded:: 3.0
%End

MatchList edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter = 0 );
Expand Down
31 changes: 30 additions & 1 deletion src/core/qgspointlocator.cpp
Expand Up @@ -181,7 +181,6 @@ class QgsPointLocator_VisitorNearestEdge : public IVisitor

////////////////////////////////////////////////////////////////////////////


/**
* \ingroup core
* Helper class used when traversing the index with areas - builds a list of matches.
Expand Down Expand Up @@ -883,6 +882,36 @@ QgsPointLocator::Match QgsPointLocator::nearestEdge( const QgsPointXY &point, do
return m;
}

QgsPointLocator::Match QgsPointLocator::nearestArea( const QgsPointXY &point, double tolerance, MatchFilter *filter )
{
if ( !mRTree )
{
init();
if ( !mRTree ) // still invalid?
return Match();
}

MatchList mlist = pointInPolygon( point );
if ( mlist.count() && mlist.at( 0 ).isValid() )
{
return mlist.at( 0 );
}

if ( tolerance == 0 )
{
return Match();
}

// discard point and line layers to keep only polygons
QgsWkbTypes::GeometryType geomType = mLayer->geometryType();
if ( geomType == QgsWkbTypes::PointGeometry || geomType == QgsWkbTypes::LineGeometry )
return Match();

// use edges for adding tolerance
return nearestEdge( point, tolerance, filter );
}


QgsPointLocator::MatchList QgsPointLocator::edgesInRect( const QgsRectangle &rect, QgsPointLocator::MatchFilter *filter )
{
if ( !mRTree )
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgspointlocator.h
Expand Up @@ -228,6 +228,15 @@ class CORE_EXPORT QgsPointLocator : public QObject
*/
Match nearestEdge( 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 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.
* \since QGIS 3.0
*/
Match nearestArea( const QgsPointXY &point, double tolerance, QgsPointLocator::MatchFilter *filter = nullptr );

/**
* Find edges within a specified recangle
* Optional filter may discard unwanted matches.
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgssnappingutils.cpp
Expand Up @@ -185,6 +185,13 @@ static void _updateBestMatch( QgsPointLocator::Match &bestMatch, const QgsPointX
{
_replaceIfBetter( bestMatch, loc->nearestEdge( pointMap, tolerance, filter ), tolerance );
}
if ( bestMatch.type() != QgsPointLocator::Vertex && bestMatch.type() != QgsPointLocator::Edge && ( type & QgsPointLocator::Area ) )
{
// if edges were detected, set tolerance to 0 to only do pointInPolygon (and avoid redo nearestEdge)
if ( type & QgsPointLocator::Edge )
tolerance = 0;
_replaceIfBetter( bestMatch, loc->nearestArea( pointMap, tolerance, filter ), tolerance );
}
}


Expand Down

0 comments on commit 9e2e99f

Please sign in to comment.