Check for drilled hole errors in Footprint Checker.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18093
This commit is contained in:
Jeff Young 2024-05-27 13:51:02 +01:00
parent 2925d63c44
commit bc14a841cb
12 changed files with 71 additions and 60 deletions

View File

@ -158,6 +158,11 @@ public:
return false; return false;
} }
virtual bool HasDrilledHole() const
{
return false;
}
virtual bool IsTented() const virtual bool IsTented() const
{ {
return false; return false;

View File

@ -160,6 +160,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR; m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
m_DRCSeverities[ DRCE_DRILLED_HOLES_COLOCATED ] = RPT_SEVERITY_WARNING; 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_MISSING_COURTYARD ] = RPT_SEVERITY_IGNORE;
m_DRCSeverities[ DRCE_PTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE; m_DRCSeverities[ DRCE_PTH_IN_COURTYARD ] = RPT_SEVERITY_IGNORE;

View File

@ -158,10 +158,9 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks()
} ); } );
footprint->CheckShortingPads( 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, errorHandler( aPadA, aPadB, nullptr, aErrorCode, wxEmptyString, aPosition );
aPosition );
} ); } );
if( footprint->IsNetTie() ) if( footprint->IsNetTie() )

View File

@ -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<const PAD*>( aItem );
return pad->GetDrillSizeX() == pad->GetDrillSizeY();
}
default:
return false;
}
}
DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM* a, DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM* a,
const BOARD_ITEM* b, PCB_LAYER_ID aLayer, const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
REPORTER* aReporter ) 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 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 // Report non-drilled-holes as an implicit condition
if( aReporter ) 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." ), REPORT( wxString::Format( _( "%s is not a drilled hole; rule ignored." ),
x->GetItemDescription( this ) ) ) x->GetItemDescription( this ) ) )

View File

@ -78,15 +78,18 @@ private:
static std::shared_ptr<SHAPE_CIRCLE> getDrilledHoleShape( BOARD_ITEM* aItem ) static std::shared_ptr<SHAPE_CIRCLE> getDrilledHoleShape( BOARD_ITEM* aItem )
{ {
if( aItem->Type() == PCB_VIA_T ) if( aItem->HasDrilledHole() )
{ {
PCB_VIA* via = static_cast<PCB_VIA*>( aItem ); if( aItem->Type() == PCB_VIA_T )
return std::make_shared<SHAPE_CIRCLE>( via->GetCenter(), via->GetDrillValue() / 2 ); {
} PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
else if( aItem->Type() == PCB_PAD_T ) return std::make_shared<SHAPE_CIRCLE>( via->GetCenter(), via->GetDrillValue() / 2 );
{ }
PAD* pad = static_cast<PAD*>( aItem ); else if( aItem->Type() == PCB_PAD_T )
return std::make_shared<SHAPE_CIRCLE>( pad->GetPosition(), pad->GetDrillSize().x / 2 ); {
PAD* pad = static_cast<PAD*>( aItem );
return std::make_shared<SHAPE_CIRCLE>( pad->GetPosition(), pad->GetDrillSize().x / 2 );
}
} }
return std::make_shared<SHAPE_CIRCLE>( VECTOR2I( 0, 0 ), 0 ); return std::make_shared<SHAPE_CIRCLE>( VECTOR2I( 0, 0 ), 0 );
@ -219,7 +222,7 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::Run()
return false; // DRC cancelled return false; // DRC cancelled
// We only care about drilled (ie: round) holes // We only care about drilled (ie: round) holes
if( pad->GetDrillSize().x && pad->GetDrillSize().x == pad->GetDrillSize().y ) if( pad->HasDrilledHole() )
{ {
std::shared_ptr<SHAPE_CIRCLE> holeShape = getDrilledHoleShape( pad ); std::shared_ptr<SHAPE_CIRCLE> holeShape = getDrilledHoleShape( pad );

View File

@ -3110,6 +3110,7 @@ void FOOTPRINT::CheckPads( const std::function<void( const PAD*, int,
void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const PAD*, void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const PAD*,
int aErrorCode,
const VECTOR2I& )>& aErrorHandler ) const VECTOR2I& )>& aErrorHandler )
{ {
std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs; std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
@ -3120,13 +3121,7 @@ void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const P
for( PAD* other : Pads() ) for( PAD* other : Pads() )
{ {
if( other == pad || pad->SameLogicalPadAs( other ) ) if( other == pad )
continue;
if( alg::contains( netTiePads, other ) )
continue;
if( !( ( pad->GetLayerSet() & other->GetLayerSet() ) & LSET::AllCuMask() ).any() )
continue; continue;
// store canonical order so we don't collide in both directions (a:b and b:a) // 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::function<void( const PAD*, const P
{ {
checkedPairs[ { a, b } ] = 1; checkedPairs[ { a, b } ] = 1;
if( pad->HasDrilledHole() && other->HasDrilledHole() )
{
VECTOR2I pos = pad->GetPosition();
if( pad->GetPosition() == other->GetPosition() )
{
aErrorHandler( pad, other, DRCE_DRILLED_HOLES_COLOCATED, pos );
}
else
{
std::shared_ptr<SHAPE_SEGMENT> holeA = pad->GetEffectiveHoleShape();
std::shared_ptr<SHAPE_SEGMENT> 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() ) ) if( pad->GetBoundingBox().Intersects( other->GetBoundingBox() ) )
{ {
VECTOR2I pos; VECTOR2I pos;
@ -3147,7 +3166,7 @@ void FOOTPRINT::CheckShortingPads( const std::function<void( const PAD*, const P
SHAPE* otherShape = other->GetEffectiveShape().get(); SHAPE* otherShape = other->GetEffectiveShape().get();
if( padShape->Collide( otherShape, 0, nullptr, &pos ) ) if( padShape->Collide( otherShape, 0, nullptr, &pos ) )
aErrorHandler( pad, other, pos ); aErrorHandler( pad, other, DRCE_SHORTING_ITEMS, pos );
} }
} }
} }

View File

@ -461,8 +461,7 @@ public:
* *
* @param aErrorHandler callback to handle the error messages generated * @param aErrorHandler callback to handle the error messages generated
*/ */
void CheckShortingPads( const std::function<void( const PAD*, void CheckShortingPads( const std::function<void( const PAD*, const PAD*, int aErrorCode,
const PAD*,
const VECTOR2I& )>& aErrorHandler ); const VECTOR2I& )>& aErrorHandler );
/** /**

View File

@ -105,6 +105,11 @@ public:
return GetDrillSizeX() > 0 && GetDrillSizeY() > 0; return GetDrillSizeX() > 0 && GetDrillSizeY() > 0;
} }
bool HasDrilledHole() const override
{
return HasHole() && GetDrillSizeX() == GetDrillSizeY();
}
bool IsLocked() const override; bool IsLocked() const override;
/** /**

View File

@ -1563,10 +1563,10 @@ void PCB_IO_IPC2581::generateDrillLayers( wxXmlNode* aCadLayerNode )
{ {
for( PAD* pad : fp->Pads() ) for( PAD* pad : fp->Pads() )
{ {
if( pad->HasHole() && pad->GetDrillSizeX() != pad->GetDrillSizeY() ) if( pad->HasDrilledHole() )
m_slot_holes[std::make_pair( F_Cu, B_Cu )].push_back( pad );
else if( pad->HasHole() )
m_drill_layers[std::make_pair( F_Cu, B_Cu )].push_back( pad ); 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 // Only handle round holes here because IPC2581 does not support non-round holes
// These will be handled in a slot layer // These will be handled in a slot layer
if( aPad->HasHole() && aPad->GetDrillSizeX() == aPad->GetDrillSizeY() ) if( aPad->HasDrilledHole() )
{ {
wxXmlNode* padStackHoleNode = appendNode( padStackDefNode, "PadstackHoleDef" ); wxXmlNode* padStackHoleNode = appendNode( padStackDefNode, "PadstackHoleDef" );
padStackHoleNode->AddAttribute( "name", wxString::Format( "%s%d_%d", padStackHoleNode->AddAttribute( "name", wxString::Format( "%s%d_%d",

View File

@ -420,6 +420,11 @@ public:
return true; return true;
} }
bool HasDrilledHole() const override
{
return m_viaType == VIATYPE::THROUGH;
}
std::shared_ptr<SHAPE_SEGMENT> GetEffectiveHoleShape() const override; std::shared_ptr<SHAPE_SEGMENT> GetEffectiveHoleShape() const override;
MINOPTMAX<int> GetWidthConstraint( wxString* aSource = nullptr ) const override; MINOPTMAX<int> GetWidthConstraint( wxString* aSource = nullptr ) const override;

View File

@ -298,15 +298,13 @@ static bool isEdge( const PNS::ITEM* aItem )
bool PNS_PCBNEW_RULE_RESOLVER::IsDrilledHole( const PNS::ITEM* aItem ) bool PNS_PCBNEW_RULE_RESOLVER::IsDrilledHole( const PNS::ITEM* aItem )
{ {
if( !isHole( aItem ) ) if( isHole( aItem ) )
return false; {
if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( aItem->Parent() ) )
return item->HasDrilledHole();
}
if( PAD* pad = dynamic_cast<PAD*>( aItem->Parent() ) ) return false;
return pad->GetDrillSizeX() && pad->GetDrillSizeX() == pad->GetDrillSizeY();
// Via holes are (currently) always round
return true;
} }

View File

@ -1112,7 +1112,7 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
r->Flush(); r->Flush();
} }
if( a->HasHole() && b->HasHole() ) if( a->HasDrilledHole() && b->HasDrilledHole() )
{ {
if( !pageAdded ) if( !pageAdded )
{ {