Fix a degeneracy bug in arc collisions.

This also fixes a failure to use the correct effective width for
shapes (which might, for instance, inherit their widths from schematic
defaults, netclasses, etc.).

Fixes https://gitlab.com/kicad/code/kicad/issues/11358
This commit is contained in:
Jeff Young 2022-04-08 16:14:42 +01:00
parent 722b2588f4
commit 007906cd16
4 changed files with 24 additions and 21 deletions

View File

@ -1086,16 +1086,16 @@ void EDA_SHAPE::SetPolyPoints( const std::vector<VECTOR2I>& aPoints )
std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes( bool aEdgeOnly ) const std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes( bool aEdgeOnly ) const
{ {
std::vector<SHAPE*> effectiveShapes; std::vector<SHAPE*> effectiveShapes;
int width = GetEffectiveWidth();
switch( m_shape ) switch( m_shape )
{ {
case SHAPE_T::ARC: case SHAPE_T::ARC:
effectiveShapes.emplace_back( new SHAPE_ARC( m_arcCenter, m_start, GetArcAngle(), effectiveShapes.emplace_back( new SHAPE_ARC( m_arcCenter, m_start, GetArcAngle(), width ) );
GetWidth() ) );
break; break;
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
effectiveShapes.emplace_back( new SHAPE_SEGMENT( m_start, m_end, GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( m_start, m_end, width ) );
break; break;
case SHAPE_T::RECT: case SHAPE_T::RECT:
@ -1105,12 +1105,12 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes( bool aEdgeOnly ) const
if( IsFilled() && !aEdgeOnly ) if( IsFilled() && !aEdgeOnly )
effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) ); effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
if( GetWidth() > 0 || !IsFilled() || aEdgeOnly ) if( width > 0 || !IsFilled() || aEdgeOnly )
{ {
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], width ) );
} }
} }
break; break;
@ -1120,21 +1120,21 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes( bool aEdgeOnly ) const
if( IsFilled() && !aEdgeOnly ) if( IsFilled() && !aEdgeOnly )
effectiveShapes.emplace_back( new SHAPE_CIRCLE( getCenter(), GetRadius() ) ); effectiveShapes.emplace_back( new SHAPE_CIRCLE( getCenter(), GetRadius() ) );
if( GetWidth() > 0 || !IsFilled() || aEdgeOnly ) if( width > 0 || !IsFilled() || aEdgeOnly )
effectiveShapes.emplace_back( new SHAPE_ARC( getCenter(), GetEnd(), ANGLE_360 ) ); effectiveShapes.emplace_back( new SHAPE_ARC( getCenter(), GetEnd(), ANGLE_360, width ) );
break; break;
} }
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
{ {
std::vector<VECTOR2I> bezierPoints = buildBezierToSegmentsPointsList( GetWidth() ); std::vector<VECTOR2I> bezierPoints = buildBezierToSegmentsPointsList( width );
VECTOR2I start_pt = bezierPoints[0]; VECTOR2I start_pt = bezierPoints[0];
for( unsigned int jj = 1; jj < bezierPoints.size(); jj++ ) for( unsigned int jj = 1; jj < bezierPoints.size(); jj++ )
{ {
VECTOR2I end_pt = bezierPoints[jj]; VECTOR2I end_pt = bezierPoints[jj];
effectiveShapes.emplace_back( new SHAPE_SEGMENT( start_pt, end_pt, GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( start_pt, end_pt, width ) );
start_pt = end_pt; start_pt = end_pt;
} }
@ -1154,10 +1154,10 @@ std::vector<SHAPE*> EDA_SHAPE::MakeEffectiveShapes( bool aEdgeOnly ) const
if( IsFilled() && !aEdgeOnly ) if( IsFilled() && !aEdgeOnly )
effectiveShapes.emplace_back( new SHAPE_SIMPLE( l ) ); effectiveShapes.emplace_back( new SHAPE_SIMPLE( l ) );
if( GetWidth() > 0 || !IsFilled() || aEdgeOnly ) if( width > 0 || !IsFilled() || aEdgeOnly )
{ {
for( int i = 0; i < l.SegmentCount(); i++ ) for( int i = 0; i < l.SegmentCount(); i++ )
effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ), GetWidth() ) ); effectiveShapes.emplace_back( new SHAPE_SEGMENT( l.Segment( i ), width ) );
} }
} }
break; break;
@ -1194,7 +1194,7 @@ bool EDA_SHAPE::IsPolyShapeValid() const
if( GetPolyShape().OutlineCount() == 0 ) if( GetPolyShape().OutlineCount() == 0 )
return false; return false;
const SHAPE_LINE_CHAIN& outline = ( (SHAPE_POLY_SET&)GetPolyShape() ).Outline( 0 ); const SHAPE_LINE_CHAIN& outline = static_cast<const SHAPE_POLY_SET&>( GetPolyShape() ).Outline( 0 );
return outline.PointCount() > 2; return outline.PointCount() > 2;
} }

View File

@ -58,6 +58,8 @@ public:
int GetPenWidth() const override; int GetPenWidth() const override;
int GetEffectiveWidth() const override { return GetPenWidth(); }
bool HasLineStroke() const override { return true; } bool HasLineStroke() const override { return true; }
STROKE_PARAMS GetStroke() const override { return m_stroke; } STROKE_PARAMS GetStroke() const override { return m_stroke; }
void SetStroke( const STROKE_PARAMS& aStroke ) override; void SetStroke( const STROKE_PARAMS& aStroke ) override;

View File

@ -104,6 +104,7 @@ public:
void SetWidth( int aWidth ) { m_stroke.SetWidth( aWidth ); } void SetWidth( int aWidth ) { m_stroke.SetWidth( aWidth ); }
int GetWidth() const { return m_stroke.GetWidth(); } int GetWidth() const { return m_stroke.GetWidth(); }
virtual int GetEffectiveWidth() const { return GetWidth(); }
void SetShape( SHAPE_T aShape ) { m_shape = aShape; } void SetShape( SHAPE_T aShape ) { m_shape = aShape; }
SHAPE_T GetShape() const { return m_shape; } SHAPE_T GetShape() const { return m_shape; }

View File

@ -369,7 +369,7 @@ bool SHAPE_ARC::IsClockwise() const
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual, bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance, int* aActual,
VECTOR2I* aLocation ) const VECTOR2I* aLocation ) const
{ {
int minDist = aClearance + m_width / 2; int minDist = aClearance + std::max( m_width / 2, 1 );
auto bbox = BBox( minDist ); auto bbox = BBox( minDist );
// Fast check using bounding box: // Fast check using bounding box: