ADDED defined pad groups for net-tie footprints

Each pad group is allowed to short nets with other pads in its group.

Legacy footprints with the "net tie" keyword hack will get a single
group auto-created with all the footprint's pads in it.

DRC and the router now allow a track to collide with copper graphic items
while entering a net-tie pad as long as the closest point in the collision
is within the pad.

DRC (and the footprint checker) now check for copper items in the
footprint shorting pads which are not in the same pad group.

Fixes https://gitlab.com/kicad/code/kicad/issues/2265
This commit is contained in:
Jeff Young 2022-08-19 18:34:53 +01:00
parent 508df402f6
commit 46df421064
24 changed files with 976 additions and 89 deletions

View File

@ -190,6 +190,7 @@ name
net
net_class
net_name
net_tie_pad_groups
nets
no
no_connects

View File

@ -103,15 +103,15 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
}
auto errorHandler =
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, int aErrorCode,
const wxString& aMsg, const VECTOR2I& aPt )
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, const BOARD_ITEM* aItemC,
int aErrorCode, const wxString& aMsg, const VECTOR2I& aPt )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( aErrorCode );
if( !aMsg.IsEmpty() )
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
drcItem->SetItems( aItemA, aItemB );
drcItem->SetItems( aItemA, aItemB, aItemC );
PCB_MARKER* marker = new PCB_MARKER( drcItem, aPt );
board->Add( marker );
@ -121,7 +121,7 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
OUTLINE_ERROR_HANDLER outlineErrorHandler =
[&]( const wxString& aMsg, BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const VECTOR2I& aPt )
{
errorHandler( aItemA, aItemB, DRCE_MALFORMED_COURTYARD, aMsg, aPt );
errorHandler( aItemA, aItemB, nullptr, DRCE_MALFORMED_COURTYARD, aMsg, aPt );
};
footprint->BuildCourtyardCaches( &outlineErrorHandler );
@ -129,21 +129,40 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
footprint->CheckFootprintAttributes(
[&]( const wxString& aMsg )
{
errorHandler( footprint, nullptr, DRCE_FOOTPRINT_TYPE_MISMATCH, aMsg, { 0, 0 } );
errorHandler( footprint, nullptr, nullptr, DRCE_FOOTPRINT_TYPE_MISMATCH, aMsg,
{ 0, 0 } );
} );
footprint->CheckPads(
[&]( const PAD* aPad, int aErrorCode, const wxString& aMsg )
{
errorHandler( aPad, nullptr, aErrorCode, aMsg, aPad->GetPosition() );
errorHandler( aPad, nullptr, nullptr, aErrorCode, aMsg, aPad->GetPosition() );
} );
footprint->CheckOverlappingPads(
[&]( const PAD* aPadA, const PAD* aPadB, const VECTOR2I& aPosition )
{
errorHandler( aPadA, aPadB, DRCE_OVERLAPPING_PADS, wxEmptyString, aPosition );
errorHandler( aPadA, aPadB, nullptr, DRCE_OVERLAPPING_PADS, wxEmptyString,
aPosition );
} );
if( footprint->IsNetTie() )
{
footprint->CheckNetTiePadGroups(
[&]( const wxString& aMsg )
{
errorHandler( footprint, nullptr, nullptr, DRCE_FOOTPRINT, aMsg, { 0, 0 } );
} );
footprint->CheckNetTies(
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, const BOARD_ITEM* aItemC,
const VECTOR2I& aPosition )
{
errorHandler( aItemA, aItemB, aItemC, DRCE_SHORTING_ITEMS, wxEmptyString,
aPosition );
} );
}
m_checksRun = true;
SetMarkersProvider( new DRC_ITEMS_PROVIDER( board, MARKER_BASE::MARKER_DRC ) );

View File

@ -165,6 +165,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(
m_itemsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_privateLayersGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_padGroupsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to the user's preference
m_itemsGrid->ShowHideColumns( m_frame->GetSettings()->m_FootprintTextShownColumns );
@ -202,6 +203,8 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(
m_bpDelete->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
m_bpAddLayer->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
m_bpDeleteLayer->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
m_bpAddPadGroup->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
m_bpRemovePadGroup->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
SetupStandardButtons();
@ -303,14 +306,22 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow()
case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
}
for( const wxString& group : m_footprint->GetNetTiePadGroups() )
{
if( !group.IsEmpty() )
{
m_padGroupsGrid->AppendRows( 1 );
m_padGroupsGrid->SetCellValue( m_padGroupsGrid->GetNumberRows() - 1, 0, group );
}
}
// Items grid
for( int col = 0; col < m_itemsGrid->GetNumberCols(); col++ )
{
// Adjust min size to the column label size
m_itemsGrid->SetColMinimalWidth( col, m_itemsGrid->GetVisibleWidth( col, true, false,
false ) );
m_itemsGrid->SetColMinimalWidth( col, m_itemsGrid->GetVisibleWidth( col, true, false ) );
// Adjust the column size.
int col_size = m_itemsGrid->GetVisibleWidth( col, true, true, false );
int col_size = m_itemsGrid->GetVisibleWidth( col );
if( col == FPT_LAYER ) // This one's a drop-down. Check all possible values.
{
@ -410,8 +421,12 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
if( !DIALOG_SHIM::TransferDataFromWindow() )
return false;
if( !m_itemsGrid->CommitPendingChanges() )
if( !m_itemsGrid->CommitPendingChanges()
|| !m_privateLayersGrid->CommitPendingChanges()
|| !m_padGroupsGrid->CommitPendingChanges() )
{
return false;
}
// This only commits the editor, model updating is done below so it is inside
// the commit
@ -517,6 +532,16 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
case 3: m_footprint->SetZoneConnection( ZONE_CONNECTION::NONE ); break;
}
m_footprint->ClearNetTiePadGroups();
for( int ii = 0; ii < m_padGroupsGrid->GetNumberRows(); ++ii )
{
wxString group = m_padGroupsGrid->GetCellValue( ii, 0 );
if( !group.IsEmpty() )
m_footprint->AddNetTiePadGroup( group );
}
// Copy the models from the panel to the footprint
std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList();
std::vector<FP_3DMODEL>* fpList = &m_footprint->Models();
@ -649,9 +674,7 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteLayer( wxCommandEvent& event
int curRow = m_privateLayersGrid->GetGridCursorRow();
if( curRow < 0 )
{
return;
}
m_privateLayers->erase( m_privateLayers->begin() + curRow );
@ -669,6 +692,46 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteLayer( wxCommandEvent& event
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnAddPadGroup( wxCommandEvent& event )
{
if( !m_padGroupsGrid->CommitPendingChanges() )
return;
m_padGroupsGrid->AppendRows( 1 );
m_padGroupsGrid->SetFocus();
m_padGroupsGrid->MakeCellVisible( m_padGroupsGrid->GetNumberRows() - 1, 0 );
m_padGroupsGrid->SetGridCursor( m_padGroupsGrid->GetNumberRows() - 1, 0 );
m_padGroupsGrid->EnableCellEditControl( true );
m_padGroupsGrid->ShowCellEditControl();
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnRemovePadGroup( wxCommandEvent& event )
{
if( !m_padGroupsGrid->CommitPendingChanges() )
return;
wxArrayInt selectedRows = m_padGroupsGrid->GetSelectedRows();
int curRow = m_padGroupsGrid->GetGridCursorRow();
if( selectedRows.empty() && curRow >= 0 && curRow < m_padGroupsGrid->GetNumberRows() )
selectedRows.Add( curRow );
for( int ii = selectedRows.Count() - 1; ii >= 0; --ii )
{
int row = selectedRows.Item( ii );
m_padGroupsGrid->DeleteRows( row, 1 );
curRow = std::min( curRow, row );
}
curRow = std::max( 0, curRow - 1 );
m_padGroupsGrid->MakeCellVisible( curRow, m_padGroupsGrid->GetGridCursorCol() );
m_padGroupsGrid->SetGridCursor( curRow, m_padGroupsGrid->GetGridCursorCol() );
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::adjustGridColumns()
{
// Account for scroll bars
@ -679,11 +742,16 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::adjustGridColumns()
for( int i = 1; i < m_itemsGrid->GetNumberCols(); i++ )
itemsWidth -= m_itemsGrid->GetColSize( i );
if( itemsWidth > 0 )
{
m_itemsGrid->SetColSize( 0, std::max( itemsWidth,
m_itemsGrid->GetVisibleWidth( 0, true, false, false ) ) );
}
m_itemsGrid->SetColSize( 0, std::max( itemsWidth,
m_itemsGrid->GetVisibleWidth( 0, true, false ) ) );
// Update the width private layers grid
m_privateLayersGrid->SetColSize( 0, std::max( m_privateLayersGrid->GetClientSize().x,
m_privateLayersGrid->GetVisibleWidth( 0 ) ) );
// Update the width net tie pad groups grid
m_padGroupsGrid->SetColSize( 0, std::max( m_padGroupsGrid->GetClientSize().x,
m_padGroupsGrid->GetVisibleWidth( 0 ) ) );
// Update the width of the 3D panel
m_3dPanel->AdjustGridColumnWidths();

View File

@ -88,6 +88,8 @@ private:
void OnDeleteField( wxCommandEvent& event ) override;
void OnAddLayer( wxCommandEvent& event ) override;
void OnDeleteLayer( wxCommandEvent& event ) override;
void OnAddPadGroup( wxCommandEvent& event ) override;
void OnRemovePadGroup( wxCommandEvent& event ) override;
void OnUpdateUI( wxUpdateUIEvent& event ) override;
bool checkFootprintName( const wxString& aFootprintName );

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -49,7 +49,6 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
m_itemsGrid->SetColSize( 10, 110 );
m_itemsGrid->EnableDragColMove( false );
m_itemsGrid->EnableDragColSize( true );
m_itemsGrid->SetColLabelSize( 24 );
m_itemsGrid->SetColLabelValue( 0, _("Text Items") );
m_itemsGrid->SetColLabelValue( 1, _("Show") );
m_itemsGrid->SetColLabelValue( 2, _("Width") );
@ -61,13 +60,14 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
m_itemsGrid->SetColLabelValue( 8, _("Unconstrained") );
m_itemsGrid->SetColLabelValue( 9, _("X Offset") );
m_itemsGrid->SetColLabelValue( 10, _("Y Offset") );
m_itemsGrid->SetColLabelSize( 24 );
m_itemsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_itemsGrid->EnableDragRowSize( false );
m_itemsGrid->SetRowLabelSize( 160 );
m_itemsGrid->SetRowLabelValue( 0, _("Reference designator") );
m_itemsGrid->SetRowLabelValue( 1, _("Value") );
m_itemsGrid->SetRowLabelSize( 160 );
m_itemsGrid->SetRowLabelAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
// Label Appearance
@ -222,7 +222,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
m_PanelGeneral->SetSizer( m_PanelPropertiesBoxSizer );
m_PanelGeneral->Layout();
m_PanelPropertiesBoxSizer->Fit( m_PanelGeneral );
m_NoteBook->AddPage( m_PanelGeneral, _("General"), true );
m_NoteBook->AddPage( m_PanelGeneral, _("General"), false );
m_PanelClearances = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizerPanelClearances;
bSizerPanelClearances = new wxBoxSizer( wxVERTICAL );
@ -246,7 +246,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
gbSizer1->Add( m_NetClearanceLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_NetClearanceCtrl = new wxTextCtrl( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_NetClearanceCtrl = new wxTextCtrl( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer1->Add( m_NetClearanceCtrl, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
m_NetClearanceUnits = new wxStaticText( sbSizerLocalProperties->GetStaticBox(), wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
@ -318,27 +318,81 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
bSizerPanelClearances->Add( sbSizerLocalProperties, 0, wxEXPAND|wxALL, 5 );
wxStaticBoxSizer* sbSizer5;
sbSizer5 = new wxStaticBoxSizer( new wxStaticBox( m_PanelClearances, wxID_ANY, _("Connection to Copper Zones") ), wxHORIZONTAL );
wxStaticBoxSizer* sbSizerCopperZones;
sbSizerCopperZones = new wxStaticBoxSizer( new wxStaticBox( m_PanelClearances, wxID_ANY, _("Connection to Copper Zones") ), wxHORIZONTAL );
m_staticText16 = new wxStaticText( sbSizer5->GetStaticBox(), wxID_ANY, _("Pad connection to zones:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText16 = new wxStaticText( sbSizerCopperZones->GetStaticBox(), wxID_ANY, _("Pad connection to zones:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText16->Wrap( -1 );
sbSizer5->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 5 );
sbSizerCopperZones->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT, 5 );
wxString m_ZoneConnectionChoiceChoices[] = { _("Use zone setting"), _("Solid"), _("Thermal relief"), _("None") };
int m_ZoneConnectionChoiceNChoices = sizeof( m_ZoneConnectionChoiceChoices ) / sizeof( wxString );
m_ZoneConnectionChoice = new wxChoice( sbSizer5->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
m_ZoneConnectionChoice = new wxChoice( sbSizerCopperZones->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
m_ZoneConnectionChoice->SetSelection( 0 );
sbSizer5->Add( m_ZoneConnectionChoice, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 );
sbSizerCopperZones->Add( m_ZoneConnectionChoice, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 );
bSizerPanelClearances->Add( sbSizer5, 0, wxALL|wxEXPAND, 5 );
bSizerPanelClearances->Add( sbSizerCopperZones, 0, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbSizerNetTies;
sbSizerNetTies = new wxStaticBoxSizer( new wxStaticBox( m_PanelClearances, wxID_ANY, _("Net Ties") ), wxVERTICAL );
m_padGroupsLabel = new wxStaticText( sbSizerNetTies->GetStaticBox(), wxID_ANY, _("Pad groups allowed to short different nets:"), wxDefaultPosition, wxDefaultSize, 0 );
m_padGroupsLabel->Wrap( -1 );
sbSizerNetTies->Add( m_padGroupsLabel, 0, wxRIGHT|wxLEFT, 5 );
m_padGroupsGrid = new WX_GRID( sbSizerNetTies->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_padGroupsGrid->CreateGrid( 0, 1 );
m_padGroupsGrid->EnableEditing( true );
m_padGroupsGrid->EnableGridLines( true );
m_padGroupsGrid->EnableDragGridSize( false );
m_padGroupsGrid->SetMargins( 0, 0 );
// Columns
m_padGroupsGrid->SetColSize( 0, 320 );
m_padGroupsGrid->EnableDragColMove( false );
m_padGroupsGrid->EnableDragColSize( true );
m_padGroupsGrid->SetColLabelSize( 0 );
m_padGroupsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_padGroupsGrid->EnableDragRowSize( true );
m_padGroupsGrid->SetRowLabelSize( 0 );
m_padGroupsGrid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_padGroupsGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
m_padGroupsGrid->SetMinSize( wxSize( -1,30 ) );
sbSizerNetTies->Add( m_padGroupsGrid, 1, wxALL|wxEXPAND, 5 );
wxBoxSizer* bButtonSize2;
bButtonSize2 = new wxBoxSizer( wxHORIZONTAL );
m_bpAddPadGroup = new wxBitmapButton( sbSizerNetTies->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bButtonSize2->Add( m_bpAddPadGroup, 0, wxRIGHT|wxLEFT, 5 );
bButtonSize2->Add( 20, 0, 0, wxEXPAND, 5 );
m_bpRemovePadGroup = new wxBitmapButton( sbSizerNetTies->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bButtonSize2->Add( m_bpRemovePadGroup, 0, wxRIGHT, 5 );
sbSizerNetTies->Add( bButtonSize2, 0, wxEXPAND|wxBOTTOM, 2 );
bSizerPanelClearances->Add( sbSizerNetTies, 1, wxEXPAND|wxALL, 5 );
m_PanelClearances->SetSizer( bSizerPanelClearances );
m_PanelClearances->Layout();
bSizerPanelClearances->Fit( m_PanelClearances );
m_NoteBook->AddPage( m_PanelClearances, _("Clearance Overrides and Settings"), false );
m_NoteBook->AddPage( m_PanelClearances, _("Clearance Overrides and Settings"), true );
m_GeneralBoxSizer->Add( m_NoteBook, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
@ -372,6 +426,9 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
m_privateLayersGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddLayer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddLayer ), NULL, this );
m_bpDeleteLayer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnDeleteLayer ), NULL, this );
m_padGroupsGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddPadGroup->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddPadGroup ), NULL, this );
m_bpRemovePadGroup->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnRemovePadGroup ), NULL, this );
}
DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::~DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE()
@ -386,5 +443,8 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::~DIALOG_FOOTPRINT_PROPERTIES_FP_EDIT
m_privateLayersGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddLayer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddLayer ), NULL, this );
m_bpDeleteLayer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnDeleteLayer ), NULL, this );
m_padGroupsGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddPadGroup->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddPadGroup ), NULL, this );
m_bpRemovePadGroup->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnRemovePadGroup ), NULL, this );
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="15" />
<FileVersion major="1" minor="16" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
@ -14,6 +14,7 @@
<property name="file">dialog_footprint_properties_fp_editor_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">dialog_footprint_properties_fp_editor_base</property>
@ -25,6 +26,7 @@
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
@ -50,6 +52,7 @@
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Footprint Properties</property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
@ -120,7 +123,7 @@
<object class="notebookpage" expanded="1">
<property name="bitmap"></property>
<property name="label">General</property>
<property name="select">1</property>
<property name="select">0</property>
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -300,6 +303,7 @@
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
@ -383,6 +387,7 @@
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
@ -973,6 +978,7 @@
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
@ -1056,6 +1062,7 @@
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
@ -1534,8 +1541,8 @@
<object class="notebookpage" expanded="1">
<property name="bitmap"></property>
<property name="label">Clearance Overrides and Settings</property>
<property name="select">0</property>
<object class="wxPanel" expanded="0">
<property name="select">1</property>
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1586,7 +1593,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizerPanelClearances</property>
<property name="orient">wxVERTICAL</property>
@ -1804,7 +1811,7 @@
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="value">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
@ -2678,7 +2685,7 @@
<property name="id">wxID_ANY</property>
<property name="label">Connection to Copper Zones</property>
<property name="minimum_size"></property>
<property name="name">sbSizer5</property>
<property name="name">sbSizerCopperZones</property>
<property name="orient">wxHORIZONTAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
@ -2809,6 +2816,339 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">Net Ties</property>
<property name="minimum_size"></property>
<property name="name">sbSizerNetTies</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Pad groups allowed to short different nets:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_padGroupsLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxGrid" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_LEFT</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_TOP</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size">0</property>
<property name="col_label_values"></property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">1</property>
<property name="column_sizes">320</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_col_move">0</property>
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">1</property>
<property name="editing">1</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">1</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label_bg"></property>
<property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,30</property>
<property name="moveable">1</property>
<property name="name">m_padGroupsGrid</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">WX_GRID; widgets/wx_grid.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnSize">OnGridSize</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">2</property>
<property name="flag">wxEXPAND|wxBOTTOM</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bButtonSize2</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Add Pad Group</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_bpAddPadGroup</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnAddPadGroup</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">20</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Delete Pad Group</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_bpRemovePadGroup</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnRemovePadGroup</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -86,11 +86,15 @@ class DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE : public DIALOG_SHIM
wxStaticText* m_staticTextInfoPaste;
wxStaticText* m_staticText16;
wxChoice* m_ZoneConnectionChoice;
wxStaticText* m_padGroupsLabel;
WX_GRID* m_padGroupsGrid;
wxBitmapButton* m_bpAddPadGroup;
wxBitmapButton* m_bpRemovePadGroup;
wxStdDialogButtonSizer* m_sdbSizerStdButtons;
wxButton* m_sdbSizerStdButtonsOK;
wxButton* m_sdbSizerStdButtonsCancel;
// Virtual event handlers, overide them in your derived class
// Virtual event handlers, override them in your derived class
virtual void OnInitDlg( wxInitDialogEvent& event ) { event.Skip(); }
virtual void OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void OnGridSize( wxSizeEvent& event ) { event.Skip(); }
@ -99,11 +103,14 @@ class DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE : public DIALOG_SHIM
virtual void OnFootprintNameText( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddLayer( wxCommandEvent& event ) { event.Skip(); }
virtual void OnDeleteLayer( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddPadGroup( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemovePadGroup( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Footprint Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE();
};

View File

@ -1712,10 +1712,24 @@ bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP,
}
bool DRC_ENGINE::IsNetTie( BOARD_ITEM* aItem )
bool DRC_ENGINE::IsNetTieExclusion( int aTrackNetCode, PCB_LAYER_ID aTrackLayer,
const VECTOR2I& aCollisionPos, BOARD_ITEM* aCollidingItem )
{
if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
return static_cast<FOOTPRINT*>( aItem->GetParent() )->IsNetTie();
FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( aCollidingItem->GetParentFootprint() );
if( parentFootprint && parentFootprint->IsNetTie() )
{
for( PAD* pad : parentFootprint->Pads() )
{
if( aTrackNetCode == pad->GetNetCode() )
{
std::shared_ptr<SHAPE> otherShape = pad->GetEffectiveShape( aTrackLayer );
if( otherShape->Collide( aCollisionPos, 0 ) )
return true;
}
}
}
return false;
}

View File

@ -194,7 +194,12 @@ public:
static int MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
wxString& aBaseDpName );
static bool IsNetTie( BOARD_ITEM* aItem );
/**
* Check if the given collision between a track and another item occurs during the track's
* entry into a net-tie pad.
*/
static bool IsNetTieExclusion( int aTrackNetCode, PCB_LAYER_ID aTrackLayer,
const VECTOR2I& aCollisionPos, BOARD_ITEM* aCollidingItem );
private:
void addRule( std::shared_ptr<DRC_RULE>& rule )

View File

@ -245,6 +245,10 @@ DRC_ITEM DRC_ITEM::diffPairUncoupledLengthTooLong( DRCE_DIFF_PAIR_UNCOUPLED_LENG
_( "Differential uncoupled length too long" ),
wxT( "diff_pair_uncoupled_length_too_long" ) );
DRC_ITEM DRC_ITEM::footprint( DRCE_FOOTPRINT,
_( "Footprint is not valid" ),
wxT( "footprint" ) );
DRC_ITEM DRC_ITEM::footprintTypeMismatch( DRCE_FOOTPRINT_TYPE_MISMATCH,
_( "Footprint component type doesn't match footprint pads" ),
wxT( "footprint_type_mismatch" ) );
@ -308,6 +312,7 @@ std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
DRC_ITEM::itemsNotAllowed,
DRC_ITEM::zonesIntersect,
DRC_ITEM::isolatedCopper,
DRC_ITEM::footprint,
DRC_ITEM::padstack,
DRC_ITEM::pthInsideCourtyard,
DRC_ITEM::npthInsideCourtyard,
@ -375,6 +380,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
case DRCE_TOO_MANY_VIAS: return std::make_shared<DRC_ITEM>( tooManyVias );
case DRCE_DIFF_PAIR_GAP_OUT_OF_RANGE: return std::make_shared<DRC_ITEM>( diffPairGapOutOfRange );
case DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG: return std::make_shared<DRC_ITEM>( diffPairUncoupledLengthTooLong );
case DRCE_FOOTPRINT: return std::make_shared<DRC_ITEM>( footprint );
case DRCE_FOOTPRINT_TYPE_MISMATCH: return std::make_shared<DRC_ITEM>( footprintTypeMismatch );
case DRCE_PAD_TH_WITH_NO_HOLE: return std::make_shared<DRC_ITEM>( footprintTHPadhasNoHole );
case DRCE_OVERLAPPING_PADS: return std::make_shared<DRC_ITEM>( footprintOverlappingPads );

View File

@ -77,6 +77,7 @@ enum PCB_DRC_CODE {
DRCE_LIB_FOOTPRINT_MISMATCH, // footprint does not match the current library
DRCE_PAD_TH_WITH_NO_HOLE, // footprint has Plated Through-Hole with no hole
DRCE_OVERLAPPING_PADS, // footprint with overlapping pads
DRCE_FOOTPRINT, // error in footprint definition
DRCE_UNRESOLVED_VARIABLE,
DRCE_ASSERTION_FAILURE, // user-defined (custom rule) assertion
@ -203,6 +204,7 @@ private:
static DRC_ITEM tooManyVias;
static DRC_ITEM diffPairGapOutOfRange;
static DRC_ITEM diffPairUncoupledLengthTooLong;
static DRC_ITEM footprint;
static DRC_ITEM footprintTypeMismatch;
static DRC_ITEM footprintTHPadhasNoHole;
static DRC_ITEM footprintOverlappingPads;

View File

@ -210,22 +210,30 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( PCB_TRACK* track,
if( trackShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg;
if( m_drcEngine->IsNetTieExclusion( track->GetNetCode(), layer, pos, other ) )
{
// Collision occurred as track was entering a pad marked as a net-tie. We
// allow these.
}
else
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg;
msg.Printf( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), clearance ),
MessageTextFromValue( userUnits(), actual ) );
msg.Printf( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), clearance ),
MessageTextFromValue( userUnits(), actual ) );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( track, other );
drce->SetViolatingRule( constraint.GetParentRule() );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetItems( track, other );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, pos, layer );
reportViolation( drce, pos, layer );
if( !m_drcEngine->GetReportAllTrackErrors() )
return false;
if( !m_drcEngine->GetReportAllTrackErrors() )
return false;
}
}
}
@ -433,11 +441,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
// Filter:
[&]( BOARD_ITEM* other ) -> bool
{
// It would really be better to know what particular nets a nettie
// should allow, but for now it is what it is.
if( DRC_ENGINE::IsNetTie( other ) )
return false;
auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )

View File

@ -33,7 +33,9 @@
- DRCE_FOOTPRINT_TYPE_MISMATCH,
- DRCE_OVERLAPPING_PADS,
- DRCE_PAD_TH_WITH_NO_HOLE,
- DRCE_PADSTACK
- DRCE_PADSTACK,
- DRCE_FOOTPRINT (unknown or duplicate pads in net-tie pad groups),
- DRCE_SHORTING_ITEMS
*/
class DRC_TEST_PROVIDER_FOOTPRINT_CHECKS : public DRC_TEST_PROVIDER
@ -68,15 +70,15 @@ bool DRC_TEST_PROVIDER_FOOTPRINT_CHECKS::Run()
return false; // DRC cancelled
auto errorHandler =
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, int aErrorCode,
const wxString& aMsg, const VECTOR2I& aPt, PCB_LAYER_ID aLayer )
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, const BOARD_ITEM* aItemC,
int aErrorCode, const wxString& aMsg, const VECTOR2I& aPt, PCB_LAYER_ID aLayer )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( aErrorCode );
if( !aMsg.IsEmpty() )
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + aMsg );
drcItem->SetItems( aItemA, aItemB );
drcItem->SetItems( aItemA, aItemB, aItemC );
reportViolation( drcItem, aPt, aLayer );
};
@ -87,8 +89,8 @@ bool DRC_TEST_PROVIDER_FOOTPRINT_CHECKS::Run()
footprint->CheckFootprintAttributes(
[&]( const wxString& aMsg )
{
errorHandler( footprint, nullptr, DRCE_FOOTPRINT_TYPE_MISMATCH, aMsg,
footprint->GetPosition(), footprint->GetLayer() );
errorHandler( footprint, nullptr, nullptr, DRCE_FOOTPRINT_TYPE_MISMATCH,
aMsg, footprint->GetPosition(), footprint->GetLayer() );
} );
}
@ -100,8 +102,8 @@ bool DRC_TEST_PROVIDER_FOOTPRINT_CHECKS::Run()
{
if( !m_drcEngine->IsErrorLimitExceeded( aErrorCode ) )
{
errorHandler( aPad, nullptr, aErrorCode, aMsg, aPad->GetPosition(),
aPad->GetPrincipalLayer() );
errorHandler( aPad, nullptr, nullptr, aErrorCode, aMsg,
aPad->GetPosition(), aPad->GetPrincipalLayer() );
}
} );
}
@ -111,10 +113,31 @@ bool DRC_TEST_PROVIDER_FOOTPRINT_CHECKS::Run()
footprint->CheckOverlappingPads(
[&]( const PAD* aPadA, const PAD* aPadB, const VECTOR2I& aPosition )
{
errorHandler( aPadA, aPadB, DRCE_OVERLAPPING_PADS, wxEmptyString,
errorHandler( aPadA, aPadB, nullptr, DRCE_OVERLAPPING_PADS, wxEmptyString,
aPosition, aPadA->GetPrincipalLayer() );
} );
}
if( footprint->IsNetTie() )
{
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_SHORTING_ITEMS ) )
{
footprint->CheckNetTies(
[&]( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
const BOARD_ITEM* aItemC, const VECTOR2I& aPosition )
{
errorHandler( aItemA, aItemB, aItemC, DRCE_SHORTING_ITEMS,
wxEmptyString, aPosition, footprint->GetLayer() );
} );
}
footprint->CheckNetTiePadGroups(
[&]( const wxString& aMsg )
{
errorHandler( footprint, nullptr, nullptr, DRCE_FOOTPRINT, aMsg,
footprint->GetPosition(), footprint->GetLayer() );
} );
}
}
return !m_drcEngine->IsCancelled();

View File

@ -376,6 +376,11 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint )
TEST( GetZoneConnection(), aLibFootprint->GetZoneConnection() );
#endif
TEST( GetNetTiePadGroups().size(), aLibFootprint->GetNetTiePadGroups().size() );
for( size_t ii = 0; ii < GetNetTiePadGroups().size(); ++ii )
TEST( GetNetTiePadGroups()[ii], aLibFootprint->GetNetTiePadGroups()[ii] );
// Text items are really problematic. We don't want to test the reference, but after that
// it gets messy.
//

View File

@ -87,6 +87,8 @@ private:
bool checkMaskAperture( BOARD_ITEM* aMaskItem, BOARD_ITEM* aTestItem, PCB_LAYER_ID aTestLayer,
int aTestNet, BOARD_ITEM** aCollidingItem );
bool checkItemMask( BOARD_ITEM* aMaskItem, int aTestNet );
private:
DRC_RULE m_bridgeRule;
@ -366,6 +368,38 @@ bool DRC_TEST_PROVIDER_SOLDER_MASK::checkMaskAperture( BOARD_ITEM* aMaskItem, BO
}
bool DRC_TEST_PROVIDER_SOLDER_MASK::checkItemMask( BOARD_ITEM* aMaskItem, int aTestNet )
{
FOOTPRINT* fp = static_cast<FOOTPRINT*>( aMaskItem->GetParentFootprint() );
if( fp && ( fp->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES ) > 0 )
{
// If we're allowing bridges then we're allowing bridges. Nothing to check.
return false;
}
// Graphic items are used to implement net-ties between pads of a group within a net-tie
// footprint. They must be allowed to intrude into their pad's mask aperture.
if( aTestNet < 0 && aMaskItem->Type() == PCB_PAD_T && fp->IsNetTie() )
{
wxString padNumber = static_cast<PAD*>( aMaskItem )->GetNumber();
for( const wxString& group : fp->GetNetTiePadGroups() )
{
wxStringTokenizer groupParser( group, "," );
while( groupParser.HasMoreTokens() )
{
if( groupParser.GetNextToken().Trim( false ).Trim( true ) == padNumber )
return false;
}
}
}
return true;
}
void DRC_TEST_PROVIDER_SOLDER_MASK::testItemAgainstItems( BOARD_ITEM* aItem,
const EDA_RECT& aItemBBox,
PCB_LAYER_ID aRefLayer,
@ -505,7 +539,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testItemAgainstItems( BOARD_ITEM* aItem,
reportViolation( drce, pos, aTargetLayer );
}
}
else
else if( checkItemMask( other, itemNet ) )
{
auto drce = DRC_ITEM::Create( DRCE_SOLDERMASK_BRIDGE );

View File

@ -109,6 +109,7 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
m_localSolderPasteMargin = aFootprint.m_localSolderPasteMargin;
m_localSolderPasteMarginRatio = aFootprint.m_localSolderPasteMarginRatio;
m_zoneConnection = aFootprint.m_zoneConnection;
m_netTiePadGroups = aFootprint.m_netTiePadGroups;
std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
@ -288,6 +289,7 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther )
m_localSolderPasteMargin = aOther.m_localSolderPasteMargin;
m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio;
m_zoneConnection = aOther.m_zoneConnection;
m_netTiePadGroups = aOther.m_netTiePadGroups;
// Move reference and value
m_reference = aOther.m_reference;
@ -384,6 +386,7 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther )
m_localSolderPasteMargin = aOther.m_localSolderPasteMargin;
m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio;
m_zoneConnection = aOther.m_zoneConnection;
m_netTiePadGroups = aOther.m_netTiePadGroups;
// Copy reference and value
*m_reference = *aOther.m_reference;
@ -2348,7 +2351,7 @@ void FOOTPRINT::CheckPads( const std::function<void( const PAD*, int,
padOutline.BooleanSubtract( holeOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
if( padOutline.IsEmpty() )
(aErrorHandler)( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
aErrorHandler( pad, DRCE_PADSTACK, _( "(PTH pad's hole leaves no copper)" ) );
}
}
}
@ -2387,14 +2390,133 @@ void FOOTPRINT::CheckOverlappingPads( const std::function<void( const PAD*, cons
if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) )
{
VECTOR2I pos;
SHAPE* padShape = pad->GetEffectiveShape().get();
SHAPE* otherShape = other->GetEffectiveShape().get();
if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
aErrorHandler( pad, other, pos );
}
}
}
}
}
void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
const BOARD_ITEM* bItem,
const BOARD_ITEM* cItem,
const VECTOR2I& )>& aErrorHandler )
{
// First build a map from pads to allowed-shorting-group indexes. This ends up being
// something like O(3n), but it still beats O(n^2) for large numbers of pads.
std::unordered_map<const PAD*, int> padToGroupIdxMap;
for( const PAD* pad : m_pads )
padToGroupIdxMap[ pad ] = -1;
for( size_t ii = 0; ii < m_netTiePadGroups.size(); ++ii )
{
wxStringTokenizer groupParser( m_netTiePadGroups[ ii ], "," );
while( groupParser.HasMoreTokens() )
{
PAD* pad = FindPadByNumber( groupParser.GetNextToken().Trim( false ).Trim( true ) );
if( pad )
padToGroupIdxMap[ pad ] = ii;
}
}
// Now collect all the footprint items which are on copper layers
std::vector<BOARD_ITEM*> copperItems;
for( BOARD_ITEM* item : m_drawings )
{
if( item->IsOnCopperLayer() )
copperItems.push_back( item );
}
for( ZONE* zone : m_fp_zones )
{
if( !zone->GetIsRuleArea() && zone->IsOnCopperLayer() )
copperItems.push_back( zone );
}
if( m_reference->IsOnCopperLayer() )
copperItems.push_back( m_reference );
if( m_value->IsOnCopperLayer() )
copperItems.push_back( m_value );
for( PCB_LAYER_ID layer : { F_Cu, In1_Cu, B_Cu } )
{
// Next, build a polygon-set for the copper on this layer. We don't really care about
// nets here, we just want to end up with a set of outlines describing the distinct
// copper polygons of the footprint.
SHAPE_POLY_SET copperOutlines;
std::map<int, std::vector<const PAD*>> outlineIdxToPadsMap;
for( BOARD_ITEM* item : copperItems )
{
if( item->IsOnLayer( layer ) )
{
item->TransformShapeWithClearanceToPolygon( copperOutlines, layer, 0,
ARC_HIGH_DEF, ERROR_OUTSIDE );
}
}
copperOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
// Index each pad to the outline in the set that it is part of.
for( const PAD* pad : m_pads )
{
for( int ii = 0; ii < copperOutlines.OutlineCount(); ++ii )
{
if( pad->GetEffectiveShape( layer )->Collide( &copperOutlines.Outline( ii ), 0 ) )
outlineIdxToPadsMap[ ii ].emplace_back( pad );
}
}
// Finally, ensure that each outline which contains multiple pads has all its pads
// listed in an allowed-shorting group.
for( const auto& [ outlineIdx, pads ] : outlineIdxToPadsMap )
{
if( pads.size() > 1 )
{
const PAD* firstPad = pads[0];
int firstGroupIdx = padToGroupIdxMap[ firstPad ];
for( size_t ii = 1; ii < pads.size(); ++ii )
{
const PAD* thisPad = pads[ii];
int thisGroupIdx = padToGroupIdxMap[ thisPad ];
if( thisGroupIdx < 0 || thisGroupIdx != firstGroupIdx )
{
(aErrorHandler)( pad, other, pos );
BOARD_ITEM* shortingItem = nullptr;
VECTOR2I pos = ( firstPad->GetPosition() + thisPad->GetPosition() ) / 2;
pos = copperOutlines.Outline( outlineIdx ).NearestPoint( pos );
for( BOARD_ITEM* item : copperItems )
{
if( item->HitTest( pos, 1 ) )
{
shortingItem = item;
break;
}
}
if( shortingItem )
aErrorHandler( shortingItem, firstPad, thisPad, pos );
else
aErrorHandler( firstPad, thisPad, nullptr, pos );
}
}
}
@ -2403,6 +2525,36 @@ void FOOTPRINT::CheckOverlappingPads( const std::function<void( const PAD*, cons
}
void FOOTPRINT::CheckNetTiePadGroups( const std::function<void( const wxString& )>& aErrorHandler )
{
std::set<wxString> padNumbers;
for( size_t ii = 0; ii < m_netTiePadGroups.size(); ++ii )
{
wxStringTokenizer groupParser( m_netTiePadGroups[ ii ], "," );
while( groupParser.HasMoreTokens() )
{
wxString padNumber( groupParser.GetNextToken().Trim( false ).Trim( true ) );
const PAD* pad = FindPadByNumber( padNumber );
if( !pad )
{
aErrorHandler( wxString::Format( _( "(net-tie pad group contains unknown pad "
"number %s)" ),
padNumber ) );
}
else if( !padNumbers.insert( padNumber ).second )
{
aErrorHandler( wxString::Format( _( "(pad %s appears in more than one net-tie "
"pad group)" ),
padNumber ) );
}
}
}
}
void FOOTPRINT::SwapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );

View File

@ -250,10 +250,31 @@ public:
void IncrementFlag() { m_arflag += 1; }
int GetFlag() const { return m_arflag; }
// A bit of a hack until net ties are supported as first class citizens
bool IsNetTie() const
{
return GetKeywords().StartsWith( wxT( "net tie" ) );
for( const wxString& group : m_netTiePadGroups )
{
if( !group.IsEmpty() )
return true;
}
return false;
}
/**
* Return a list of pad groups, each of which is allowed to short nets within their group.
* A pad group is a comma-separated list of pad numbers.
*/
const std::vector<wxString>& GetNetTiePadGroups() const { return m_netTiePadGroups; }
void ClearNetTiePadGroups()
{
m_netTiePadGroups.clear();
}
void AddNetTiePadGroup( const wxString& aGroup )
{
m_netTiePadGroups.emplace_back( aGroup );
}
/**
@ -369,9 +390,29 @@ public:
*
* @param aErrorHandler callback to handle the error messages generated
*/
void CheckOverlappingPads( const std::function<void( const PAD*, const PAD*,
void CheckOverlappingPads( const std::function<void( const PAD*,
const PAD*,
const VECTOR2I& )>& aErrorHandler );
/**
* Check for un-allowed shorting of pads in net-tie footprints. If two pads are shorted,
* they must both appear in one of the allowed-shorting lists.
*
* @param aErrorHandler callback to handle the error messages generated
*/
void CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
const BOARD_ITEM* bItem,
const BOARD_ITEM* cItem,
const VECTOR2I& )>& aErrorHandler );
/**
* Sanity check net-tie pad groups. Pads cannot be listed more than once, and pad numbers
* must correspond to a pad.
*
* @param aErrorHandler callback to handle the error messages generated
*/
void CheckNetTiePadGroups( const std::function<void( const wxString& )>& aErrorHandler );
/**
* Generate pads shapes on layer \a aLayer as polygons and adds these polygons to
* \a aCornerBuffer.
@ -764,6 +805,10 @@ private:
mutable SHAPE_POLY_SET m_cachedHull;
mutable int m_hullCacheTimeStamp;
// A list of pad groups, each of which is allowed to short nets within their group.
// A pad group is a comma-separated list of pad numbers.
std::vector<wxString> m_netTiePadGroups;
ZONE_CONNECTION m_zoneConnection;
int m_localClearance;
int m_localSolderMaskMargin; // Solder mask margin

View File

@ -3729,6 +3729,12 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
break;
}
case T_net_tie_pad_groups:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
footprint->AddNetTiePadGroup( CurStr() );
break;
case T_solder_mask_margin:
footprint->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin "
"value" ) );
@ -3933,6 +3939,25 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
pad->SetLocked( footprint->IsLocked() || footprint->LegacyPadsLocked() );
}
if( m_requiredVersion <= LEGACY_NET_TIES )
{
if( footprint->GetKeywords().StartsWith( wxT( "net tie" ) ) )
{
wxString padGroup;
for( PAD* pad : footprint->Pads() )
{
if( !padGroup.IsEmpty() )
padGroup += wxS( ", " );
padGroup += pad->GetNumber();
}
if( !padGroup.IsEmpty() )
footprint->AddNetTiePadGroup( padGroup );
}
}
footprint->SetAttributes( attributes );
footprint->SetFPID( fpid );

View File

@ -1189,11 +1189,15 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
}
if( m_ctl & CTL_OMIT_LIBNAME )
{
m_out->Print( aNestLevel, "(footprint %s",
m_out->Quotes( aFootprint->GetFPID().GetLibItemName() ).c_str() );
}
else
{
m_out->Print( aNestLevel, "(footprint %s",
m_out->Quotes( aFootprint->GetFPID().Format() ).c_str() );
}
if( !( m_ctl & CTL_OMIT_FOOTPRINT_VERSION ) )
m_out->Print( 0, " (version %d) (generator pcbnew)\n ", SEXPR_BOARD_FILE_VERSION );
@ -1223,12 +1227,16 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
}
if( !aFootprint->GetDescription().IsEmpty() )
{
m_out->Print( aNestLevel+1, "(descr %s)\n",
m_out->Quotew( aFootprint->GetDescription() ).c_str() );
}
if( !aFootprint->GetKeywords().IsEmpty() )
{
m_out->Print( aNestLevel+1, "(tags %s)\n",
m_out->Quotew( aFootprint->GetKeywords() ).c_str() );
}
const std::map<wxString, wxString>& props = aFootprint->GetProperties();
@ -1240,28 +1248,40 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
}
if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )
{
m_out->Print( aNestLevel+1, "(path %s)\n",
m_out->Quotew( aFootprint->GetPath().AsString() ).c_str() );
}
if( aFootprint->GetLocalSolderMaskMargin() != 0 )
{
m_out->Print( aNestLevel+1, "(solder_mask_margin %s)\n",
FormatInternalUnits( aFootprint->GetLocalSolderMaskMargin() ).c_str() );
}
if( aFootprint->GetLocalSolderPasteMargin() != 0 )
{
m_out->Print( aNestLevel+1, "(solder_paste_margin %s)\n",
FormatInternalUnits( aFootprint->GetLocalSolderPasteMargin() ).c_str() );
}
if( aFootprint->GetLocalSolderPasteMarginRatio() != 0 )
{
m_out->Print( aNestLevel+1, "(solder_paste_ratio %s)\n",
Double2Str( aFootprint->GetLocalSolderPasteMarginRatio() ).c_str() );
}
if( aFootprint->GetLocalClearance() != 0 )
{
m_out->Print( aNestLevel+1, "(clearance %s)\n",
FormatInternalUnits( aFootprint->GetLocalClearance() ).c_str() );
}
if( aFootprint->GetZoneConnection() != ZONE_CONNECTION::INHERITED )
{
m_out->Print( aNestLevel+1, "(zone_connect %d)\n",
static_cast<int>( aFootprint->GetZoneConnection() ) );
}
// Attributes
if( aFootprint->GetAttributes() )
@ -1305,6 +1325,19 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
m_out->Print( 0, ")\n" );
}
if( aFootprint->IsNetTie() )
{
m_out->Print( aNestLevel+1, "(net_tie_pad_groups" );
for( const wxString& group : aFootprint->GetNetTiePadGroups() )
{
m_out->Print( 0, " \"%s\"",
EscapeString( group, CTX_QUOTED_STR ).ToStdString().c_str() );
}
m_out->Print( 0, ")\n" );
}
Format( (BOARD_ITEM*) &aFootprint->Reference(), aNestLevel + 1 );
Format( (BOARD_ITEM*) &aFootprint->Value(), aNestLevel + 1 );

View File

@ -125,10 +125,13 @@ class SHAPE_LINE_CHAIN;
//#define SEXPR_BOARD_FILE_VERSION 20220427 // Exclude Edge.Cuts & Margin from fp private layers
//#define SEXPR_BOARD_FILE_VERSION 20220609 // Add teardrop keywords to identify teardrop zones
//#define SEXPR_BOARD_FILE_VERSION 20220621 // Add Image support
#define SEXPR_BOARD_FILE_VERSION 20220815 // Add allow-soldermask-bridges-in-FPs flag
//#define SEXPR_BOARD_FILE_VERSION 20220815 // Add allow-soldermask-bridges-in-FPs flag
#define SEXPR_BOARD_FILE_VERSION 20220818 // First-class storage for net-ties
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting
#define LEGACY_NET_TIES 20220815 ///< These were the last to use the keywords field
///< to indicate a net-tie.
#define CTL_OMIT_PAD_NETS (1 << 1) ///< Omit pads net names (useless in library)
#define CTL_OMIT_TSTAMPS (1 << 2) ///< Omit component time stamp (useless in library)

View File

@ -132,19 +132,29 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
if( clearance >= 0 )
{
if( m_parent && m_parent->GetLayer() == Edge_Cuts )
bool checkCastellation = ( m_parent && m_parent->GetLayer() == Edge_Cuts );
bool checkNetTie = aNode->GetRuleResolver()->IsInNetTie( this );
if( checkCastellation || checkNetTie )
{
// Slow method
int actual;
VECTOR2I pos;
if( shapeA->Collide( shapeB, clearance + lineWidthA, &actual, &pos )
&& !aNode->QueryEdgeExclusions( pos ) )
if( shapeA->Collide( shapeB, clearance + lineWidthA, &actual, &pos ) )
{
if( checkCastellation && aNode->QueryEdgeExclusions( pos ) )
return false;
if( checkNetTie && aNode->GetRuleResolver()->IsNetTieExclusion( aOther, pos, this ) )
return false;
return true;
}
}
else
{
// Fast method
if( shapeA->Collide( shapeB, clearance + lineWidthA + lineWidthB ) )
return true;
}

View File

@ -114,6 +114,10 @@ public:
virtual bool DpNetPair( const PNS::ITEM* aItem, int& aNetP, int& aNetN ) override;
virtual bool IsDiffPair( const PNS::ITEM* aA, const PNS::ITEM* aB ) override;
virtual bool IsInNetTie( const PNS::ITEM* aA ) override;
virtual bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
const PNS::ITEM* aCollidingItem ) override;
virtual bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
const PNS::ITEM* aItemB, int aLayer,
PNS::CONSTRAINT* aConstraint ) override;
@ -209,6 +213,35 @@ bool PNS_PCBNEW_RULE_RESOLVER::IsDiffPair( const PNS::ITEM* aA, const PNS::ITEM*
}
bool PNS_PCBNEW_RULE_RESOLVER::IsInNetTie( const PNS::ITEM* aA )
{
BOARD_ITEM* item = aA->Parent();
BOARD_ITEM* parentFootprint = item ? item->GetParentFootprint() : nullptr;
if( parentFootprint )
return static_cast<FOOTPRINT*>( parentFootprint )->IsNetTie();
return false;
}
bool PNS_PCBNEW_RULE_RESOLVER::IsNetTieExclusion( const PNS::ITEM* aItem,
const VECTOR2I& aCollisionPos,
const PNS::ITEM* aCollidingItem )
{
std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
BOARD_ITEM* collidingItem = aCollidingItem->Parent();
if( drcEngine && collidingItem )
{
return drcEngine->IsNetTieExclusion( aItem->Net(), ToLAYER_ID( aItem->Layer() ),
aCollisionPos, collidingItem );
}
return false;
}
bool isCopper( const PNS::ITEM* aItem )
{
BOARD_ITEM* parent = aItem->Parent();
@ -1334,9 +1367,6 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
for( FP_ZONE* zone : footprint->Zones() )
syncZone( aWorld, zone, boardOutline );
if( footprint->IsNetTie() )
continue;
for( BOARD_ITEM* mgitem : footprint->GraphicalItems() )
{
if( mgitem->Type() == PCB_FP_SHAPE_T || mgitem->Type() == PCB_FP_TEXTBOX_T )

View File

@ -91,6 +91,11 @@ public:
virtual bool IsDiffPair( const ITEM* aA, const ITEM* aB ) = 0;
virtual bool IsInNetTie( const ITEM* aA ) = 0;
virtual bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
const PNS::ITEM* aCollidingItem )= 0;
virtual bool QueryConstraint( CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
const PNS::ITEM* aItemB, int aLayer,
PNS::CONSTRAINT* aConstraint ) = 0;

View File

@ -2789,11 +2789,6 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
{
// It would really be better to know what particular nets a nettie should allow,
// but for now it is what it is.
if( DRC_ENGINE::IsNetTie( aOther ) )
return false;
DRC_CONSTRAINT constraint;
if( ( aOther->Type() == PCB_ZONE_T || aOther->Type() == PCB_FP_ZONE_T )