From 3b63d70d0177e39642b8ca44e220b9cac27db88e Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 8 Apr 2023 15:02:48 +0100 Subject: [PATCH] Centralize NPTH has-annulus processing. Fixes https://gitlab.com/kicad/code/kicad/issues/13437 --- 3d-viewer/3d_canvas/board_adapter.h | 3 +- .../3d_canvas/create_3Dgraphic_brd_items.cpp | 37 +++++----------- 3d-viewer/3d_canvas/create_layer_items.cpp | 10 ++--- pcbnew/pad.cpp | 44 ++++++++++++++----- pcbnew/pad.h | 5 +-- pcbnew/plot_board_layers.cpp | 3 ++ pcbnew/plot_brditems_plotter.cpp | 4 +- pcbnew/router/pns_kicad_iface.cpp | 26 +---------- 8 files changed, 56 insertions(+), 76 deletions(-) diff --git a/3d-viewer/3d_canvas/board_adapter.h b/3d-viewer/3d_canvas/board_adapter.h index d3bca1b269..4e8ce26abe 100644 --- a/3d-viewer/3d_canvas/board_adapter.h +++ b/3d-viewer/3d_canvas/board_adapter.h @@ -342,8 +342,7 @@ private: OBJECT_2D* createPadWithDrill( const PAD* aPad, int aInflateValue ); void addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer, - PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads, - bool aSkipNonPlatedPads ); + PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads ); void addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayerId ); diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index e0cfab4a34..6a7ad27695 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -490,41 +490,24 @@ OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer, - PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper, - bool aSkipPlatedPads, bool aSkipNonPlatedPads ) + PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads ) { for( PAD* pad : aFootprint->Pads() ) { if( !pad->IsOnLayer( aLayerId ) ) continue; - // Skip pad annulus when not connected on this layer (if removing is enabled) - if( !pad->FlashLayer( aLayerId ) && IsCopperLayer( aLayerId ) ) - continue; - - // NPTH pads are not drawn on layers if the shape size and pos is the same as their hole: - if( aSkipNPTHPadsWihNoCopper && ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) ) + if( IsCopperLayer( aLayerId ) ) { - if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == VECTOR2I( 0, 0 ) ) - { - switch( pad->GetShape() ) - { - case PAD_SHAPE::CIRCLE: - if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ) - continue; + // Skip pad annulus when there isn't one (note: this is more discerning than + // pad->IsOnLayer(), which doesn't check for NPTH pads with holes that consume + // the entire pad). + if( !pad->IsOnCopperLayer() ) + continue; - break; - - case PAD_SHAPE::OVAL: - if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE ) - continue; - - break; - - default: - break; - } - } + // Skip pad annulus when not connected on this layer (if removing is enabled) + if( !pad->FlashLayer( aLayerId ) ) + continue; } VECTOR2I margin( 0, 0 ); diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp index 9c4472ad4b..9dae96d744 100644 --- a/3d-viewer/3d_canvas/create_layer_items.cpp +++ b/3d-viewer/3d_canvas/create_layer_items.cpp @@ -525,9 +525,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) // ADD PADS for( FOOTPRINT* footprint : m_board->Footprints() ) { - // Note: NPTH pads are not drawn on copper layers when the pad has the same shape - // as its hole - addPads( footprint, layerContainer, layer, true, renderPlatedPadsAsPlated, false ); + addPads( footprint, layerContainer, layer, renderPlatedPadsAsPlated, false ); // Micro-wave footprints may have items on copper layers addFootprintShapes( footprint, layerContainer, layer ); @@ -539,8 +537,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) // ADD PLATED PADS for( FOOTPRINT* footprint : m_board->Footprints() ) { - addPads( footprint, m_platedPadsFront, F_Cu, true, false, true ); - addPads( footprint, m_platedPadsBack, B_Cu, true, false, true ); + addPads( footprint, m_platedPadsFront, F_Cu, false, true ); + addPads( footprint, m_platedPadsBack, B_Cu, false, true ); } m_platedPadsFront->BuildBVH(); @@ -995,7 +993,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) } else { - addPads( footprint, layerContainer, layer, false, false, false ); + addPads( footprint, layerContainer, layer, false, false ); } addFootprintShapes( footprint, layerContainer, layer ); diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index 907cee5cf0..147a4b5724 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -766,6 +766,38 @@ VECTOR2I PAD::ShapePos() const } +bool PAD::IsOnCopperLayer() const +{ + if( GetAttribute() == PAD_ATTRIB::NPTH ) + { + // NPTH pads have no plated hole cylinder. If their annular ring size is 0 or + // negative, then they have no annular ring either. + + switch( GetShape() ) + { + case PAD_SHAPE::CIRCLE: + if( m_offset == VECTOR2I( 0, 0 ) && m_size.x <= m_drill.x ) + return false; + + break; + + case PAD_SHAPE::OVAL: + if( m_offset == VECTOR2I( 0, 0 ) && m_size.x <= m_drill.x && m_size.y <= m_drill.y ) + return false; + + break; + + default: + // We could subtract the hole polygon from the shape polygon for these, but it + // would be expensive and we're probably well out of the common use cases.... + break; + } + } + + return ( GetLayerSet() & LSET::AllCuMask() ).any(); +} + + int PAD::GetLocalClearanceOverrides( wxString* aSource ) const { // A pad can have specific clearance that overrides its NETCLASS clearance value @@ -817,13 +849,9 @@ int PAD::GetOwnClearance( PCB_LAYER_ID aLayer, wxString* aSource ) const int PAD::GetSolderMaskExpansion() const { - // The pad inherits the margin only to calculate a default shape, - // therefore only if it is also a copper layer // Pads defined only on mask layers (and perhaps on other tech layers) use the shape // defined by the pad settings only - bool isOnCopperLayer = ( m_layerMask & LSET::AllCuMask() ).any(); - - if( !isOnCopperLayer ) + if( !IsOnCopperLayer() ) return 0; int margin = m_localSolderMaskMargin; @@ -862,13 +890,9 @@ int PAD::GetSolderMaskExpansion() const VECTOR2I PAD::GetSolderPasteMargin() const { - // The pad inherits the margin only to calculate a default shape, - // therefore only if it is also a copper layer. // Pads defined only on mask layers (and perhaps on other tech layers) use the shape // defined by the pad settings only - bool isOnCopperLayer = ( m_layerMask & LSET::AllCuMask() ).any(); - - if( !isOnCopperLayer ) + if( !IsOnCopperLayer() ) return VECTOR2I( 0, 0 ); int margin = m_localSolderPasteMargin; diff --git a/pcbnew/pad.h b/pcbnew/pad.h index 1c829b53db..0eea504930 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -239,10 +239,7 @@ public: /** * @return true if the pad is on any copper layer, false otherwise. */ - bool IsOnCopperLayer() const override - { - return ( GetLayerSet() & LSET::AllCuMask() ) != 0; - } + bool IsOnCopperLayer() const override; void SetY( int y ) { m_pos.y = y; SetDirty(); } void SetX( int x ) { m_pos.x = x; SetDirty(); } diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index c643e471e5..b20ddaef93 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -310,6 +310,9 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, } } + if( onCopperLayer && !pad->IsOnCopperLayer() ) + continue; + /// pads not connected to copper are optionally not drawn if( onCopperLayer && !pad->FlashLayer( aLayerMask ) ) continue; diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 1725f32afc..9fe425dbde 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -726,9 +726,7 @@ void BRDITEMS_PLOTTER::PlotFilledAreas( const ZONE* aZone, PCB_LAYER_ID aLayer, GBR_METADATA gbr_metadata; - bool isOnCopperLayer = aZone->IsOnCopperLayer(); - - if( isOnCopperLayer ) + if( aZone->IsOnCopperLayer() ) { gbr_metadata.SetNetName( aZone->GetNetname() ); gbr_metadata.SetCopper( true ); diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index b582c0d41d..a60c02adba 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -254,31 +254,9 @@ bool PNS_PCBNEW_RULE_RESOLVER::IsNetTieExclusion( const PNS::ITEM* aItem, bool isCopper( const PNS::ITEM* aItem ) { - BOARD_ITEM* parent = aItem->Parent(); + const BOARD_ITEM *parent = aItem->Parent(); - if( parent && parent->Type() == PCB_PAD_T ) - { - PAD* pad = static_cast( parent ); - - if( !pad->IsOnCopperLayer() ) - return false; - - if( pad->GetAttribute() != PAD_ATTRIB::NPTH ) - return true; - - // round NPTH with a hole size >= pad size are not on a copper layer - // All other NPTH are seen on copper layers - // This is a basic criteria, but probably enough for a NPTH - if( pad->GetShape() == PAD_SHAPE::CIRCLE ) - { - if( pad->GetSize().x <= pad->GetDrillSize().x ) - return false; - } - - return true; - } - - return true; + return !parent || parent->IsOnCopperLayer(); }