Skip to content

Commit

Permalink
[geometry snapper] Fix wrong point-to-segment distance within maths
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Feb 21, 2024
1 parent 086d5cf commit b1d22b9
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 5 deletions.
9 changes: 5 additions & 4 deletions src/analysis/vector/qgsgeometrysnapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<double>::epsilon() );
Expand Down Expand Up @@ -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 )
{
Expand All @@ -264,7 +265,7 @@ QgsSnapIndex::SnapItem *QgsSnapIndex::getSnapItem( const QgsPoint &pos, const do
}
else if ( item->type == SnapSegment && !endPointOnly )
{
if ( !static_cast<SegmentSnapItem *>( item )->withinDistance( pos, tolerance ) )
if ( !static_cast<SegmentSnapItem *>( item )->withinSqrDistance( pos, sqrTolerance ) )
continue;

QgsPoint pProj;
Expand All @@ -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<QgsSnapIndex::SnapItem *>( snapPoint ) : static_cast<QgsSnapIndex::SnapItem *>( snapSegment );
Expand Down
2 changes: 1 addition & 1 deletion src/analysis/vector/qgsgeometrysnapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
4 changes: 4 additions & 0 deletions tests/src/analysis/testqgsgeometrysnapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit b1d22b9

Please sign in to comment.