From b6d03209b97c9379693456d85d424db72103fdfa Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Thu, 11 Aug 2016 17:23:01 +0200 Subject: [PATCH] Fix closest segment for points (#3383) * Make closestSegment() behave as expected by QgsGeometry::closestSegmentWithContext This fixes a bug that QgsPointLocator::nearestEdge() would return valid match even for point layers. * Shortcut if using QgsPointLocator with a wrong layer type --- python/core/geometry/qgsabstractgeometry.sip | 2 +- src/core/geometry/qgsabstractgeometry.h | 2 +- src/core/geometry/qgspointv2.cpp | 7 ++++--- src/core/qgspointlocator.cpp | 12 ++++++++++++ tests/src/core/testqgsgeometry.cpp | 13 +++++++++---- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/python/core/geometry/qgsabstractgeometry.sip b/python/core/geometry/qgsabstractgeometry.sip index 11dc2c55ee8..1ec9995b471 100644 --- a/python/core/geometry/qgsabstractgeometry.sip +++ b/python/core/geometry/qgsabstractgeometry.sip @@ -261,7 +261,7 @@ class QgsAbstractGeometry * @param leftOf returns whether the point lies on the left side of the nearest segment (true if point is to left of segment, * false if point is to right of segment) * @param epsilon epsilon for segment snapping - * @returns squared distance to closest segment + * @returns squared distance to closest segment or negative value on error */ virtual double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const = 0; diff --git a/src/core/geometry/qgsabstractgeometry.h b/src/core/geometry/qgsabstractgeometry.h index 6ad9da4e9f6..b3910daf53b 100644 --- a/src/core/geometry/qgsabstractgeometry.h +++ b/src/core/geometry/qgsabstractgeometry.h @@ -246,7 +246,7 @@ class CORE_EXPORT QgsAbstractGeometry * @param leftOf returns whether the point lies on the left side of the nearest segment (true if point is to left of segment, * false if point is to right of segment) * @param epsilon epsilon for segment snapping - * @returns squared distance to closest segment + * @returns squared distance to closest segment or negative value on error */ virtual double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const = 0; diff --git a/src/core/geometry/qgspointv2.cpp b/src/core/geometry/qgspointv2.cpp index 03c901fb4c0..d4789d49c7d 100644 --- a/src/core/geometry/qgspointv2.cpp +++ b/src/core/geometry/qgspointv2.cpp @@ -311,11 +311,12 @@ bool QgsPointV2::moveVertex( QgsVertexId position, const QgsPointV2& newPos ) double QgsPointV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const { + Q_UNUSED( pt ); + Q_UNUSED( segmentPt ); + Q_UNUSED( vertexAfter ); Q_UNUSED( leftOf ); Q_UNUSED( epsilon ); - segmentPt = *this; - vertexAfter = QgsVertexId( 0, 0, 0 ); - return QgsGeometryUtils::sqrDistance2D( *this, pt ); + return -1; // no segments - return error } bool QgsPointV2::nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const diff --git a/src/core/qgspointlocator.cpp b/src/core/qgspointlocator.cpp index 49e545ae717..7461ce257f6 100644 --- a/src/core/qgspointlocator.cpp +++ b/src/core/qgspointlocator.cpp @@ -861,6 +861,10 @@ QgsPointLocator::Match QgsPointLocator::nearestEdge( const QgsPoint& point, doub return Match(); } + QgsWkbTypes::GeometryType geomType = mLayer->geometryType(); + if ( geomType == QgsWkbTypes::PointGeometry ) + return Match(); + Match m; QgsPointLocator_VisitorNearestEdge visitor( this, m, point, filter ); QgsRectangle rect( point.x() - tolerance, point.y() - tolerance, point.x() + tolerance, point.y() + tolerance ); @@ -879,6 +883,10 @@ QgsPointLocator::MatchList QgsPointLocator::edgesInRect( const QgsRectangle& rec return MatchList(); } + QgsWkbTypes::GeometryType geomType = mLayer->geometryType(); + if ( geomType == QgsWkbTypes::PointGeometry ) + return MatchList(); + MatchList lst; QgsPointLocator_VisitorEdgesInRect visitor( this, lst, rect, filter ); mRTree->intersectsWithQuery( rect2region( rect ), visitor ); @@ -902,6 +910,10 @@ QgsPointLocator::MatchList QgsPointLocator::pointInPolygon( const QgsPoint& poin return MatchList(); } + QgsWkbTypes::GeometryType geomType = mLayer->geometryType(); + if ( geomType == QgsWkbTypes::PointGeometry || geomType == QgsWkbTypes::LineGeometry ) + return MatchList(); + MatchList lst; QgsPointLocator_VisitorArea visitor( this, point, lst ); mRTree->intersectsWithQuery( point2point( point ), visitor ); diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index cb77195d752..fbabe9ec845 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -684,12 +684,11 @@ void TestQgsGeometry::point() p20.deleteVertex( QgsVertexId( 0, 0, 0 ) ); QCOMPARE( p20, QgsPointV2( 2.0, 3.0 ) ); - //closestSegment + // closestSegment QgsPointV2 closest; QgsVertexId after; - QCOMPARE( p20.closestSegment( QgsPointV2( 4.0, 6.0 ), closest, after, 0, 0 ), 13.0 ); - QCOMPARE( closest, p20 ); - QCOMPARE( after, QgsVertexId( 0, 0, 0 ) ); + // return error - points have no segments + QVERIFY( p20.closestSegment( QgsPointV2( 4.0, 6.0 ), closest, after, 0, 0 ) < 0 ); //nextVertex QgsPointV2 p21( 3.0, 4.0 ); @@ -3023,6 +3022,12 @@ void TestQgsGeometry::multiPoint() boundaryMP.addGeometry( new QgsPointV2( 0, 0 ) ); boundaryMP.addGeometry( new QgsPointV2( 1, 1 ) ); QVERIFY( !boundaryMP.boundary() ); + + // closestSegment + QgsPointV2 closest; + QgsVertexId after; + // return error - points have no segments + QVERIFY( boundaryMP.closestSegment( QgsPointV2( 0.5, 0.5 ), closest, after, 0, 0 ) < 0 ); } void TestQgsGeometry::multiLineString()