diff --git a/include/board_item.h b/include/board_item.h index deb8316bb7..f2aa1517fd 100644 --- a/include/board_item.h +++ b/include/board_item.h @@ -158,6 +158,11 @@ public: return false; } + virtual bool HasDrilledHole() const + { + return false; + } + virtual bool IsTented() const { return false; diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index eb4269fb48..67becef3fc 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -160,6 +160,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std: m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR; m_DRCSeverities[ DRCE_DRILLED_HOLES_COLOCATED ] = RPT_SEVERITY_WARNING; + m_DRCSeverities[ DRCE_DRILLED_HOLES_TOO_CLOSE ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE; m_DRCSeverities[ DRCE_PTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE; diff --git a/pcbnew/dialogs/dialog_footprint_checker.cpp b/pcbnew/dialogs/dialog_footprint_checker.cpp index 3c1108ed8f..a8fa3d6227 100644 --- a/pcbnew/dialogs/dialog_footprint_checker.cpp +++ b/pcbnew/dialogs/dialog_footprint_checker.cpp @@ -158,10 +158,9 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks() } ); footprint->CheckShortingPads( - [&]( const PAD* aPadA, const PAD* aPadB, const VECTOR2I& aPosition ) + [&]( const PAD* aPadA, const PAD* aPadB, int aErrorCode, const VECTOR2I& aPosition ) { - errorHandler( aPadA, aPadB, nullptr, DRCE_SHORTING_ITEMS, wxEmptyString, - aPosition ); + errorHandler( aPadA, aPadB, nullptr, aErrorCode, wxEmptyString, aPosition ); } ); if( footprint->IsNetTie() ) diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index 4d8904ed16..6ac88a3782 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -649,29 +649,6 @@ DRC_CONSTRAINT DRC_ENGINE::EvalZoneConnection( const BOARD_ITEM* a, const BOARD_ } -bool hasDrilledHole( const BOARD_ITEM* aItem ) -{ - if( !aItem->HasHole() ) - return false; - - switch( aItem->Type() ) - { - case PCB_VIA_T: - return true; - - case PCB_PAD_T: - { - const PAD* pad = static_cast( aItem ); - - return pad->GetDrillSizeX() == pad->GetDrillSizeY(); - } - - default: - return false; - } -} - - DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM* a, const BOARD_ITEM* b, PCB_LAYER_ID aLayer, REPORTER* aReporter ) @@ -1212,12 +1189,12 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO } } else if( c->constraint.m_Type == HOLE_TO_HOLE_CONSTRAINT - && ( !hasDrilledHole( a ) || !hasDrilledHole( b ) ) ) + && ( !a->HasDrilledHole() || !b->HasDrilledHole() ) ) { // Report non-drilled-holes as an implicit condition if( aReporter ) { - const BOARD_ITEM* x = !hasDrilledHole( a ) ? a : b; + const BOARD_ITEM* x = !a->HasDrilledHole() ? a : b; REPORT( wxString::Format( _( "%s is not a drilled hole; rule ignored." ), x->GetItemDescription( this ) ) ) diff --git a/pcbnew/drc/drc_test_provider_hole_to_hole.cpp b/pcbnew/drc/drc_test_provider_hole_to_hole.cpp index 65343c6bcb..796b4ea365 100644 --- a/pcbnew/drc/drc_test_provider_hole_to_hole.cpp +++ b/pcbnew/drc/drc_test_provider_hole_to_hole.cpp @@ -78,15 +78,18 @@ private: static std::shared_ptr getDrilledHoleShape( BOARD_ITEM* aItem ) { - if( aItem->Type() == PCB_VIA_T ) + if( aItem->HasDrilledHole() ) { - PCB_VIA* via = static_cast( aItem ); - return std::make_shared( via->GetCenter(), via->GetDrillValue() / 2 ); - } - else if( aItem->Type() == PCB_PAD_T ) - { - PAD* pad = static_cast( aItem ); - return std::make_shared( pad->GetPosition(), pad->GetDrillSize().x / 2 ); + if( aItem->Type() == PCB_VIA_T ) + { + PCB_VIA* via = static_cast( aItem ); + return std::make_shared( via->GetCenter(), via->GetDrillValue() / 2 ); + } + else if( aItem->Type() == PCB_PAD_T ) + { + PAD* pad = static_cast( aItem ); + return std::make_shared( pad->GetPosition(), pad->GetDrillSize().x / 2 ); + } } return std::make_shared( VECTOR2I( 0, 0 ), 0 ); @@ -219,7 +222,7 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::Run() return false; // DRC cancelled // We only care about drilled (ie: round) holes - if( pad->GetDrillSize().x && pad->GetDrillSize().x == pad->GetDrillSize().y ) + if( pad->HasDrilledHole() ) { std::shared_ptr holeShape = getDrilledHoleShape( pad ); diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp index 8f93db8ead..6e297e6b58 100644 --- a/pcbnew/footprint.cpp +++ b/pcbnew/footprint.cpp @@ -3110,6 +3110,7 @@ void FOOTPRINT::CheckPads( const std::function& aErrorHandler ) { std::unordered_map checkedPairs; @@ -3120,13 +3121,7 @@ void FOOTPRINT::CheckShortingPads( const std::functionSameLogicalPadAs( other ) ) - continue; - - if( alg::contains( netTiePads, other ) ) - continue; - - if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() ) + if( other == pad ) continue; // store canonical order so we don't collide in both directions (a:b and b:a) @@ -3140,6 +3135,30 @@ void FOOTPRINT::CheckShortingPads( const std::functionHasDrilledHole() && other->HasDrilledHole() ) + { + VECTOR2I pos = pad->GetPosition(); + + if( pad->GetPosition() == other->GetPosition() ) + { + aErrorHandler( pad, other, DRCE_DRILLED_HOLES_COLOCATED, pos ); + } + else + { + std::shared_ptr holeA = pad->GetEffectiveHoleShape(); + std::shared_ptr holeB = other->GetEffectiveHoleShape(); + + if( holeA->Collide( holeB->GetSeg(), 0 ) ) + aErrorHandler( pad, other, DRCE_DRILLED_HOLES_TOO_CLOSE, pos ); + } + } + + if( pad->SameLogicalPadAs( other ) || alg::contains( netTiePads, other ) ) + continue; + + if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() ) + continue; + if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) ) { VECTOR2I pos; @@ -3147,7 +3166,7 @@ void FOOTPRINT::CheckShortingPads( const std::functionGetEffectiveShape().get(); if( padShape->Collide( otherShape, 0, nullptr, &pos ) ) - aErrorHandler( pad, other, pos ); + aErrorHandler( pad, other, DRCE_SHORTING_ITEMS, pos ); } } } diff --git a/pcbnew/footprint.h b/pcbnew/footprint.h index 3f1336e4d4..8277f6fc86 100644 --- a/pcbnew/footprint.h +++ b/pcbnew/footprint.h @@ -461,8 +461,7 @@ public: * * @param aErrorHandler callback to handle the error messages generated */ - void CheckShortingPads( const std::function& aErrorHandler ); /** diff --git a/pcbnew/pad.h b/pcbnew/pad.h index cceefc0157..8dab9fb8f9 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -105,6 +105,11 @@ public: return GetDrillSizeX() > 0 && GetDrillSizeY() > 0; } + bool HasDrilledHole() const override + { + return HasHole() && GetDrillSizeX() == GetDrillSizeY(); + } + bool IsLocked() const override; /** diff --git a/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp b/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp index 51fb860416..cb334db0c4 100644 --- a/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp +++ b/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp @@ -1563,10 +1563,10 @@ void PCB_IO_IPC2581::generateDrillLayers( wxXmlNode* aCadLayerNode ) { for( PAD* pad : fp->Pads() ) { - if( pad->HasHole() && pad->GetDrillSizeX() != pad->GetDrillSizeY() ) - m_slot_holes[std::make_pair( F_Cu, B_Cu )].push_back( pad ); - else if( pad->HasHole() ) + if( pad->HasDrilledHole() ) m_drill_layers[std::make_pair( F_Cu, B_Cu )].push_back( pad ); + else if( pad->HasHole() ) + m_slot_holes[std::make_pair( F_Cu, B_Cu )].push_back( pad ); } } @@ -1703,7 +1703,7 @@ void PCB_IO_IPC2581::addPadStack( wxXmlNode* aPadNode, const PAD* aPad ) // Only handle round holes here because IPC2581 does not support non-round holes // These will be handled in a slot layer - if( aPad->HasHole() && aPad->GetDrillSizeX() == aPad->GetDrillSizeY() ) + if( aPad->HasDrilledHole() ) { wxXmlNode* padStackHoleNode = appendNode( padStackDefNode, "PadstackHoleDef" ); padStackHoleNode->AddAttribute( "name", wxString::Format( "%s%d_%d", diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index cab54ab528..15bcf3aa3d 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -420,6 +420,11 @@ public: return true; } + bool HasDrilledHole() const override + { + return m_viaType == VIATYPE::THROUGH; + } + std::shared_ptr GetEffectiveHoleShape() const override; MINOPTMAX GetWidthConstraint( wxString* aSource = nullptr ) const override; diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 3523e4ee2b..b1b069111a 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -298,15 +298,13 @@ static bool isEdge( const PNS::ITEM* aItem ) bool PNS_PCBNEW_RULE_RESOLVER::IsDrilledHole( const PNS::ITEM* aItem ) { - if( !isHole( aItem ) ) - return false; + if( isHole( aItem ) ) + { + if( BOARD_ITEM* item = dynamic_cast( aItem->Parent() ) ) + return item->HasDrilledHole(); + } - if( PAD* pad = dynamic_cast( aItem->Parent() ) ) - return pad->GetDrillSizeX() && pad->GetDrillSizeX() == pad->GetDrillSizeY(); - - // Via holes are (currently) always round - - return true; + return false; } diff --git a/pcbnew/tools/board_inspection_tool.cpp b/pcbnew/tools/board_inspection_tool.cpp index 78a70a7e0f..424322a686 100644 --- a/pcbnew/tools/board_inspection_tool.cpp +++ b/pcbnew/tools/board_inspection_tool.cpp @@ -1112,7 +1112,7 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent ) r->Flush(); } - if( a->HasHole() && b->HasHole() ) + if( a->HasDrilledHole() && b->HasDrilledHole() ) { if( !pageAdded ) {