Fix SHAPE_LINE_CHAIN::NearestPoint when aAllowInternalShapePoints=false

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8770
This commit is contained in:
Roberto Fernandez Bautista 2021-08-08 20:56:46 +01:00
parent cc99323c86
commit ae87dc686a
2 changed files with 60 additions and 16 deletions

View File

@ -1557,30 +1557,43 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP,
{
int d = CSegment( i ).Distance( aP );
bool isInternalShapePoint = false;
// An internal shape point here is everything after the start of an arc and before the
// second-to-last vertex of the arc, because we are looking at segments here!
if( i > 0 && i < SegmentCount() - 1 && m_shapes[i] != SHAPES_ARE_PT
&& ( ( m_shapes[i - 1] != SHAPES_ARE_PT && m_shapes[i - 1] == m_shapes[i] )
&& ( m_shapes[i + 2] != SHAPES_ARE_PT && m_shapes[i + 2] == m_shapes[i] ) ) )
{
isInternalShapePoint = true;
}
if( ( d < min_d ) && ( aAllowInternalShapePoints || !isInternalShapePoint ) )
if( d < min_d )
{
min_d = d;
nearest = i;
}
}
// Is this the start or end of an arc? If so, return it directly
if( !aAllowInternalShapePoints && ( IsArcStart( nearest ) || IsArcEnd( nearest ) ) )
if( !aAllowInternalShapePoints )
{
//Snap to arc end points if the closest found segment is part of an arc segment
if( nearest > 0 && nearest < PointCount() && IsArcSegment( nearest ) )
{
VECTOR2I ptToSegStart = CSegment( nearest ).A - aP;
VECTOR2I ptToSegEnd = CSegment( nearest ).B - aP;
if( ptToSegStart.EuclideanNorm() > ptToSegEnd.EuclideanNorm() )
nearest++;
// Is this the start or end of an arc? If so, return it directly
if( IsArcStart( nearest ) || IsArcEnd( nearest ) )
{
//@todo should we calculate the nearest point to the "true" arc?
return m_points[nearest];
}
else
{
const SHAPE_ARC& nearestArc = Arc( ArcIndex( nearest ) );
VECTOR2I ptToArcStart = nearestArc.GetP0() - aP;
VECTOR2I ptToArcEnd = nearestArc.GetP1() - aP;
if( ptToArcStart.EuclideanNorm() > ptToArcEnd.EuclideanNorm() )
return nearestArc.GetP1();
else
return nearestArc.GetP0();
}
}
}
return CSegment( nearest ).NearestPoint( aP );
}

View File

@ -260,4 +260,35 @@ BOOST_AUTO_TEST_CASE( Slice )
}
// Test SHAPE_LINE_CHAIN::NearestPoint( VECTOR2I )
BOOST_AUTO_TEST_CASE( NearestPointPt )
{
SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), 180.0 );
// Start a chain with 2 points (seg1)
SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
// Add first arc
chain.Append( arc );
BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
// Add two points (seg2)
chain.Append( seg2.A );
chain.Append( seg2.B );
BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
VECTOR2I ptOnArcCloseToStart( 297553, 31697 ); //should be index 3 in chain
VECTOR2I ptOnArcCloseToEnd( 139709, 82983 ); //should be index 6 in chain
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, true ), ptOnArcCloseToStart );
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, false ), arc.GetP0() );
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, true ), ptOnArcCloseToEnd );
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, false ), arc.GetP1() );
}
BOOST_AUTO_TEST_SUITE_END()