mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
design blocks / multichannel: basics of placing DB layout
This commit is contained in:
parent
986c1a597a
commit
97af2af779
@ -66,7 +66,7 @@
|
||||
#define SHOW_ELEC_TYPE (1UL << 25) ///< Show pin electrical type
|
||||
#define BRIGHTENED (1UL << 26) ///< item is drawn with a bright contour
|
||||
|
||||
// 27 is unused
|
||||
#define MCT_SKIP_STRUCT (1 << 27) ///< flag used by the multichannel tool to mark items that should be skipped
|
||||
|
||||
#define UR_TRANSIENT (1UL << 28) ///< indicates the item is owned by the undo/redo stack
|
||||
|
||||
|
@ -526,6 +526,44 @@ int MULTICHANNEL_TOOL::CheckRACompatibility( ZONE *aRefZone )
|
||||
}
|
||||
|
||||
|
||||
int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, RULE_AREA& aRefArea, RULE_AREA& aTargetArea )
|
||||
{
|
||||
RULE_AREA_COMPAT_DATA compat;
|
||||
|
||||
if( !resolveConnectionTopology( &aRefArea, &aTargetArea, compat ) )
|
||||
{
|
||||
if( Pgm().IsGUI() )
|
||||
{
|
||||
auto errMsg = wxString::Format( _( "Rule Area topologies do not match: %s" ), compat.m_errorMsg );
|
||||
frame()->ShowInfoBarError( errMsg, true );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
BOARD_COMMIT commit( GetManager(), true );
|
||||
|
||||
if( !copyRuleAreaContents( compat.m_matchingComponents, &commit, &aRefArea, &aTargetArea, m_areas.m_options,
|
||||
compat.m_affectedItems, compat.m_groupableItems ) )
|
||||
{
|
||||
auto errMsg = wxString::Format( _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
|
||||
m_areas.m_refRA->m_area->GetZoneName(), aTargetArea.m_area->GetZoneName() );
|
||||
|
||||
commit.Revert();
|
||||
|
||||
if( Pgm().IsGUI() )
|
||||
{
|
||||
frame()->ShowInfoBarError( errMsg, true );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
commit.Push( _( "Repeat layout" ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
|
||||
{
|
||||
int totalCopied = 0;
|
||||
|
@ -101,6 +101,7 @@ public:
|
||||
RULE_AREAS_DATA* GetData() { return &m_areas; }
|
||||
int AutogenerateRuleAreas( const TOOL_EVENT& aEvent );
|
||||
int RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone );
|
||||
int RepeatLayout( const TOOL_EVENT& aEvent, RULE_AREA& aRefArea, RULE_AREA& aTargetArea );
|
||||
void QuerySheetsAndComponentClasses();
|
||||
void FindExistingRuleAreas();
|
||||
int CheckRACompatibility( ZONE *aRefZone );
|
||||
|
@ -463,6 +463,14 @@ TOOL_ACTION PCB_ACTIONS::placeLinkedDesignBlock( TOOL_ACTION_ARGS()
|
||||
.Icon( BITMAPS::add_component )
|
||||
.Flags( AF_ACTIVATE ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::applyDesignBlockLayout( TOOL_ACTION_ARGS()
|
||||
.Name( "pcbnew.InteractiveDrawing.applyDesignBlockLayout" )
|
||||
.Scope( AS_GLOBAL )
|
||||
.FriendlyName( _( "Apply Design Block Layout" ) )
|
||||
.Tooltip( _( "Apply linked design block layout to selected group" ) )
|
||||
.Icon( BITMAPS::add_component )
|
||||
.Flags( AF_ACTIVATE ) );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::saveToLinkedDesignBlock( TOOL_ACTION_ARGS()
|
||||
.Name( "pcbnew.InteractiveDrawing.saveToLinkedDesignBlock" )
|
||||
.Scope( AS_GLOBAL )
|
||||
|
@ -456,6 +456,7 @@ public:
|
||||
// Design Block management
|
||||
static TOOL_ACTION placeDesignBlock;
|
||||
static TOOL_ACTION placeLinkedDesignBlock;
|
||||
static TOOL_ACTION applyDesignBlockLayout;
|
||||
static TOOL_ACTION saveToLinkedDesignBlock;
|
||||
static TOOL_ACTION showDesignBlockPanel;
|
||||
static TOOL_ACTION saveBoardAsDesignBlock;
|
||||
|
@ -45,6 +45,8 @@
|
||||
#include <design_block.h>
|
||||
#include <dialogs/dialog_paste_special.h>
|
||||
#include <pcb_dimension.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
#include <geometry/shape_utils.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <footprint.h>
|
||||
#include <layer_pairs.h>
|
||||
@ -73,6 +75,7 @@
|
||||
#include <settings/color_settings.h>
|
||||
#include <string>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tools/multichannel_tool.h>
|
||||
#include <footprint_edit_frame.h>
|
||||
#include <footprint_editor_settings.h>
|
||||
#include <footprint_viewer_frame.h>
|
||||
@ -1374,6 +1377,175 @@ int PCB_CONTROL::AppendDesignBlock( const TOOL_EVENT& aEvent )
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PCB_CONTROL::ApplyDesignBlockLayout( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
|
||||
|
||||
if( !editFrame )
|
||||
return 1;
|
||||
|
||||
BOARD* brd = board();
|
||||
|
||||
if( !brd )
|
||||
return 1;
|
||||
|
||||
// Need to have a group selected and it needs to have a linked design block
|
||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
PCB_SELECTION selection = selTool->GetSelection();
|
||||
|
||||
if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
|
||||
return 1;
|
||||
|
||||
PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
|
||||
|
||||
if( !group->HasDesignBlockLink() )
|
||||
return 1;
|
||||
|
||||
std::set<EDA_ITEM*> originalItems;
|
||||
// Apply MCT_SKIP_STRUCT to every EDA_ITEM on the board so we know what is not part of the design block
|
||||
// Can't use SKIP_STRUCT as that is used and cleared by the temporary board appending
|
||||
brd->Visit( []( EDA_ITEM* item, void* )
|
||||
{
|
||||
item->SetFlags( MCT_SKIP_STRUCT );
|
||||
return INSPECT_RESULT::CONTINUE;
|
||||
},
|
||||
nullptr, GENERAL_COLLECTOR::AllBoardItems );
|
||||
|
||||
int ret = PlaceLinkedDesignBlock( aEvent );
|
||||
|
||||
// If we succeeded in placing the linked design block, we're ready to apply the multichannel tool
|
||||
if( ret == 0 )
|
||||
{
|
||||
// Make a lambda for the bounding box of all the components
|
||||
auto generateBoundingBox = [&]( std::unordered_set<EDA_ITEM*> aItems )
|
||||
{
|
||||
std::vector<VECTOR2I> bbCorners;
|
||||
bbCorners.reserve( aItems.size() * 4 );
|
||||
|
||||
for( auto item : aItems )
|
||||
{
|
||||
const BOX2I bb = item->GetBoundingBox().GetInflated( 100000 );
|
||||
KIGEOM::CollectBoxCorners( bb, bbCorners );
|
||||
}
|
||||
|
||||
std::vector<VECTOR2I> hullVertices;
|
||||
BuildConvexHull( hullVertices, bbCorners );
|
||||
|
||||
SHAPE_LINE_CHAIN hull( hullVertices );
|
||||
|
||||
// Make the newly computed convex hull use only 90 degree segments
|
||||
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_generateEnabled = true;
|
||||
|
||||
// Add all components that aren't marked MCT_SKIP_STRUCT to ra.m_components
|
||||
std::unordered_set<EDA_ITEM*> allDbItems;
|
||||
brd->Visit(
|
||||
[&]( EDA_ITEM* item, void* data )
|
||||
{
|
||||
if( !item->HasFlag( MCT_SKIP_STRUCT ) )
|
||||
{
|
||||
allDbItems.insert( item );
|
||||
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
dbRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
|
||||
}
|
||||
return INSPECT_RESULT::CONTINUE;
|
||||
},
|
||||
nullptr, GENERAL_COLLECTOR::AllBoardItems );
|
||||
|
||||
dbRA.m_area = new ZONE( board() );
|
||||
//dbRA.m_area->SetZoneName( wxString::Format( wxT( "design-block-source-%s" ), group->GetDesignBlockLibId().GetUniStringLibId() ) );
|
||||
dbRA.m_area->SetIsRuleArea( true );
|
||||
dbRA.m_area->SetLayerSet( LSET::AllCuMask() );
|
||||
dbRA.m_area->SetPlacementAreaEnabled( true );
|
||||
dbRA.m_area->SetDoNotAllowZoneFills( false );
|
||||
dbRA.m_area->SetDoNotAllowVias( false );
|
||||
dbRA.m_area->SetDoNotAllowTracks( false );
|
||||
dbRA.m_area->SetDoNotAllowPads( false );
|
||||
dbRA.m_area->SetDoNotAllowFootprints( false );
|
||||
dbRA.m_area->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::GROUP_PLACEMENT );
|
||||
dbRA.m_area->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() );
|
||||
dbRA.m_area->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
|
||||
dbRA.m_area->AddPolygon( generateBoundingBox( allDbItems ) );
|
||||
dbRA.m_center = dbRA.m_area->Outline()->COutline( 0 ).Centre();
|
||||
|
||||
// Create the destination rule area for the group
|
||||
RULE_AREA destRA;
|
||||
|
||||
destRA.m_sourceType = PLACEMENT_SOURCE_T::GROUP_PLACEMENT;
|
||||
|
||||
// Add all the design block group footprints to the destination rule area
|
||||
for( EDA_ITEM* item : group->GetItems() )
|
||||
{
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
{
|
||||
FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
|
||||
|
||||
// If the footprint is locked, we can't place it
|
||||
if( fp->IsLocked() )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Footprint %s is locked and cannot be placed." ), fp->GetReference() );
|
||||
m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
|
||||
return 1;
|
||||
}
|
||||
|
||||
destRA.m_components.insert( fp );
|
||||
}
|
||||
}
|
||||
|
||||
destRA.m_area = new ZONE( board() );
|
||||
destRA.m_area->SetZoneName(
|
||||
wxString::Format( wxT( "design-block-dest-%s" ), group->GetDesignBlockLibId().GetUniStringLibId() ) );
|
||||
destRA.m_area->SetIsRuleArea( true );
|
||||
destRA.m_area->SetLayerSet( LSET::AllCuMask() );
|
||||
destRA.m_area->SetPlacementAreaEnabled( true );
|
||||
destRA.m_area->SetDoNotAllowZoneFills( false );
|
||||
destRA.m_area->SetDoNotAllowVias( false );
|
||||
destRA.m_area->SetDoNotAllowTracks( false );
|
||||
destRA.m_area->SetDoNotAllowPads( false );
|
||||
destRA.m_area->SetDoNotAllowFootprints( false );
|
||||
destRA.m_area->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::GROUP_PLACEMENT );
|
||||
destRA.m_area->SetPlacementAreaSource( group->GetName() );
|
||||
destRA.m_area->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
|
||||
destRA.m_area->AddPolygon( generateBoundingBox( group->GetItems() ) );
|
||||
destRA.m_center = destRA.m_area->Outline()->COutline( 0 ).Centre();
|
||||
|
||||
// Use the multichannel tool to repeat the layout
|
||||
MULTICHANNEL_TOOL* mct = m_toolMgr->GetTool<MULTICHANNEL_TOOL>();
|
||||
|
||||
ret = mct->RepeatLayout( aEvent, dbRA, destRA );
|
||||
|
||||
delete dbRA.m_area;
|
||||
delete destRA.m_area;
|
||||
}
|
||||
|
||||
// We're done, remove SKIP_STRUCT
|
||||
brd->Visit( []( EDA_ITEM* item, void* )
|
||||
{
|
||||
item->ClearFlags( MCT_SKIP_STRUCT );
|
||||
return INSPECT_RESULT::CONTINUE;
|
||||
},
|
||||
nullptr, GENERAL_COLLECTOR::AllBoardItems );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PCB_CONTROL::PlaceLinkedDesignBlock( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
@ -2732,6 +2904,7 @@ void PCB_CONTROL::setTransitions()
|
||||
|
||||
// Append control
|
||||
Go( &PCB_CONTROL::AppendDesignBlock, PCB_ACTIONS::placeDesignBlock.MakeEvent() );
|
||||
Go( &PCB_CONTROL::ApplyDesignBlockLayout, PCB_ACTIONS::applyDesignBlockLayout.MakeEvent() );
|
||||
Go( &PCB_CONTROL::PlaceLinkedDesignBlock, PCB_ACTIONS::placeLinkedDesignBlock.MakeEvent() );
|
||||
Go( &PCB_CONTROL::SaveToLinkedDesignBlock, PCB_ACTIONS::saveToLinkedDesignBlock.MakeEvent() );
|
||||
Go( &PCB_CONTROL::AppendBoardFromFile, PCB_ACTIONS::appendBoard.MakeEvent() );
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
int Paste( const TOOL_EVENT& aEvent );
|
||||
int AppendBoardFromFile( const TOOL_EVENT& aEvent );
|
||||
int AppendDesignBlock( const TOOL_EVENT& aEvent );
|
||||
int ApplyDesignBlockLayout( const TOOL_EVENT& aEvent );
|
||||
int PlaceLinkedDesignBlock( const TOOL_EVENT& aEvent );
|
||||
int SaveToLinkedDesignBlock( const TOOL_EVENT& aEvent );
|
||||
int AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock = nullptr );
|
||||
|
@ -198,6 +198,7 @@ bool PCB_SELECTION_TOOL::Init()
|
||||
menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
|
||||
menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
|
||||
menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
|
||||
menu.AddItem( PCB_ACTIONS::applyDesignBlockLayout, groupEnterCondition, 1 );
|
||||
menu.AddItem( PCB_ACTIONS::placeLinkedDesignBlock, groupEnterCondition, 1 );
|
||||
menu.AddItem( PCB_ACTIONS::saveToLinkedDesignBlock, groupEnterCondition, 1 );
|
||||
menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 1 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user