diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp index 663097d91f..2e70e1b661 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp @@ -2630,6 +2630,9 @@ void PCB_IO_KICAD_SEXPR::format( const ZONE* aZone ) const case PLACEMENT_SOURCE_T::GROUP_PLACEMENT: m_out->Print( "(group %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() ); break; + // These are transitory and should not be saved + case PLACEMENT_SOURCE_T::DESIGN_BLOCK: + break; } m_out->Print( ")" ); diff --git a/pcbnew/tools/multichannel_tool.cpp b/pcbnew/tools/multichannel_tool.cpp index 30581e4dd3..3b03b42f9f 100644 --- a/pcbnew/tools/multichannel_tool.cpp +++ b/pcbnew/tools/multichannel_tool.cpp @@ -80,6 +80,21 @@ bool MULTICHANNEL_TOOL::findComponentsInRuleArea( RULE_AREA* aRuleAre if( !aRuleArea || !aRuleArea->m_zone ) return false; + // When we're copying the layout of a design block, we are provided an exact list of items + // rather than querying the board for items that are inside the area. + if( aRuleArea->m_sourceType == PLACEMENT_SOURCE_T::DESIGN_BLOCK ) + { + // Get all board connected items that are from the design bloc + for( EDA_ITEM* item : aRuleArea->m_designBlockItems ) + { + if( item->Type() == PCB_FOOTPRINT_T ) + aComponents.insert( static_cast( item ) ); + } + + return (int) aComponents.size(); + } + + PCBEXPR_COMPILER compiler( new PCBEXPR_UNIT_RESOLVER ); PCBEXPR_UCODE ucode; PCBEXPR_CONTEXT ctx, preflightCtx; @@ -110,6 +125,9 @@ bool MULTICHANNEL_TOOL::findComponentsInRuleArea( RULE_AREA* aRuleAre case PLACEMENT_SOURCE_T::GROUP_PLACEMENT: ruleText = wxT( "A.memberOfGroup('" ) + aRuleArea->m_zone->GetPlacementAreaSource() + wxT( "')" ); break; + case PLACEMENT_SOURCE_T::DESIGN_BLOCK: + // For design blocks, handled above outside the rules system + break; } auto ok = compiler.Compile( ruleText, &ucode, &preflightCtx ); @@ -141,6 +159,27 @@ bool MULTICHANNEL_TOOL::findOtherItemsInRuleArea( RULE_AREA* aRuleArea, std::set if( !aRuleArea || !aRuleArea->m_zone ) return false; + // When we're copying the layout of a design block, we are provided an exact list of items + // rather than querying the board for items that are inside the area. + if( aRuleArea->m_sourceType == PLACEMENT_SOURCE_T::DESIGN_BLOCK ) + { + // Get all board items that aren't footprints or connected items, + // since they'll be handled in the the other findXInRuleArea routines + for( EDA_ITEM* item : aRuleArea->m_designBlockItems ) + { + if( item->Type() == PCB_FOOTPRINT_T ) + continue; + + if( dynamic_cast( item ) ) + continue; + + if( item->IsBOARD_ITEM() ) + aItems.insert( static_cast( item ) ); + } + + return (int) aItems.size(); + } + std::vector result; PCBEXPR_COMPILER compiler( new PCBEXPR_UNIT_RESOLVER ); @@ -660,11 +699,28 @@ int MULTICHANNEL_TOOL::findRoutingInRuleArea( RULE_AREA* aRuleArea, std::set aConnectivity, const SHAPE_POLY_SET& aRAPoly, const REPEAT_LAYOUT_OPTIONS& aOpts ) const { + if( !aRuleArea || !aRuleArea->m_zone ) + return 0; + // The user also will consider tracks and vias that are inside the source area but // not connected to any of the source pads to count as "routing" (e.g. stitching vias) int count = 0; + // When we're copying the layout of a design block, we are provided an exact list of items + // rather than querying the board for items that are inside the area. + if( aRuleArea->m_sourceType == PLACEMENT_SOURCE_T::DESIGN_BLOCK ) + { + // Get all board connected items that are from the design bloc + for( EDA_ITEM* item : aRuleArea->m_designBlockItems ) + { + if( BOARD_CONNECTED_ITEM* bci = dynamic_cast( item ) ) + aOutput.insert( bci ); + } + + return (int) aOutput.size(); + } + PCBEXPR_COMPILER compiler( new PCBEXPR_UNIT_RESOLVER ); PCBEXPR_UCODE ucode; PCBEXPR_CONTEXT ctx, preflightCtx; diff --git a/pcbnew/tools/multichannel_tool.h b/pcbnew/tools/multichannel_tool.h index 03e44a0c20..05eb096b69 100644 --- a/pcbnew/tools/multichannel_tool.h +++ b/pcbnew/tools/multichannel_tool.h @@ -69,6 +69,7 @@ struct RULE_AREA ZONE* m_oldZone = nullptr; ZONE* m_zone = nullptr; std::set m_components; + std::unordered_set m_designBlockItems; bool m_existsAlready = false; bool m_generateEnabled = false; wxString m_sheetPath; diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index a767b28abe..19b29813f7 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -1419,7 +1419,7 @@ int PCB_CONTROL::ApplyDesignBlockLayout( const TOOL_EVENT& aEvent ) // If we succeeded in placing the linked design block, we're ready to apply the multichannel tool if( m_toolMgr->RunSynchronousAction( PCB_ACTIONS::placeLinkedDesignBlock, &tempCommit, &placementPos ) ) { - // Make a lambda for the bounding box of all the components + // Lambda for the bounding box of all the components auto generateBoundingBox = [&]( std::unordered_set aItems ) { std::vector bbCorners; @@ -1440,30 +1440,20 @@ int PCB_CONTROL::ApplyDesignBlockLayout( const TOOL_EVENT& aEvent ) return KIGEOM::RectifyPolygon( hull ); }; - // Build an outline that is the entire board editor since a design block can - // have anything within this space - SHAPE_LINE_CHAIN wholeEditorOutline; - wholeEditorOutline.Append( VECTOR2I( -INT_MAX, -INT_MAX ) ); - wholeEditorOutline.Append( VECTOR2I( INT_MAX, -INT_MAX ) ); - wholeEditorOutline.Append( VECTOR2I( INT_MAX, INT_MAX ) ); - wholeEditorOutline.Append( VECTOR2I( -INT_MAX, INT_MAX ) ); - wholeEditorOutline.SetClosed( true ); - // Build a rule area that contains all the components in the design block, // meaning all items without SKIP_STRUCT set. RULE_AREA dbRA; - dbRA.m_sourceType = PLACEMENT_SOURCE_T::GROUP_PLACEMENT; + dbRA.m_sourceType = PLACEMENT_SOURCE_T::DESIGN_BLOCK; dbRA.m_generateEnabled = true; // Add all components that aren't marked MCT_SKIP_STRUCT to ra.m_components - std::unordered_set allDbItems; brd->Visit( [&]( EDA_ITEM* item, void* data ) { if( !item->HasFlag( MCT_SKIP_STRUCT ) ) { - allDbItems.insert( item ); + dbRA.m_designBlockItems.insert( item ); if( item->Type() == PCB_FOOTPRINT_T ) dbRA.m_components.insert( static_cast( item ) ); @@ -1482,10 +1472,10 @@ int PCB_CONTROL::ApplyDesignBlockLayout( const TOOL_EVENT& aEvent ) dbRA.m_zone->SetDoNotAllowTracks( false ); dbRA.m_zone->SetDoNotAllowPads( false ); dbRA.m_zone->SetDoNotAllowFootprints( false ); - dbRA.m_zone->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::GROUP_PLACEMENT ); + dbRA.m_zone->SetPlacementAreaSourceType( dbRA.m_sourceType ); dbRA.m_zone->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() ); dbRA.m_zone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH ); - dbRA.m_zone->AddPolygon( generateBoundingBox( allDbItems ) ); + dbRA.m_zone->AddPolygon( generateBoundingBox( dbRA.m_designBlockItems ) ); dbRA.m_center = dbRA.m_zone->Outline()->COutline( 0 ).Centre(); tempCommit.Add( dbRA.m_zone ); @@ -1525,7 +1515,7 @@ int PCB_CONTROL::ApplyDesignBlockLayout( const TOOL_EVENT& aEvent ) destRA.m_zone->SetDoNotAllowTracks( false ); destRA.m_zone->SetDoNotAllowPads( false ); destRA.m_zone->SetDoNotAllowFootprints( false ); - destRA.m_zone->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::GROUP_PLACEMENT ); + destRA.m_zone->SetPlacementAreaSourceType( destRA.m_sourceType ); destRA.m_zone->SetPlacementAreaSource( group->GetName() ); destRA.m_zone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH ); destRA.m_zone->AddPolygon( generateBoundingBox( group->GetItems() ) ); diff --git a/pcbnew/zone_settings.h b/pcbnew/zone_settings.h index e1f4dc0dc1..393ada0bec 100644 --- a/pcbnew/zone_settings.h +++ b/pcbnew/zone_settings.h @@ -75,7 +75,8 @@ enum class PLACEMENT_SOURCE_T { SHEETNAME = 0, COMPONENT_CLASS, - GROUP_PLACEMENT + GROUP_PLACEMENT, + DESIGN_BLOCK }; /**