From 1a4eba56a78bbb5f9b1daca5040d67ccb9bb6383 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Thu, 7 Aug 2025 11:24:36 -0700 Subject: [PATCH] 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 --- api/proto/board/board_types.proto | 4 ++++ common/pcb.keywords | 1 + pcbnew/api/api_pcb_enums.cpp | 6 ++++++ .../dialog_global_edit_tracks_and_vias.cpp | 4 ++++ ...ialog_global_edit_tracks_and_vias_base.cpp | 2 +- ...ialog_global_edit_tracks_and_vias_base.fbp | 2 +- .../dialogs/dialog_track_via_properties.cpp | 7 +++++++ .../dialog_track_via_properties_base.cpp | 2 +- .../dialog_track_via_properties_base.fbp | 2 +- pcbnew/pad.cpp | 9 ++++++++- pcbnew/pad.h | 6 ++---- pcbnew/padstack.h | 1 + .../pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp | 4 ++++ .../kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp | 8 ++++++++ pcbnew/pcb_track.cpp | 3 +++ pcbnew/pcb_track.h | 6 ++---- pcbnew/router/pns_kicad_iface.cpp | 19 +++++++++++++++++++ pcbnew/router/pns_via.cpp | 9 +++++++++ pcbnew/router/pns_via.h | 13 +++++++++++++ pcbnew/zone_filler.cpp | 12 ++++++++++-- 20 files changed, 105 insertions(+), 15 deletions(-) diff --git a/api/proto/board/board_types.proto b/api/proto/board/board_types.proto index d8f1503d83..f9c1744df7 100644 --- a/api/proto/board/board_types.proto +++ b/api/proto/board/board_types.proto @@ -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 diff --git a/common/pcb.keywords b/common/pcb.keywords index 6ddf2524a6..ad278590d2 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -323,6 +323,7 @@ solid span stackup start +start_end_only status stroke style diff --git a/pcbnew/api/api_pcb_enums.cpp b/pcbnew/api/api_pcb_enums.cpp index d332cce1c1..50b801fefd 100644 --- a/pcbnew/api/api_pcb_enums.cpp +++ b/pcbnew/api/api_pcb_enums.cpp @@ -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"); @@ -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"); diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp index c9c6a5cc3a..660e969a57 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp @@ -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; } diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.cpp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.cpp index b9c5f71c1d..1a7803b6a6 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.cpp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.cpp @@ -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 ); diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.fbp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.fbp index ba67d9dfe3..708b8e78a3 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.fbp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias_base.fbp @@ -1721,7 +1721,7 @@ 1 0 - "All copper layers" "Start, end, and connected layers" "Connected layers only" + "All copper layers" "Start, end, and connected layers" "Connected layers only" "Start and end layers only" 1 1 diff --git a/pcbnew/dialogs/dialog_track_via_properties.cpp b/pcbnew/dialogs/dialog_track_via_properties.cpp index 276b6716f6..ae27453656 100644 --- a/pcbnew/dialogs/dialog_track_via_properties.cpp +++ b/pcbnew/dialogs/dialog_track_via_properties.cpp @@ -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 ); } } diff --git a/pcbnew/dialogs/dialog_track_via_properties_base.cpp b/pcbnew/dialogs/dialog_track_via_properties_base.cpp index c8515a7aaa..0111b13dd2 100644 --- a/pcbnew/dialogs/dialog_track_via_properties_base.cpp +++ b/pcbnew/dialogs/dialog_track_via_properties_base.cpp @@ -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 ); diff --git a/pcbnew/dialogs/dialog_track_via_properties_base.fbp b/pcbnew/dialogs/dialog_track_via_properties_base.fbp index c54c26521b..9ba322e062 100644 --- a/pcbnew/dialogs/dialog_track_via_properties_base.fbp +++ b/pcbnew/dialogs/dialog_track_via_properties_base.fbp @@ -3903,7 +3903,7 @@ 1 0 - "All copper layers" "Start, end, and connected layers" "Connected layers only" + "All copper layers" "Start, end, and connected layers" "Connected layers only" "Start and end layers only" 1 1 diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index dbe7cd7600..0d108523d6 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -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 ); diff --git a/pcbnew/pad.h b/pcbnew/pad.h index bd3076e6b7..a7b6b3c96f 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -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; diff --git a/pcbnew/padstack.h b/pcbnew/padstack.h index 0fa317321c..e182fa68f5 100644 --- a/pcbnew/padstack.h +++ b/pcbnew/padstack.h @@ -150,6 +150,7 @@ public: enum class UNCONNECTED_LAYER_MODE { KEEP_ALL, + START_END_ONLY, REMOVE_ALL, REMOVE_EXCEPT_START_AND_END }; diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp index c445cf2c2b..243faebc6d 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp @@ -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; } diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp index c6c5ca766f..a8af826560 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp @@ -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 diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index 5896658041..a7fe860474 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -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 ) diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index e036e1cfef..32450a1c60 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -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; diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 79fe6de009..5bde1a01aa 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -1325,6 +1325,7 @@ std::unique_ptr 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( 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( 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( 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() ) ); diff --git a/pcbnew/router/pns_via.cpp b/pcbnew/router/pns_via.cpp index ea82049978..241e05718f 100644 --- a/pcbnew/router/pns_via.cpp +++ b/pcbnew/router/pns_via.cpp @@ -75,6 +75,15 @@ std::vector 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; diff --git a/pcbnew/router/pns_via.h b/pcbnew/router/pns_via.h index 9130d14a24..ff8d959445 100644 --- a/pcbnew/router/pns_via.h +++ b/pcbnew/router/pns_via.h @@ -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; }; diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 2e8860597a..67a23f6470 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -403,7 +403,11 @@ bool ZONE_FILLER::Fill( const std::vector& 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;