7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-11 10:00:13 +00:00

Fix error in PointInside

If we are checking a point that is inline with multiple segments, we
were counting both the entry and exit as crossings, leading to points
inside a polygon being registered as outside.  Changing the conditional
to only catch one crossing as required.

Adds a QA check to ensure that this remains fixed

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18377
This commit is contained in:
Seth Hillbrand 2024-11-07 09:01:32 -08:00
parent 99d5e66370
commit 7916b1ddb8
2 changed files with 41 additions and 12 deletions
libs/kimath/src/geometry
qa/tests/libs/kimath/geometry

View File

@ -1943,8 +1943,6 @@ bool SHAPE_LINE_CHAIN_BASE::PointInside( const VECTOR2I& aPt, int aAccuracy,
if( !IsClosed() || GetPointCount() < 3 )
return false;
bool inside = false;
/*
* To check for interior points, we draw a line in the positive x direction from
* the point. If it intersects an even number of segments, the point is outside the
@ -1956,21 +1954,22 @@ bool SHAPE_LINE_CHAIN_BASE::PointInside( const VECTOR2I& aPt, int aAccuracy,
* Note: we open-code CPoint() here so that we don't end up calculating the size of the
* vector number-of-points times. This has a non-trivial impact on zone fill times.
*/
int pointCount = GetPointCount();
int pointCount = GetPointCount();
bool inside = false;
for( int i = 0; i < pointCount; )
{
const auto p1 = GetPoint( i++ );
const auto p2 = GetPoint( i == pointCount ? 0 : i );
const auto diff = p2 - p1;
const VECTOR2I p1 = GetPoint( i++ );
const VECTOR2I p2 = GetPoint( i == pointCount ? 0 : i );
const VECTOR2I diff = p2 - p1;
if( diff.y != 0 )
{
const int d = rescale( diff.x, ( aPt.y - p1.y ), diff.y );
if( diff.y == 0 )
continue;
if( ( ( p1.y > aPt.y ) != ( p2.y > aPt.y ) ) && ( aPt.x - p1.x < d ) )
inside = !inside;
}
const int d = rescale( diff.x, ( aPt.y - p1.y ), diff.y );
if( ( ( p1.y >= aPt.y ) != ( p2.y >= aPt.y ) ) && ( aPt.x - p1.x < d ) )
inside = !inside;
}
// If accuracy is <= 1 (nm) then we skip the accuracy test for performance. Otherwise

View File

@ -367,6 +367,36 @@ BOOST_AUTO_TEST_CASE( ToggleClosed )
}
BOOST_AUTO_TEST_CASE( PointInPolygon )
{
SHAPE_LINE_CHAIN outline1( { { 1316455, 913576 }, { 1316455, 901129 }, { 1321102, 901129 },
{ 1322152, 901191 }, { 1323055, 901365 }, { 1323830, 901639 },
{ 1324543, 902036 }, { 1325121, 902521 }, { 1325581, 903100 },
{ 1325914, 903759 }, { 1326120, 904516 }, { 1326193, 905390 },
{ 1326121, 906253 }, { 1325915, 907005 }, { 1325581, 907667 },
{ 1325121, 908248 }, { 1324543, 908735 }, { 1323830, 909132 },
{ 1323055, 909406 }, { 1322153, 909579 }, { 1321102, 909641 },
{ 1317174, 909641 }, { 1317757, 909027 }, { 1317757, 913576 } } );
SHAPE_LINE_CHAIN outline2( { { 1297076, 916244 }, { 1284629, 916244 }, { 1284629, 911597 },
{ 1284691, 910547 }, { 1284865, 909644 }, { 1285139, 908869 },
{ 1285536, 908156 }, { 1286021, 907578 }, { 1286600, 907118 },
{ 1287259, 906785 }, { 1288016, 906579 }, { 1288890, 906506 },
{ 1289753, 906578 }, { 1290505, 906784 }, { 1291167, 907118 },
{ 1291748, 907578 }, { 1292235, 908156 }, { 1292632, 908869 },
{ 1292906, 909644 }, { 1293079, 910546 }, { 1293141, 911597 },
{ 1293141, 915525 }, { 1292527, 914942 }, { 1297076, 914942 } } );
// Test a point inside the polygon
VECTOR2I point1( 1317757, 909133 );
VECTOR2I point2( 1292633, 914942 );
outline1.SetClosed( true );
outline2.SetClosed( true );
BOOST_CHECK( outline1.PointInside( point1, 0, false ) );
BOOST_CHECK( outline2.PointInside( point2, 0, false ) );
}
// Test that duplicate point gets removed when we call simplify
BOOST_AUTO_TEST_CASE( SimplifyDuplicatePoint )
{