mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
ADDED: Skip Via support
Skip vias are vias that are flashed on their start and end layers but have no annular rings on the interior layers and do not connect to zones in those layers You can now select Annular ring type "Start and end layers only". This will prevent annular ring flashing on intermediate layers and zones fills will provide clearance. You can still connect tracks to intermediate layers but preventing that will fall to the designer Fixes https://gitlab.com/kicad/code/kicad/-/issues/21433
This commit is contained in:
parent
d8a99ea38f
commit
1a4eba56a7
@ -196,6 +196,10 @@ enum UnconnectedLayerRemoval
|
||||
|
||||
// Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected.
|
||||
ULR_REMOVE_EXCEPT_START_AND_END = 3;
|
||||
|
||||
// Keep annular rings only on the start and end layers regardless of connections.
|
||||
// Since: 10.0.0
|
||||
ULR_START_END_ONLY = 4;
|
||||
}
|
||||
|
||||
// The shape of a pad on a given layer
|
||||
|
@ -323,6 +323,7 @@ solid
|
||||
span
|
||||
stackup
|
||||
start
|
||||
start_end_only
|
||||
status
|
||||
stroke
|
||||
style
|
||||
|
@ -257,6 +257,9 @@ types::UnconnectedLayerRemoval ToProtoEnum( PADSTACK::UNCONNECTED_LAYER_MODE aVa
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
return types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY:
|
||||
return types::UnconnectedLayerRemoval::ULR_START_END_ONLY;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, types::UnconnectedLayerRemoval::ULR_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<PADSTACK::UNCONNECTED_LAYER_MODE>");
|
||||
@ -279,6 +282,9 @@ PADSTACK::UNCONNECTED_LAYER_MODE FromProtoEnum( types::UnconnectedLayerRemoval a
|
||||
case types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
|
||||
return PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END;
|
||||
|
||||
case types::UnconnectedLayerRemoval::ULR_START_END_ONLY:
|
||||
return PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL,
|
||||
"Unhandled case in FromProtoEnum<types::UnconnectedLayerRemoval>");
|
||||
|
@ -318,6 +318,10 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::processItem( PICKED_ITEMS_LIST* aUndoLi
|
||||
v->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
||||
break;
|
||||
case 3:
|
||||
v->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS_BASE::DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS_BASE
|
||||
m_annularRingsLabel->Wrap( -1 );
|
||||
fgSizerTrackViaPopups->Add( m_annularRingsLabel, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 15 );
|
||||
|
||||
wxString m_annularRingsCtrlChoices[] = { _("All copper layers"), _("Start, end, and connected layers"), _("Connected layers only") };
|
||||
wxString m_annularRingsCtrlChoices[] = { _("All copper layers"), _("Start, end, and connected layers"), _("Connected layers only"), _("Start and end layers only") };
|
||||
int m_annularRingsCtrlNChoices = sizeof( m_annularRingsCtrlChoices ) / sizeof( wxString );
|
||||
m_annularRingsCtrl = new wxChoice( sbAction->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_annularRingsCtrlNChoices, m_annularRingsCtrlChoices, 0 );
|
||||
m_annularRingsCtrl->SetSelection( 1 );
|
||||
|
@ -1721,7 +1721,7 @@
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="choices">"All copper layers" "Start, end, and connected layers" "Connected layers only"</property>
|
||||
<property name="choices">"All copper layers" "Start, end, and connected layers" "Connected layers only" "Start and end layers only"</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
|
@ -136,6 +136,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_EDIT_FRAME* a
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL: return 0;
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END: return 1;
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL: return 2;
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY: return 3;
|
||||
}
|
||||
};
|
||||
|
||||
@ -510,6 +511,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_EDIT_FRAME* a
|
||||
|
||||
m_annularRingsLabel->Show( getLayerDepth() > 1 );
|
||||
m_annularRingsCtrl->Show( getLayerDepth() > 1 );
|
||||
m_annularRingsCtrl->Enable( true );
|
||||
|
||||
afterPadstackModeChanged();
|
||||
}
|
||||
@ -857,6 +859,10 @@ bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
|
||||
via->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
||||
break;
|
||||
case 3:
|
||||
via->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1252,6 +1258,7 @@ void DIALOG_TRACK_VIA_PROPERTIES::onViaEdit( wxCommandEvent& aEvent )
|
||||
|
||||
m_annularRingsLabel->Show( getLayerDepth() > 1 );
|
||||
m_annularRingsCtrl->Show( getLayerDepth() > 1 );
|
||||
m_annularRingsCtrl->Enable( true );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,7 @@ DIALOG_TRACK_VIA_PROPERTIES_BASE::DIALOG_TRACK_VIA_PROPERTIES_BASE( wxWindow* pa
|
||||
m_annularRingsLabel->Wrap( -1 );
|
||||
gbSizer4->Add( m_annularRingsLabel, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
wxString m_annularRingsCtrlChoices[] = { _("All copper layers"), _("Start, end, and connected layers"), _("Connected layers only") };
|
||||
wxString m_annularRingsCtrlChoices[] = { _("All copper layers"), _("Start, end, and connected layers"), _("Connected layers only"), _("Start and end layers only") };
|
||||
int m_annularRingsCtrlNChoices = sizeof( m_annularRingsCtrlChoices ) / sizeof( wxString );
|
||||
m_annularRingsCtrl = new wxChoice( m_sbViaSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_annularRingsCtrlNChoices, m_annularRingsCtrlChoices, 0 );
|
||||
m_annularRingsCtrl->SetSelection( 0 );
|
||||
|
@ -3903,7 +3903,7 @@
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="choices">"All copper layers" "Start, end, and connected layers" "Connected layers only"</property>
|
||||
<property name="choices">"All copper layers" "Start, end, and connected layers" "Connected layers only" "Start and end layers only"</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
|
@ -406,6 +406,11 @@ bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
|
||||
|
||||
// Plated through hole pads need copper on the top/bottom layers for proper soldering
|
||||
// Unless the user has removed them in the pad dialog
|
||||
if( mode == PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY )
|
||||
{
|
||||
return aLayer == m_padStack.Drill().start || aLayer == m_padStack.Drill().end;
|
||||
}
|
||||
|
||||
if( mode == PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END
|
||||
&& IsExternalCopperLayer( aLayer ) )
|
||||
{
|
||||
@ -2762,7 +2767,9 @@ static struct PAD_DESC
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL, _HKI( "All copper layers" ) )
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL, _HKI( "Connected layers only" ) )
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END,
|
||||
_HKI( "Front, back and connected layers" ) );
|
||||
_HKI( "Front, back and connected layers" ) )
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY,
|
||||
_HKI( "Start and end layers only" ) );
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( PAD );
|
||||
|
@ -774,10 +774,8 @@ public:
|
||||
return true;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
{
|
||||
if( aLayer == m_padStack.Drill().start || aLayer == m_padStack.Drill().end )
|
||||
return false;
|
||||
}
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY:
|
||||
return aLayer != m_padStack.Drill().start && aLayer != m_padStack.Drill().end;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -150,6 +150,7 @@ public:
|
||||
enum class UNCONNECTED_LAYER_MODE
|
||||
{
|
||||
KEEP_ALL,
|
||||
START_END_ONLY,
|
||||
REMOVE_ALL,
|
||||
REMOVE_EXCEPT_START_AND_END
|
||||
};
|
||||
|
@ -2368,6 +2368,10 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack ) const
|
||||
KICAD_FORMAT::FormatBool( m_out, "keep_end_layers", true );
|
||||
break;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY:
|
||||
KICAD_FORMAT::FormatBool( m_out, "start_end_only", true );
|
||||
break;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL:
|
||||
break;
|
||||
}
|
||||
|
@ -6661,6 +6661,14 @@ PCB_VIA* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_VIA()
|
||||
break;
|
||||
}
|
||||
|
||||
case T_start_end_only:
|
||||
{
|
||||
if( parseMaybeAbsentBool( true ) )
|
||||
via->Padstack().SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case T_zone_layer_connections:
|
||||
{
|
||||
// Ensure only copper layers are stored int ZoneLayerOverride array
|
||||
|
@ -1458,6 +1458,9 @@ bool PCB_VIA::FlashLayer( int aLayer ) const
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL:
|
||||
// Check for removal below
|
||||
break;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY:
|
||||
return layer == Padstack().Drill().start || layer == Padstack().Drill().end;
|
||||
}
|
||||
|
||||
if( GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
|
||||
|
@ -630,10 +630,8 @@ public:
|
||||
return true;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
{
|
||||
if( aLayer == m_padStack.Drill().start || aLayer == m_padStack.Drill().end )
|
||||
return false;
|
||||
}
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY:
|
||||
return aLayer != m_padStack.Drill().start && aLayer != m_padStack.Drill().end;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1325,6 +1325,7 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
|
||||
aVia->GetDrillValue(),
|
||||
aVia->GetNet(),
|
||||
aVia->GetViaType() );
|
||||
via->SetUnconnectedLayerMode( aVia->Padstack().UnconnectedLayerMode() );
|
||||
|
||||
auto syncDiameter =
|
||||
[&]( PCB_LAYER_ID aLayer )
|
||||
@ -1591,6 +1592,9 @@ bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer
|
||||
}
|
||||
}
|
||||
|
||||
if( aItem->OfKind( PNS::ITEM::VIA_T ) )
|
||||
return static_cast<const PNS::VIA*>( aItem )->ConnectsLayer( aLayer );
|
||||
|
||||
return aItem->Layers().Overlaps( aLayer );
|
||||
}
|
||||
|
||||
@ -1635,6 +1639,19 @@ bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem,
|
||||
}
|
||||
}
|
||||
|
||||
if( aItem->OfKind( PNS::ITEM::VIA_T ) )
|
||||
{
|
||||
const PNS::VIA* via = static_cast<const PNS::VIA*>( aItem );
|
||||
|
||||
for( int layer = test.Start(); layer <= test.End(); ++layer )
|
||||
{
|
||||
if( via->ConnectsLayer( layer ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return test.Start() <= test.End();
|
||||
}
|
||||
|
||||
@ -2029,6 +2046,7 @@ void PNS_KICAD_IFACE::modifyBoardItem( PNS::ITEM* aItem )
|
||||
via_board->SetDrill( via->Drill() );
|
||||
via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
|
||||
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
|
||||
via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
|
||||
via_board->SetIsFree( via->IsFree() );
|
||||
via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
|
||||
GetBoardLayerFromPNSLayer( via->Layers().End() ) );
|
||||
@ -2128,6 +2146,7 @@ BOARD_CONNECTED_ITEM* PNS_KICAD_IFACE::createBoardItem( PNS::ITEM* aItem )
|
||||
via_board->SetDrill( via->Drill() );
|
||||
via_board->SetNet( net );
|
||||
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
|
||||
via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
|
||||
via_board->SetIsFree( via->IsFree() );
|
||||
via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
|
||||
GetBoardLayerFromPNSLayer( via->Layers().End() ) );
|
||||
|
@ -75,6 +75,15 @@ std::vector<int> VIA::UniqueShapeLayers() const
|
||||
}
|
||||
|
||||
|
||||
bool VIA::ConnectsLayer( int aLayer ) const
|
||||
{
|
||||
if( m_unconnectedLayerMode == PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY )
|
||||
return aLayer == m_layers.Start() || aLayer == m_layers.End();
|
||||
|
||||
return m_layers.Overlaps( aLayer );
|
||||
}
|
||||
|
||||
|
||||
void VIA::SetStackMode( STACK_MODE aStackMode )
|
||||
{
|
||||
m_stackMode = aStackMode;
|
||||
|
@ -84,6 +84,7 @@ public:
|
||||
m_diameters[0] = 2; // Dummy value
|
||||
m_drill = 1; // Dummy value
|
||||
m_viaType = VIATYPE::THROUGH;
|
||||
m_unconnectedLayerMode = PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL;
|
||||
m_isFree = false;
|
||||
m_isVirtual = false;
|
||||
SetHole( HOLE::MakeCircularHole( m_pos, m_drill / 2, PNS_LAYER_RANGE() ) );
|
||||
@ -103,6 +104,7 @@ public:
|
||||
m_shapes[0] = SHAPE_CIRCLE( aPos, aDiameter / 2 );
|
||||
SetHole( HOLE::MakeCircularHole( m_pos, aDrill / 2, PNS_LAYER_RANGE() ) );
|
||||
m_viaType = aViaType;
|
||||
m_unconnectedLayerMode = PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL;
|
||||
m_isFree = false;
|
||||
m_isVirtual = false;
|
||||
}
|
||||
@ -125,6 +127,7 @@ public:
|
||||
m_marker = aB.m_marker;
|
||||
m_rank = aB.m_rank;
|
||||
m_viaType = aB.m_viaType;
|
||||
m_unconnectedLayerMode = aB.m_unconnectedLayerMode;
|
||||
m_isFree = aB.m_isFree;
|
||||
m_isVirtual = aB.m_isVirtual;
|
||||
}
|
||||
@ -156,6 +159,7 @@ public:
|
||||
m_rank = aB.m_rank;
|
||||
m_routable = aB.m_routable;
|
||||
m_viaType = aB.m_viaType;
|
||||
m_unconnectedLayerMode = aB.m_unconnectedLayerMode;
|
||||
m_isFree = aB.m_isFree;
|
||||
m_isVirtual = aB.m_isVirtual;
|
||||
m_uid = aB.m_uid;
|
||||
@ -193,6 +197,14 @@ public:
|
||||
VIATYPE ViaType() const { return m_viaType; }
|
||||
void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; }
|
||||
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const { return m_unconnectedLayerMode; }
|
||||
void SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE aMode )
|
||||
{
|
||||
m_unconnectedLayerMode = aMode;
|
||||
}
|
||||
|
||||
bool ConnectsLayer( int aLayer ) const;
|
||||
|
||||
int Diameter( int aLayer ) const
|
||||
{
|
||||
int layer = EffectiveLayer( aLayer );
|
||||
@ -284,6 +296,7 @@ private:
|
||||
int m_drill;
|
||||
VECTOR2I m_pos;
|
||||
VIATYPE m_viaType;
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE m_unconnectedLayerMode;
|
||||
bool m_isFree;
|
||||
HOLE* m_hole;
|
||||
};
|
||||
|
@ -403,7 +403,11 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
|
||||
{
|
||||
ZONE* zone = findHighestPriorityZone( bbox, layer, netcode, viaTestFn );
|
||||
|
||||
if( zone && zone->GetNetCode() == via->GetNetCode() )
|
||||
if( zone && zone->GetNetCode() == via->GetNetCode()
|
||||
&& ( via->Padstack().UnconnectedLayerMode()
|
||||
!= PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY
|
||||
|| layer == via->Padstack().Drill().start
|
||||
|| layer == via->Padstack().Drill().end ) )
|
||||
via->SetZoneLayerOverride( layer, ZLO_FORCE_FLASHED );
|
||||
else
|
||||
via->SetZoneLayerOverride( layer, ZLO_FORCE_NO_ZONE_CONNECTION );
|
||||
@ -1204,7 +1208,11 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer
|
||||
if( !viaBBox.Intersects( aZone->GetBoundingBox() ) )
|
||||
continue;
|
||||
|
||||
bool noConnection = via->GetNetCode() != aZone->GetNetCode();
|
||||
bool noConnection = via->GetNetCode() != aZone->GetNetCode()
|
||||
|| ( via->Padstack().UnconnectedLayerMode()
|
||||
== PADSTACK::UNCONNECTED_LAYER_MODE::START_END_ONLY
|
||||
&& aLayer != via->Padstack().Drill().start
|
||||
&& aLayer != via->Padstack().Drill().end );
|
||||
|
||||
if( noConnection )
|
||||
continue;
|
||||
|
Loading…
x
Reference in New Issue
Block a user