Implement free vias fully

CHANGED: manually-placed (stitching) vias won't have their nets automatically updated
(unless the via is placed directly on a track segment)

CHANGED: stitching vias can be placed on footprint pads and pick up their nets

Fixes https://gitlab.com/kicad/code/kicad/-/issues/5484
This commit is contained in:
Jon Evans 2020-12-20 16:29:43 -05:00
parent cd162a8f58
commit 70c397a9b4
15 changed files with 182 additions and 59 deletions

View File

@ -117,6 +117,7 @@ fp_line
fp_poly
fp_rect
fp_text
free
full
general
generator

View File

@ -260,7 +260,7 @@ CN_ITEM* CN_LIST::Add( ARC* aArc )
CN_ITEM* CN_LIST::Add( VIA* via )
{
auto item = new CN_ITEM( via, true, 1 );
auto item = new CN_ITEM( via, !via->GetIsFree(), 1 );
m_items.push_back( item );
item->AddAnchor( via->GetStart() );

View File

@ -161,6 +161,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
viaType = v->GetViaType();
m_ViaStartLayer->SetLayerSelection( v->TopLayer() );
m_ViaEndLayer->SetLayerSelection( v->BottomLayer() );
m_viaNotFree->SetValue( !v->GetIsFree() );
}
else // check if values are the same for every selected via
{
@ -179,6 +180,9 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
if( viaType != v->GetViaType() )
viaType = VIATYPE::NOT_DEFINED;
if( v->GetIsFree() != !m_viaNotFree->GetValue() )
m_viaNotFree->Set3StateValue( wxCHK_UNDETERMINED );
if( m_ViaStartLayer->GetLayerSelection() != v->TopLayer() )
{
m_ViaStartLayer->SetUndefinedLayerName( INDETERMINATE_STATE );
@ -486,6 +490,9 @@ bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
if( !m_viaY.IsIndeterminate() )
v->SetPosition( wxPoint( v->GetPosition().x, m_viaY.GetValue() ) );
if( m_viaNotFree->Get3StateValue() != wxCHK_UNDETERMINED )
v->SetIsFree( !m_viaNotFree->GetValue() );
switch( m_ViaTypeChoice->GetSelection() )
{
case 0:

View File

@ -231,15 +231,14 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
m_sbViaSizer->Add( 0, 0, 0, wxEXPAND|wxRIGHT|wxLEFT, 10 );
wxFlexGridSizer* fgViaRightSizer;
fgViaRightSizer = new wxFlexGridSizer( 3, 2, 3, 5 );
fgViaRightSizer->AddGrowableCol( 1 );
fgViaRightSizer->SetFlexibleDirection( wxBOTH );
fgViaRightSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
wxGridBagSizer* gbViaRightSizer;
gbViaRightSizer = new wxGridBagSizer( 0, 0 );
gbViaRightSizer->SetFlexibleDirection( wxBOTH );
gbViaRightSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_ViaTypeLabel = new wxStaticText( m_sbViaSizer->GetStaticBox(), wxID_ANY, _("Via type:"), wxDefaultPosition, wxDefaultSize, 0 );
m_ViaTypeLabel->Wrap( -1 );
fgViaRightSizer->Add( m_ViaTypeLabel, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
gbViaRightSizer->Add( m_ViaTypeLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 );
wxString m_ViaTypeChoiceChoices[] = { _("Through"), _("Micro"), _("Blind/buried") };
int m_ViaTypeChoiceNChoices = sizeof( m_ViaTypeChoiceChoices ) / sizeof( wxString );
@ -247,24 +246,31 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
m_ViaTypeChoice->SetSelection( 0 );
m_ViaTypeChoice->Enable( false );
fgViaRightSizer->Add( m_ViaTypeChoice, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxBOTTOM, 4 );
gbViaRightSizer->Add( m_ViaTypeChoice, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_ViaStartLayerLabel = new wxStaticText( m_sbViaSizer->GetStaticBox(), wxID_ANY, _("Start layer:"), wxDefaultPosition, wxDefaultSize, 0 );
m_ViaStartLayerLabel->Wrap( -1 );
fgViaRightSizer->Add( m_ViaStartLayerLabel, 0, wxALIGN_CENTER_VERTICAL, 5 );
gbViaRightSizer->Add( m_ViaStartLayerLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_ViaStartLayer = new PCB_LAYER_BOX_SELECTOR( m_sbViaSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
fgViaRightSizer->Add( m_ViaStartLayer, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
gbViaRightSizer->Add( m_ViaStartLayer, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_ViaEndLayerLabel1 = new wxStaticText( m_sbViaSizer->GetStaticBox(), wxID_ANY, _("End layer:"), wxDefaultPosition, wxDefaultSize, 0 );
m_ViaEndLayerLabel1->Wrap( -1 );
fgViaRightSizer->Add( m_ViaEndLayerLabel1, 0, wxALIGN_CENTER_VERTICAL, 5 );
gbViaRightSizer->Add( m_ViaEndLayerLabel1, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_ViaEndLayer = new PCB_LAYER_BOX_SELECTOR( m_sbViaSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
fgViaRightSizer->Add( m_ViaEndLayer, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
gbViaRightSizer->Add( m_ViaEndLayer, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_viaNotFree = new wxCheckBox( m_sbViaSizer->GetStaticBox(), wxID_ANY, _("Automatically update via net"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE );
m_viaNotFree->SetToolTip( _("Automatically change the net of this via when the pads or zones it touches are changed") );
gbViaRightSizer->Add( m_viaNotFree, wxGBPosition( 3, 0 ), wxGBSpan( 1, 2 ), wxALL, 5 );
m_sbViaSizer->Add( fgViaRightSizer, 4, wxLEFT, 10 );
gbViaRightSizer->AddGrowableCol( 1 );
m_sbViaSizer->Add( gbViaRightSizer, 4, wxEXPAND|wxLEFT, 5 );
m_MainSizer->Add( m_sbViaSizer, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
@ -284,7 +290,6 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
this->SetSizer( m_MainSizer );
this->Layout();
m_MainSizer->Fit( this );
this->Centre( wxBOTH );

View File

@ -45,7 +45,7 @@
<property name="minimum_size">-1,-1</property>
<property name="name">DIALOG_TRACK_VIA_PROPERTIES_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="size">720,685</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Track &amp; Via Properties</property>
@ -1681,11 +1681,11 @@
<property name="orient">wxHORIZONTAL</property>
<property name="parent">1</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">5</property>
<object class="wxFlexGridSizer" expanded="1">
<object class="wxFlexGridSizer" expanded="0">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property>
@ -2717,36 +2717,38 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">10</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">10</property>
<property name="flag">wxLEFT</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxLEFT</property>
<property name="proportion">4</property>
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">2</property>
<object class="wxGridBagSizer" expanded="0">
<property name="empty_cell_size"></property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property>
<property name="growablerows"></property>
<property name="hgap">5</property>
<property name="hgap">0</property>
<property name="minimum_size"></property>
<property name="name">fgViaRightSizer</property>
<property name="name">gbViaRightSizer</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="rows">3</property>
<property name="vgap">3</property>
<object class="sizeritem" expanded="0">
<property name="vgap">0</property>
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM</property>
<property name="proportion">0</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="row">0</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -2804,10 +2806,13 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">4</property>
<property name="flag">wxEXPAND|wxALIGN_CENTER_VERTICAL|wxBOTTOM</property>
<property name="proportion">0</property>
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">1</property>
<property name="flag">wxALL</property>
<property name="row">0</property>
<property name="rowspan">1</property>
<object class="wxChoice" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -2869,10 +2874,13 @@
<event name="OnChoice">onViaEdit</event>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -2930,10 +2938,13 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALIGN_CENTER_VERTICAL|wxBOTTOM</property>
<property name="proportion">0</property>
<property name="colspan">1</property>
<property name="column">1</property>
<property name="flag">wxALL</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxBitmapComboBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -2995,10 +3006,13 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="row">2</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -3056,10 +3070,13 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<property name="colspan">1</property>
<property name="column">1</property>
<property name="flag">wxALL</property>
<property name="row">2</property>
<property name="rowspan">1</property>
<object class="wxBitmapComboBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -3121,6 +3138,73 @@
<property name="window_style"></property>
</object>
</object>
<object class="gbsizeritem" expanded="0">
<property name="border">5</property>
<property name="colspan">2</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="row">3</property>
<property name="rowspan">1</property>
<object class="wxCheckBox" expanded="0">
<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="checked">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">Automatically update via net</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_viaNotFree</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">wxCHK_3STATE</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Automatically change the net of this via when the pads or zones it touches are changed</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>
</object>
</object>
</object>
</object>
</object>

View File

@ -26,6 +26,7 @@ class PCB_LAYER_BOX_SELECTOR;
#include <wx/textctrl.h>
#include <wx/choice.h>
#include <wx/bmpcbox.h>
#include <wx/gbsizer.h>
#include <wx/button.h>
#include <wx/dialog.h>
@ -90,6 +91,7 @@ class DIALOG_TRACK_VIA_PROPERTIES_BASE : public DIALOG_SHIM
PCB_LAYER_BOX_SELECTOR* m_ViaStartLayer;
wxStaticText* m_ViaEndLayerLabel1;
PCB_LAYER_BOX_SELECTOR* m_ViaEndLayer;
wxCheckBox* m_viaNotFree;
wxStdDialogButtonSizer* m_StdButtons;
wxButton* m_StdButtonsOK;
wxButton* m_StdButtonsCancel;
@ -105,7 +107,7 @@ class DIALOG_TRACK_VIA_PROPERTIES_BASE : public DIALOG_SHIM
public:
DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Track & Via Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU );
DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Track & Via Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 720,685 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU );
~DIALOG_TRACK_VIA_PROPERTIES_BASE();
};

View File

@ -1724,6 +1724,9 @@ void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const
if( via->GetKeepTopBottom() )
m_out->Print( 0, " (keep_end_layers)" );
}
if( via->GetIsFree() )
m_out->Print( 0, " (free)" );
}
else if( aTrack->Type() == PCB_ARC_T )
{

View File

@ -91,7 +91,8 @@ class PCB_TEXT;
//#define SEXPR_BOARD_FILE_VERSION 20201002 // Add groups in footprints (for footprint editor).
//#define SEXPR_BOARD_FILE_VERSION 20201114 // Add first-class support for filled shapes.
//#define SEXPR_BOARD_FILE_VERSION 20201115 // module -> footprint and change fill syntax.
#define SEXPR_BOARD_FILE_VERSION 20201116 // Write version and generator string in footprint files.
//#define SEXPR_BOARD_FILE_VERSION 20201116 // Write version and generator string in footprint files.
#define SEXPR_BOARD_FILE_VERSION 20201220 // Add free via token
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag

View File

@ -4365,8 +4365,13 @@ VIA* PCB_PARSER::parseVIA()
NeedRIGHT();
break;
case T_free:
via->SetIsFree();
NeedRIGHT();
break;
default:
Expecting( "blind, micro, at, size, drill, layers, net, tstamp, or status" );
Expecting( "blind, micro, at, size, drill, layers, net, free, tstamp, or status" );
}
}

View File

@ -920,6 +920,8 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( VIA* aVia )
if( aVia->IsLocked() )
via->Mark( PNS::MK_LOCKED );
via->SetIsFree( aVia->GetIsFree() );
return via;
}
@ -1426,6 +1428,7 @@ void PNS_KICAD_IFACE::AddItem( PNS::ITEM* aItem )
via_board->SetDrill( via->Drill() );
via_board->SetNetCode( via->Net() > 0 ? via->Net() : 0 );
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
via_board->SetIsFree( via->IsFree() );
via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ),
ToLAYER_ID( via->Layers().End() ) );
newBI = via_board;

View File

@ -99,6 +99,7 @@ VIA* VIA::Clone() const
v->m_marker = m_marker;
v->m_viaType = m_viaType;
v->m_parent = m_parent;
v->m_isFree = m_isFree;
return v;
}

View File

@ -54,6 +54,7 @@ public:
m_diameter = 2; // Dummy value
m_drill = 0;
m_viaType = VIATYPE::THROUGH;
m_isFree = false;
}
VIA( const VECTOR2I& aPos, const LAYER_RANGE& aLayers, int aDiameter, int aDrill, int aNet = -1,
@ -68,6 +69,7 @@ public:
m_shape = SHAPE_CIRCLE( aPos, aDiameter / 2 );
m_alternateShape = SHAPE_CIRCLE( m_pos, aDrill / 2 );
m_viaType = aViaType;
m_isFree = false;
}
@ -84,6 +86,7 @@ public:
m_rank = aB.m_rank;
m_drill = aB.m_drill;
m_viaType = aB.m_viaType;
m_isFree = aB.m_isFree;
}
static inline bool ClassOf( const ITEM* aItem )
@ -134,6 +137,9 @@ public:
m_drill = aDrill;
}
bool IsFree() const { return m_isFree; }
void SetIsFree( bool aIsFree ) { m_isFree = aIsFree; }
bool PushoutForce( NODE* aNode,
const VECTOR2I& aDirection,
VECTOR2I& aForce,
@ -175,6 +181,7 @@ private:
SHAPE_CIRCLE m_shape;
SHAPE_CIRCLE m_alternateShape;
VIATYPE m_viaType;
bool m_isFree;
};
}

View File

@ -2178,15 +2178,6 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
const wxPoint position = aVia->GetPosition();
const LSET lset = aVia->GetLayerSet();
for( FOOTPRINT* footprint : m_board->Footprints() )
{
for( PAD* pad : footprint->Pads() )
{
if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
return -1;
}
}
std::vector<ZONE*> foundZones;
for( ZONE* zone : m_board->Zones() )
@ -2270,7 +2261,10 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
newNet = track->GetNetCode();
}
else
{
newNet = findStitchedZoneNet( via );
via->SetIsFree();
}
if( newNet > 0 )
via->SetNetCode( newNet );

View File

@ -67,6 +67,7 @@ VIA::VIA( BOARD_ITEM* aParent ) :
SetDrillDefault();
m_removeUnconnectedLayer = false;
m_keepTopBottomLayer = true;
m_isFree = false;
}

View File

@ -505,6 +505,14 @@ public:
*/
void SetDrillDefault() { m_drill = UNDEFINED_DRILL_DIAMETER; }
/**
* Checks if the via is a free via (as opposed to one created on a track by the router).
* Free vias don't have their nets automatically updated by the connectivity algorithm.
* @return true if the via is a free via
*/
bool GetIsFree() const { return m_isFree; }
void SetIsFree( bool aFree = true ) { m_isFree = aFree; }
/**
* Function IsDrillDefault
* @return true if the drill value is default value (-1)
@ -529,6 +537,7 @@ private:
bool m_removeUnconnectedLayer; ///< Remove unconnected copper on a via
bool m_keepTopBottomLayer; ///< Keep the top and bottom annular rings
bool m_isFree; ///< "Free" vias don't get their nets auto-updated
};