From b1d22b9e0a6e8a2fe6c393817fb1319de44d9a21 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 20 Feb 2024 20:27:45 +0700 Subject: [PATCH] [geometry snapper] Fix wrong point-to-segment distance within maths --- src/analysis/vector/qgsgeometrysnapper.cpp | 9 +++++---- src/analysis/vector/qgsgeometrysnapper.h | 2 +- tests/src/analysis/testqgsgeometrysnapper.cpp | 4 ++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/analysis/vector/qgsgeometrysnapper.cpp b/src/analysis/vector/qgsgeometrysnapper.cpp index daea5921819f..82bfa8817e8c 100644 --- a/src/analysis/vector/qgsgeometrysnapper.cpp +++ b/src/analysis/vector/qgsgeometrysnapper.cpp @@ -99,7 +99,7 @@ bool QgsSnapIndex::SegmentSnapItem::getProjection( const QgsPoint &p, QgsPoint & return true; } -bool QgsSnapIndex::SegmentSnapItem::withinDistance( const QgsPoint &p, const double tolerance ) +bool QgsSnapIndex::SegmentSnapItem::withinSqrDistance( const QgsPoint &p, const double tolerance ) { double minDistX, minDistY; const double distance = QgsGeometryUtilsBase::sqrDistToLine( p.x(), p.y(), idxFrom->point().x(), idxFrom->point().y(), idxTo->point().x(), idxTo->point().y(), minDistX, minDistY, 4 * std::numeric_limits::epsilon() ); @@ -250,6 +250,7 @@ QgsSnapIndex::SnapItem *QgsSnapIndex::getSnapItem( const QgsPoint &pos, const do QgsSnapIndex::SegmentSnapItem *snapSegment = nullptr; QgsSnapIndex::PointSnapItem *snapPoint = nullptr; + const double sqrTolerance = tolerance * tolerance; const auto constItems = items; for ( QgsSnapIndex::SnapItem *item : constItems ) { @@ -264,7 +265,7 @@ QgsSnapIndex::SnapItem *QgsSnapIndex::getSnapItem( const QgsPoint &pos, const do } else if ( item->type == SnapSegment && !endPointOnly ) { - if ( !static_cast( item )->withinDistance( pos, tolerance ) ) + if ( !static_cast( item )->withinSqrDistance( pos, sqrTolerance ) ) continue; QgsPoint pProj; @@ -279,8 +280,8 @@ QgsSnapIndex::SnapItem *QgsSnapIndex::getSnapItem( const QgsPoint &pos, const do } } } - snapPoint = minDistPoint < tolerance * tolerance ? snapPoint : nullptr; - snapSegment = minDistSegment < tolerance * tolerance ? snapSegment : nullptr; + snapPoint = minDistPoint < sqrTolerance ? snapPoint : nullptr; + snapSegment = minDistSegment < sqrTolerance ? snapSegment : nullptr; if ( pSnapPoint ) *pSnapPoint = snapPoint; if ( pSnapSegment ) *pSnapSegment = snapSegment; return minDistPoint < minDistSegment ? static_cast( snapPoint ) : static_cast( snapSegment ); diff --git a/src/analysis/vector/qgsgeometrysnapper.h b/src/analysis/vector/qgsgeometrysnapper.h index 0972d693a266..5f689f6b3bc3 100644 --- a/src/analysis/vector/qgsgeometrysnapper.h +++ b/src/analysis/vector/qgsgeometrysnapper.h @@ -209,7 +209,7 @@ class QgsSnapIndex QgsPoint getSnapPoint( const QgsPoint &p ) const override; bool getIntersection( const QgsPoint &p1, const QgsPoint &p2, QgsPoint &inter ) const; bool getProjection( const QgsPoint &p, QgsPoint &pProj ) const; - bool withinDistance( const QgsPoint &p, const double distance ); + bool withinSqrDistance( const QgsPoint &p, const double distance ); const CoordIdx *idxFrom = nullptr; const CoordIdx *idxTo = nullptr; }; diff --git a/tests/src/analysis/testqgsgeometrysnapper.cpp b/tests/src/analysis/testqgsgeometrysnapper.cpp index ba0e19bd4972..8c788283eed2 100644 --- a/tests/src/analysis/testqgsgeometrysnapper.cpp +++ b/tests/src/analysis/testqgsgeometrysnapper.cpp @@ -378,6 +378,10 @@ void TestQgsGeometrySnapper::snapPointToLine() pointGeom = QgsGeometry::fromWkt( QStringLiteral( "Point(0.5 0.5)" ) ); result = snapper.snapGeometry( pointGeom, 1 ); QCOMPARE( result.asWkt(), QStringLiteral( "Point (0 0)" ) ); + + pointGeom = QgsGeometry::fromWkt( QStringLiteral( "Point(3 3)" ) ); + result = snapper.snapGeometry( pointGeom, 4 ); + QCOMPARE( result.asWkt(), QStringLiteral( "Point (3 0)" ) ); } void TestQgsGeometrySnapper::snapPointToLinePreferNearest()