Browse Source

Correctly handle zone net updates in multichannel tool

Also fixes some item duplication issues

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19410
pcb_db
JamesJCode 12 months ago
parent
commit
a45b601e11
  1. 145
      pcbnew/tools/multichannel_tool.cpp
  2. 2
      pcbnew/tools/multichannel_tool.h

145
pcbnew/tools/multichannel_tool.cpp

@ -749,49 +749,112 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( TMATCH::COMPONENT_MATCHES& aMatche
if( aOpts.m_copyOtherItems )
{
std::set<BOARD_ITEM*> sourceItems;
std::set<BOARD_ITEM*> targetItems;
findOtherItemsInRuleArea( aRefArea->m_area, sourceItems );
findOtherItemsInRuleArea( aTargetArea->m_area, targetItems );
for( BOARD_ITEM* item : sourceItems )
for( BOARD_ITEM* item : targetItems )
{
if( !aRefArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
if( item->Type() == PCB_TEXT_T && item->GetParent()
&& item->GetParent()->Type() == PCB_FOOTPRINT_T )
continue;
if( !aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
if( item->IsLocked() && !aOpts.m_includeLockedItems )
continue;
// Groups that are fully-contained within the area are added themselves; copy their
// items as part of DeepClone rather than explicitly
if( item->GetParentGroup() && sourceItems.contains( item->GetParentGroup() ) )
// item already removed
if( aCommit->GetStatus( item ) != 0 )
continue;
BOARD_ITEM* copied;
if( item->Type() == PCB_GROUP_T )
if( item->Type() != PCB_ZONE_T )
{
copied = static_cast<PCB_GROUP*>( item )->DeepClone();
if( aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
{
aAffectedItems.insert( item );
aCommit->Remove( item );
}
}
else
{
copied = static_cast<BOARD_ITEM*>( item->Clone() );
ZONE* zone = static_cast<ZONE*>( item );
// Check all zone layers are included in the rule area
bool layerMismatch = false;
LSET zoneLayers = zone->GetLayerSet();
for( const PCB_LAYER_ID& layer : zoneLayers )
{
if( !aTargetArea->m_area->GetLayerSet().Contains( layer ) )
layerMismatch = true;
}
if( !layerMismatch )
{
aAffectedItems.insert( zone );
aCommit->Remove( zone );
}
}
}
copied->ClearFlags();
copied->SetParentGroup( nullptr );
copied->Move( disp );
aGroupableItems.insert( copied );
aCommit->Add( copied );
for( BOARD_ITEM* item : sourceItems )
{
if( item->Type() == PCB_TEXT_T && item->GetParent()
&& item->GetParent()->Type() == PCB_FOOTPRINT_T )
continue;
getView()->Query( copied->GetBoundingBox(),
[&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
BOARD_ITEM* copied = nullptr;
if( item->Type() != PCB_ZONE_T )
{
if( !aRefArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
continue;
if( !aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
continue;
if( item->Type() == PCB_GROUP_T )
{
copied = static_cast<PCB_GROUP*>( item )->DeepClone();
}
else
{
BOARD_ITEM* existingItem = static_cast<BOARD_ITEM*>( viewItem );
copied = static_cast<BOARD_ITEM*>( item->Clone() );
}
}
else
{
ZONE* zone = static_cast<ZONE*>( item );
if( existingItem && existingItem->Similarity( *copied ) == 1.0 )
aCommit->Remove( existingItem );
// Check all zone layers are included in the rule area
bool layerMismatch = false;
LSET zoneLayers = zone->GetLayerSet();
return true;
} );
for( const PCB_LAYER_ID& layer : zoneLayers )
{
if( !aRefArea->m_area->GetLayerSet().Contains( layer )
|| !aTargetArea->m_area->GetLayerSet().Contains( layer ) )
{
layerMismatch = true;
}
}
if( layerMismatch )
continue;
ZONE* targetZone = static_cast<ZONE*>( item->Clone() );
fixupZoneNets( zone, targetZone, aMatches );
copied = targetZone;
}
if( copied )
{
copied->ClearFlags();
copied->SetParentGroup( nullptr );
copied->Move( disp );
aGroupableItems.insert( copied );
aCommit->Add( copied );
}
}
}
@ -852,6 +915,42 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( TMATCH::COMPONENT_MATCHES& aMatche
}
/**
* @brief Attempts to modify the assigned net of a copied zone
*
*/
void MULTICHANNEL_TOOL::fixupZoneNets( ZONE* aRefZone, ZONE* aTargetZone,
TMATCH::COMPONENT_MATCHES& aComponentMatches )
{
auto connectivity = board()->GetConnectivity();
const std::vector<BOARD_CONNECTED_ITEM*> refZoneConnectedPads =
connectivity->GetNetItems( aRefZone->GetNetCode(), { PCB_PAD_T } );
for( const BOARD_CONNECTED_ITEM* refConItem : refZoneConnectedPads )
{
if( refConItem->Type() != PCB_PAD_T )
continue;
const PAD* refPad = static_cast<const PAD*>( refConItem );
FOOTPRINT* sourceFootprint = refPad->GetParentFootprint();
if( aComponentMatches.contains( sourceFootprint ) )
{
const FOOTPRINT* targetFootprint = aComponentMatches[sourceFootprint];
std::vector<const PAD*> targetFpPads = targetFootprint->GetPads( refPad->GetNumber() );
if( !targetFpPads.empty() )
{
int targetNetCode = targetFpPads[0]->GetNet()->GetNetCode();
aTargetZone->SetNetCode( targetNetCode );
break;
}
}
}
}
bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_AREA* aTargetArea,
RULE_AREA_COMPAT_DATA& aMatches )
{

2
pcbnew/tools/multichannel_tool.h

@ -143,6 +143,8 @@ private:
std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
const SHAPE_POLY_SET& aRAPoly, RULE_AREA* aRA, FOOTPRINT* aFp,
const REPEAT_LAYOUT_OPTIONS& aOpts ) const;
void fixupZoneNets( ZONE* aRefZone, ZONE* aTargetZone,
TMATCH::COMPONENT_MATCHES& aComponentMatches );
bool pruneExistingGroups( COMMIT& aCommit, const std::unordered_set<BOARD_ITEM*>& aItemsToCheck );

Loading…
Cancel
Save