Browse Source

Polygon operations: fix merging of disjoint shapes

Don't enforce that every merge result has to be
non-disjoint. Sometimes it will merge in the end
when gaps are filled in by other shapes. Even if
not, at the end, just create a new polygon for
each disjoint polygon.
jobs
John Beard 1 year ago
parent
commit
8609632fc4
  1. 2
      pcbnew/tools/edit_tool.cpp
  2. 70
      pcbnew/tools/item_modification_routine.cpp
  3. 16
      pcbnew/tools/item_modification_routine.h

2
pcbnew/tools/edit_tool.cpp

@ -1728,6 +1728,8 @@ int EDIT_TOOL::BooleanPolygons( const TOOL_EVENT& aEvent )
for( PCB_SHAPE* shape : items_to_process )
boolean_routine->ProcessShape( *shape );
boolean_routine->Finalize();
// Select new items
for( BOARD_ITEM* item : items_to_select_on_success )
m_selectionTool->AddItemToSel( item, true );

70
pcbnew/tools/item_modification_routine.cpp

@ -462,21 +462,13 @@ void POLYGON_BOOLEAN_ROUTINE::ProcessShape( PCB_SHAPE& aPcbShape )
return;
}
if( !m_workingPolygon )
if( m_firstPolygon )
{
auto initial = std::make_unique<PCB_SHAPE>( GetBoard(), SHAPE_T::POLY );
initial->SetPolyShape( *poly );
m_width = aPcbShape.GetWidth();
m_layer = aPcbShape.GetLayer();
m_workingPolygons = std::move( *poly );
m_firstPolygon = false;
// Copy properties
initial->SetLayer( aPcbShape.GetLayer() );
initial->SetWidth( aPcbShape.GetWidth() );
// Keep the pointer
m_workingPolygon = initial.get();
// Hand over ownership
GetHandler().AddNewItem( std::move( initial ) );
// And remove the shape
GetHandler().DeleteItem( aPcbShape );
}
else
@ -495,6 +487,35 @@ void POLYGON_BOOLEAN_ROUTINE::ProcessShape( PCB_SHAPE& aPcbShape )
}
void POLYGON_BOOLEAN_ROUTINE::Finalize()
{
if( m_workingPolygons.OutlineCount() == 0 || m_firstPolygon )
{
// Nothing to do (no polygons handled or nothing left?)
return;
}
CHANGE_HANDLER& handler = GetHandler();
// If we have disjoint polygons, we'll fix that now and create
// new PCB_SHAPEs for each outline
for( int i = 0; i < m_workingPolygons.OutlineCount(); ++i )
{
std::unique_ptr<PCB_SHAPE> new_poly_shape =
std::make_unique<PCB_SHAPE>( GetBoard(), SHAPE_T::POLY );
SHAPE_POLY_SET poly_set = m_workingPolygons.Outline( i );
new_poly_shape->SetPolyShape( poly_set );
// Copy properties from the source polygon
new_poly_shape->SetWidth( m_width );
new_poly_shape->SetLayer( m_layer );
handler.AddNewItem( std::move( new_poly_shape ) );
}
}
wxString POLYGON_MERGE_ROUTINE::GetCommitDescription() const
{
return _( "Merge polygons." );
@ -518,17 +539,7 @@ std::optional<wxString> POLYGON_MERGE_ROUTINE::GetStatusMessage() const
bool POLYGON_MERGE_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET& aPolygon )
{
const SHAPE_POLY_SET::POLYGON_MODE poly_mode = SHAPE_POLY_SET::POLYGON_MODE::PM_FAST;
SHAPE_POLY_SET working_copy = GetWorkingPolygon()->GetPolyShape();
working_copy.BooleanAdd( aPolygon, poly_mode );
// Check it's not disjoint - this doesn't work well in the UI
if( working_copy.OutlineCount() != 1 )
{
return false;
}
GetWorkingPolygon()->SetPolyShape( working_copy );
GetWorkingPolygons().BooleanAdd( aPolygon, poly_mode );
return true;
}
@ -557,7 +568,8 @@ bool POLYGON_SUBTRACT_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET& a
{
const SHAPE_POLY_SET::POLYGON_MODE poly_mode = SHAPE_POLY_SET::POLYGON_MODE::PM_FAST;
SHAPE_POLY_SET working_copy = GetWorkingPolygon()->GetPolyShape();
SHAPE_POLY_SET& working_polygons = GetWorkingPolygons();
SHAPE_POLY_SET working_copy = working_copy;
working_copy.BooleanSubtract( aPolygon, poly_mode );
// Subtraction can create holes or delete the polygon
@ -570,10 +582,11 @@ bool POLYGON_SUBTRACT_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET& a
return false;
}
GetWorkingPolygon()->SetPolyShape( working_copy );
working_polygons = std::move( working_copy );
return true;
}
wxString POLYGON_INTERSECT_ROUTINE::GetCommitDescription() const
{
return _( "Intersect polygons." );
@ -598,7 +611,8 @@ bool POLYGON_INTERSECT_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET&
{
const SHAPE_POLY_SET::POLYGON_MODE poly_mode = SHAPE_POLY_SET::POLYGON_MODE::PM_FAST;
SHAPE_POLY_SET working_copy = GetWorkingPolygon()->GetPolyShape();
SHAPE_POLY_SET& working_polygons = GetWorkingPolygons();
SHAPE_POLY_SET working_copy = working_polygons;
working_copy.BooleanIntersection( aPolygon, poly_mode );
// Is there anything left?
@ -609,7 +623,7 @@ bool POLYGON_INTERSECT_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET&
return false;
}
GetWorkingPolygon()->SetPolyShape( working_copy );
working_polygons = std::move( working_copy );
return true;
}

16
pcbnew/tools/item_modification_routine.h

@ -331,19 +331,29 @@ class POLYGON_BOOLEAN_ROUTINE : public ITEM_MODIFICATION_ROUTINE
{
public:
POLYGON_BOOLEAN_ROUTINE( BOARD_ITEM* aBoard, CHANGE_HANDLER& aHandler ) :
ITEM_MODIFICATION_ROUTINE( aBoard, aHandler ), m_workingPolygon( nullptr )
ITEM_MODIFICATION_ROUTINE( aBoard, aHandler )
{
}
void ProcessShape( PCB_SHAPE& aPcbShape );
/**
* Clear up any outstanding work
*/
void Finalize();
protected:
PCB_SHAPE* GetWorkingPolygon() const { return m_workingPolygon; }
SHAPE_POLY_SET& GetWorkingPolygons() { return m_workingPolygons; }
virtual bool ProcessSubsequentPolygon( const SHAPE_POLY_SET& aPolygon ) = 0;
private:
PCB_SHAPE* m_workingPolygon;
/// This can be disjoint, which will be fixed at the end
SHAPE_POLY_SET m_workingPolygons;
bool m_firstPolygon = true;
int m_width;
PCB_LAYER_ID m_layer;
};
class POLYGON_MERGE_ROUTINE : public POLYGON_BOOLEAN_ROUTINE

Loading…
Cancel
Save