From a2f845a41cd4db93a6d4c4ea87c5e6350a49e0fa Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Wed, 2 Feb 2022 13:35:01 -0800 Subject: [PATCH] Handle invalid pads more gracefully Pads generated outside of KiCad may have self-intersecting polygons that simplify to multiple sets. We handle this by adding multiple primitives for such polygons and limiting our fracture calls to only polygons that have holes Fixes https://gitlab.com/kicad/code/kicad/issues/10712 (cherry picked from commit 6d84acfacd3a98b4032e6e707bcca3a0920233c0) --- .../dialog_pad_basicshapes_properties.cpp | 2 -- pcbnew/dialogs/dialog_pad_properties.cpp | 4 +-- pcbnew/pad_custom_shape_functions.cpp | 25 +++++++++++++------ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/pcbnew/dialogs/dialog_pad_basicshapes_properties.cpp b/pcbnew/dialogs/dialog_pad_basicshapes_properties.cpp index 2d5ed22265..f49cd165af 100644 --- a/pcbnew/dialogs/dialog_pad_basicshapes_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_basicshapes_properties.cpp @@ -250,8 +250,6 @@ DIALOG_PAD_PRIMITIVE_POLY_PROPS::DIALOG_PAD_PRIMITIVE_POLY_PROPS( wxWindow* aPar SetupStandardButtons(); - GetSizer()->SetSizeHints( this ); - m_gridCornersList->Connect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( DIALOG_PAD_PRIMITIVE_POLY_PROPS::onCellChanging ), nullptr, this ); diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 0106a58f48..7bd52bf451 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -733,7 +733,7 @@ void DIALOG_PAD_PROPERTIES::displayPrimitivesList() case SHAPE_T::POLY: bs_info[0] = "Polygon"; bs_info[1] = wxString::Format( _( "corners count %d" ), - (int) primitive->GetPolyShape().Outline( 0 ).PointCount() ); + primitive->GetPolyShape().Outline( 0 ).PointCount() ); break; default: @@ -1474,7 +1474,7 @@ void DIALOG_PAD_PROPERTIES::redraw() while( select >= 0 ) { - PCB_SHAPE* dummyShape = (PCB_SHAPE*) m_primitives[select]->Clone(); + PCB_SHAPE* dummyShape = static_cast( m_primitives[select]->Clone() ); dummyShape->SetLayer( SELECTED_ITEMS_LAYER ); dummyShape->Rotate( VECTOR2I( 0, 0), m_dummyPad->GetOrientation() ); dummyShape->Move( m_dummyPad->GetPosition() ); diff --git a/pcbnew/pad_custom_shape_functions.cpp b/pcbnew/pad_custom_shape_functions.cpp index f0d18f242d..edd7a8d838 100644 --- a/pcbnew/pad_custom_shape_functions.cpp +++ b/pcbnew/pad_custom_shape_functions.cpp @@ -42,15 +42,24 @@ void PAD::AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness, bool aF // If aPoly has holes, convert it to a polygon with no holes. SHAPE_POLY_SET poly_no_hole; poly_no_hole.Append( aPoly ); - poly_no_hole.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); - PCB_SHAPE* item = new PCB_SHAPE(); - item->SetShape( SHAPE_T::POLY ); - item->SetFilled( aFilled ); - item->SetPolyShape( poly_no_hole ); - item->SetStroke( STROKE_PARAMS( aThickness, PLOT_DASH_TYPE::SOLID ) ); - item->SetParent( this ); - m_editPrimitives.emplace_back( item ); + if( poly_no_hole.HasHoles() ) + poly_no_hole.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); + + // There should never be multiple shapes, but if there are, we split them into + // primitives so that we can edit them both. + for( int ii = 0; ii < poly_no_hole.OutlineCount(); ++ii ) + { + SHAPE_POLY_SET poly_outline( poly_no_hole.COutline( ii ) ); + PCB_SHAPE* item = new PCB_SHAPE(); + item->SetShape( SHAPE_T::POLY ); + item->SetFilled( aFilled ); + item->SetPolyShape( poly_outline ); + item->SetStroke( STROKE_PARAMS( aThickness, PLOT_DASH_TYPE::SOLID ) ); + item->SetParent( this ); + m_editPrimitives.emplace_back( item ); + } + SetDirty(); }