diff --git a/include/board_item.h b/include/board_item.h index 85846e089e..79ec45af8e 100644 --- a/include/board_item.h +++ b/include/board_item.h @@ -117,6 +117,11 @@ public: return IsCopperLayer( GetLayer() ); } + virtual bool HasHole() const + { + return false; + } + virtual bool IsTented() const { return false; diff --git a/pcbnew/drc/drc_cache_generator.cpp b/pcbnew/drc/drc_cache_generator.cpp index 427dd86783..e76feaaebb 100644 --- a/pcbnew/drc/drc_cache_generator.cpp +++ b/pcbnew/drc/drc_cache_generator.cpp @@ -116,7 +116,7 @@ bool DRC_CACHE_GENERATOR::Run() { PAD* pad = static_cast( item ); - if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) + if( pad->HasHole() ) layers |= LSET::AllCuMask(); } diff --git a/pcbnew/drc/drc_rtree.h b/pcbnew/drc/drc_rtree.h index 3e6e9a0f24..cb6f721eef 100644 --- a/pcbnew/drc/drc_rtree.h +++ b/pcbnew/drc/drc_rtree.h @@ -121,7 +121,7 @@ public: { PAD* pad = static_cast( aItem ); - if( pad->GetDrillSizeX() ) + if( pad->HasHole() ) { const SHAPE* hole = pad->GetEffectiveHoleShape(); subshapes.push_back( const_cast( hole ) ); diff --git a/pcbnew/drc/drc_test_provider.cpp b/pcbnew/drc/drc_test_provider.cpp index ba0697a099..0aa9b9b147 100644 --- a/pcbnew/drc/drc_test_provider.cpp +++ b/pcbnew/drc/drc_test_provider.cpp @@ -276,8 +276,7 @@ int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector& aTypes, for( PAD* pad : footprint->Pads() ) { // Careful: if a pad has a hole then it pierces all layers - if( ( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) - || ( pad->GetLayerSet() & aLayers ).any() ) + if( pad->HasHole() || ( pad->GetLayerSet() & aLayers ).any() ) { if( !aFunc( pad ) ) return n; diff --git a/pcbnew/drc/drc_test_provider_disallow.cpp b/pcbnew/drc/drc_test_provider_disallow.cpp index 58e35bfea0..8db6f7f16b 100644 --- a/pcbnew/drc/drc_test_provider_disallow.cpp +++ b/pcbnew/drc/drc_test_provider_disallow.cpp @@ -244,7 +244,6 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run() if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ALLOWED_ITEMS ) ) { ZONE* zone = dynamic_cast( item ); - PAD* pad = dynamic_cast( item ); if( zone && zone->GetIsRuleArea() ) return true; @@ -253,22 +252,10 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run() checkDisallow( item ); - bool hasHole; - - switch( item->Type() ) - { - case PCB_VIA_T: hasHole = true; break; - case PCB_PAD_T: hasHole = pad && pad->GetDrillSizeX() > 0; break; - default: hasHole = false; break; - } - - if( hasHole ) + if( item->HasHole() ) { item->SetFlags( HOLE_PROXY ); - { - checkDisallow( item ); - } - + checkDisallow( item ); item->ClearFlags( HOLE_PROXY ); } } diff --git a/pcbnew/drc/drc_test_provider_physical_clearance.cpp b/pcbnew/drc/drc_test_provider_physical_clearance.cpp index d6c33de647..95de339fc9 100644 --- a/pcbnew/drc/drc_test_provider_physical_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_physical_clearance.cpp @@ -136,19 +136,9 @@ bool DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::Run() LSET layers = item->GetLayerSet(); // Special-case holes and edge-cuts which pierce all physical layers - if( item->Type() == PCB_PAD_T ) + if( item->HasHole() ) { - PAD* pad = static_cast( item ); - - if( pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) - layers |= LSET::PhysicalLayersMask() | courtyards; - } - else if( item->Type() == PCB_VIA_T ) - { - PCB_VIA* via = static_cast( item ); - - if( via->GetDrill() > 0 ) - layers |= LSET::PhysicalLayersMask() | courtyards; + layers |= LSET::PhysicalLayersMask() | courtyards; } else if( item->Type() == PCB_FOOTPRINT_T ) { diff --git a/pcbnew/pad.h b/pcbnew/pad.h index 63c98ea5d8..621376188a 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -103,6 +103,11 @@ public: return false; } + bool HasHole() const override + { + return GetDrillSizeX() > 0 && GetDrillSizeY() > 0; + } + FOOTPRINT* GetParent() const; wxString GetParentAsString() const { return m_parent->m_Uuid.AsString(); } diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index 724603bd9c..7d176adfec 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -353,6 +353,11 @@ public: VIATYPE GetViaType() const { return m_viaType; } void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; } + bool HasHole() const override + { + return true; + } + bool IsTented() const override; int GetSolderMaskExpansion() const; diff --git a/pcbnew/plugins/altium/altium_pcb.cpp b/pcbnew/plugins/altium/altium_pcb.cpp index 3e2a16c34f..23cb906311 100644 --- a/pcbnew/plugins/altium/altium_pcb.cpp +++ b/pcbnew/plugins/altium/altium_pcb.cpp @@ -2546,7 +2546,7 @@ void ALTIUM_PCB::ConvertPads6ToFootprintItemOnCopper( FOOTPRINT* aFootprint, con break; } - if( pad->GetAttribute() == PAD_ATTRIB::NPTH && pad->GetDrillSizeX() ) + if( pad->GetAttribute() == PAD_ATTRIB::NPTH && pad->HasHole() ) { // KiCad likes NPTH pads to be the same size & shape as their holes pad->SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ? PAD_SHAPE::CIRCLE diff --git a/pcbnew/teardrop/teardrop_utils.cpp b/pcbnew/teardrop/teardrop_utils.cpp index fa14bdc71d..b36a48cb73 100644 --- a/pcbnew/teardrop/teardrop_utils.cpp +++ b/pcbnew/teardrop/teardrop_utils.cpp @@ -138,12 +138,10 @@ void TEARDROP_MANAGER::collectPadsCandidate( std::vector< VIAPAD >& aList, continue; } - bool has_hole = pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0; - - if( has_hole && !aDrilledViaPad ) + if( pad->HasHole() && !aDrilledViaPad ) continue; - if( has_hole || aIncludeNotDrilled ) + if( pad->HasHole() || aIncludeNotDrilled ) aList.emplace_back( pad ); } } diff --git a/pcbnew/tools/board_inspection_tool.cpp b/pcbnew/tools/board_inspection_tool.cpp index 696938684e..22aa5edd37 100644 --- a/pcbnew/tools/board_inspection_tool.cpp +++ b/pcbnew/tools/board_inspection_tool.cpp @@ -504,22 +504,6 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr& aDR } -bool hasHole( BOARD_ITEM* aItem ) -{ - PAD* pad = dynamic_cast( aItem ); - - if( pad && pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) - return true; - - PCB_VIA* via = dynamic_cast( aItem ); - - if( via ) - return true; - - return false; -}; - - int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent ) { PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool(); @@ -878,17 +862,17 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent ) } } - if( hasHole( a ) || hasHole( b ) ) + if( a->HasHole() || b->HasHole() ) { PCB_LAYER_ID layer = UNDEFINED_LAYER; - if( hasHole( a ) && b->IsOnLayer( active ) && IsCopperLayer( active ) ) + if( a->HasHole() && b->IsOnLayer( active ) && IsCopperLayer( active ) ) layer = active; - else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) ) + else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) ) layer = active; - else if( hasHole( a ) && b->IsOnCopperLayer() ) + else if( a->HasHole() && b->IsOnCopperLayer() ) layer = b->GetLayer(); - else if( hasHole( b ) && b->IsOnCopperLayer() ) + else if( b->HasHole() && b->IsOnCopperLayer() ) layer = a->GetLayer(); if( layer >= 0 ) @@ -1007,15 +991,15 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent ) reportPhysicalClearance( B_CrtYd ); } - if( hasHole( a ) || hasHole( b ) ) + if( a->HasHole() || b->HasHole() ) { PCB_LAYER_ID layer; - if( hasHole( a ) && b->IsOnLayer( active ) ) + if( a->HasHole() && b->IsOnLayer( active ) ) layer = active; - else if( hasHole( b ) && a->IsOnLayer( active ) ) + else if( b->HasHole() && a->IsOnLayer( active ) ) layer = active; - else if( hasHole( a ) ) + else if( a->HasHole() ) layer = b->GetLayer(); else layer = a->GetLayer(); diff --git a/pcbnew/tools/board_inspection_tool.h b/pcbnew/tools/board_inspection_tool.h index e52497799c..51a58bdb14 100644 --- a/pcbnew/tools/board_inspection_tool.h +++ b/pcbnew/tools/board_inspection_tool.h @@ -106,6 +106,8 @@ public: return !m_currentlyHighlighted.empty(); } + static bool HasHole( BOARD_ITEM* aItem ); + private: ///< Recalculate dynamic ratsnest for the current selection. void calculateSelectionRatsnest( const VECTOR2I& aDelta ); diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 0e636ed076..b5a53b5c64 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -1190,11 +1191,13 @@ int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent ) int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) { - PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool(); - ROUTER_TOOL* routerTool = m_toolMgr->GetTool(); - PCB_SELECTION& selection = selTool->GetSelection(); - FOOTPRINT_EDIT_FRAME* fpFrame = dynamic_cast( m_frame ); - PCB_EDIT_FRAME* pcbFrame = dynamic_cast( m_frame ); + PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool(); + ROUTER_TOOL* routerTool = m_toolMgr->GetTool(); + PCB_SELECTION& selection = selTool->GetSelection(); + FOOTPRINT_EDIT_FRAME* fpFrame = dynamic_cast( m_frame ); + PCB_EDIT_FRAME* pcbFrame = dynamic_cast( m_frame ); + std::shared_ptr drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine; + DRC_CONSTRAINT constraint; EDA_UNITS units = m_frame->GetUserUnits(); std::vector msgItems; @@ -1214,7 +1217,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) if( !footprint ) return 0; - wxString msg; + wxString msg; msg = footprint->GetFPID().GetLibNickname().wx_str(); msgItems.emplace_back( MSG_PANEL_ITEM( _( "Library" ), msg ) ); @@ -1244,90 +1247,105 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) } // Pair selection broken into multiple, optional data, starting with the selection item names - if( selection.GetSize() == 2 ) + if( pcbFrame && selection.GetSize() == 2 ) { + auto clearanceString = + [&]( const DRC_CONSTRAINT& constraint ) + { + return StringFromValue( units, constraint.m_Value.Min(), true ); + }; + BOARD_ITEM* a = static_cast( selection[0] ); BOARD_ITEM* b = static_cast( selection[1] ); msgItems.emplace_back( MSG_PANEL_ITEM( a->GetSelectMenuText( units ), b->GetSelectMenuText( units ) ) ); - } - if( BOARD_CONNECTED_ITEM *a, *b; - selection.GetSize() == 2 && pcbFrame && - ( a = dyn_cast( selection[0] ) ) && - ( b = dyn_cast( selection[1] ) ) ) - { - LSET overlap = a->GetLayerSet() & b->GetLayerSet() & LSET::AllCuMask(); + BOARD_CONNECTED_ITEM* a_conn = dyn_cast( a ); + BOARD_CONNECTED_ITEM* b_conn = dyn_cast( b ); - BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); - - if( overlap.count() > 0 - && ( a->GetNetCode() != b->GetNetCode() - || a->GetNetCode() < 0 - || b->GetNetCode() < 0 ) ) + if( a_conn && b_conn ) { - PCB_LAYER_ID layer = overlap.CuStack().front(); - auto aShape = a->GetEffectiveShape( layer ); - auto bShape = b->GetEffectiveShape( layer ); + LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask(); + int a_netcode = a_conn->GetNetCode(); + int b_netcode = b_conn->GetNetCode(); - DRC_CONSTRAINT constraint; - int clearance = 0; + if( overlap.count() > 0 + && ( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 ) ) + { + constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, + overlap.CuStack().front() ); - constraint = bds.m_DRCEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer ); - clearance = constraint.m_Value.Min(); - msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ), - StringFromValue( units, clearance, true ) ) ); + msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ), + clearanceString( constraint ) ) ); + } } - } - - auto hasHole = []( EDA_ITEM* aItem ) -> bool - { - PAD* pad = dyn_cast( aItem ); - - if( pad && pad->GetDrillSizeX() > 0 && pad->GetDrillSizeY() > 0 ) - return true; - - return !!dyn_cast( aItem ); - }; - - if( selection.GetSize() == 2 && pcbFrame && - ( hasHole( selection[0] ) || hasHole( selection[1] ) ) ) - { - PCB_LAYER_ID active = m_frame->GetActiveLayer(); - PCB_LAYER_ID layer = UNDEFINED_LAYER; - - BOARD_ITEM* a = static_cast( selection[0] ); - BOARD_ITEM* b = static_cast( selection[1] ); - - if( b->IsOnLayer( active ) && IsCopperLayer( active ) ) - layer = active; - else if( hasHole( b ) && a->IsOnLayer( active ) && IsCopperLayer( active ) ) - layer = active; - else if( hasHole( a ) && b->IsOnCopperLayer() ) - layer = b->GetLayer(); - else if( hasHole( b ) && b->IsOnCopperLayer() ) - layer = a->GetLayer(); - - if( layer >= 0 ) + if( a->HasHole() || b->HasHole() ) { + PCB_LAYER_ID active = m_frame->GetActiveLayer(); + PCB_LAYER_ID layer = UNDEFINED_LAYER; - BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); - DRC_CONSTRAINT constraint; - int clearance = 0; + if( b->IsOnLayer( active ) && IsCopperLayer( active ) ) + layer = active; + else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) ) + layer = active; + else if( a->HasHole() && b->IsOnCopperLayer() ) + layer = b->GetLayer(); + else if( b->HasHole() && b->IsOnCopperLayer() ) + layer = a->GetLayer(); - constraint = bds.m_DRCEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer ); - clearance = constraint.m_Value.Min(); - msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved hole clearance" ), - StringFromValue( units, clearance, true ) ) ); + if( layer >= 0 ) + { + constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer ); + msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved hole clearance" ), + clearanceString( constraint ) ) ); + } + } + + for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } ) + { + PCB_LAYER_ID active = m_frame->GetActiveLayer(); + PCB_LAYER_ID layer = UNDEFINED_LAYER; + + if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T ) + { + if( b->IsOnLayer( active ) && IsCopperLayer( active ) ) + layer = active; + else if( IsCopperLayer( b->GetLayer() ) ) + layer = b->GetLayer(); + } + else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T ) + { + if( a->IsOnLayer( active ) && IsCopperLayer( active ) ) + layer = active; + else if( IsCopperLayer( a->GetLayer() ) ) + layer = a->GetLayer(); + } + + if( layer >= 0 ) + { + constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer ); + + if( edgeLayer == Edge_Cuts ) + { + msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved edge clearance" ), + clearanceString( constraint ) ) ); + } + else + { + msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved margin clearance" ), + clearanceString( constraint ) ) ); + } + } } } if( msgItems.empty() ) - msgItems.emplace_back( - MSG_PANEL_ITEM( _( "Selected Items" ), - wxString::Format( wxT( "%d" ), selection.GetSize() ) ) ); + { + wxString msg = wxString::Format( wxT( "%d" ), selection.GetSize() ); + msgItems.emplace_back( MSG_PANEL_ITEM( _( "Selected Items" ), msg ) ); + } m_frame->SetMsgPanel( msgItems );