Finish implementation of hole clearance checking.

It appears we never did via hole testing, and pad hole testing didn't
appear to get much testing.
This commit is contained in:
Jeff Young 2020-12-25 22:13:47 +00:00
parent 0d57f90982
commit af2219ba7f
2 changed files with 159 additions and 76 deletions

View File

@ -32,17 +32,25 @@
#include <algorithm> #include <algorithm>
class SHAPE_SEGMENT : public SHAPE { class SHAPE_SEGMENT : public SHAPE
{
public: public:
SHAPE_SEGMENT(): SHAPE_SEGMENT() :
SHAPE( SH_SEGMENT ), m_width( 0 ) {}; SHAPE( SH_SEGMENT ),
m_width( 0 )
{};
SHAPE_SEGMENT( const VECTOR2I& aA, const VECTOR2I& aB, int aWidth = 0 ): SHAPE_SEGMENT( const VECTOR2I& aA, const VECTOR2I& aB, int aWidth = 0 ) :
SHAPE( SH_SEGMENT ), m_seg( aA, aB ), m_width( aWidth ) {}; SHAPE( SH_SEGMENT ),
m_seg( aA, aB ),
m_width( aWidth )
{};
SHAPE_SEGMENT( const SEG& aSeg, int aWidth = 0 ): SHAPE_SEGMENT( const SEG& aSeg, int aWidth = 0 ) :
SHAPE( SH_SEGMENT ), m_seg( aSeg ), m_width( aWidth ) {}; SHAPE( SH_SEGMENT ),
m_seg( aSeg ),
m_width( aWidth )
{};
~SHAPE_SEGMENT() {}; ~SHAPE_SEGMENT() {};

View File

@ -33,7 +33,6 @@
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <geometry/shape_null.h> #include <geometry/shape_null.h>
#include <drc/drc_engine.h>
#include <drc/drc_rtree.h> #include <drc/drc_rtree.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
@ -105,11 +104,11 @@ private:
bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run() bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
{ {
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
DRC_CONSTRAINT worstClearanceConstraint; DRC_CONSTRAINT worstConstraint;
if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, worstClearanceConstraint ) ) if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, worstConstraint ) )
{ {
m_largestClearance = worstClearanceConstraint.GetValue().Min(); m_largestClearance = worstConstraint.GetValue().Min();
} }
else else
{ {
@ -117,6 +116,11 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
return false; return false;
} }
if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, worstConstraint ) )
{
m_largestClearance = std::max( m_largestClearance, worstConstraint.GetValue().Min() );
}
m_drcEpsilon = m_board->GetDesignSettings().GetDRCEpsilon(); m_drcEpsilon = m_board->GetDesignSettings().GetDRCEpsilon();
m_zones.clear(); m_zones.clear();
@ -260,53 +264,112 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackAgainstItem( TRACK* track, SHA
PCB_LAYER_ID layer, PCB_LAYER_ID layer,
BOARD_ITEM* other ) BOARD_ITEM* other )
{ {
if( m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ) ) bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
return false; bool testHoles = !m_drcEngine->IsErrorLimitExceeded( DRCE_HOLE_CLEARANCE );
DRC_CONSTRAINT constraint;
int clearance;
int actual;
VECTOR2I pos;
auto constraint = m_drcEngine->EvalRulesForItems( CLEARANCE_CONSTRAINT, track, other, // It would really be better to know what particular nets a nettie should allow, but for now
layer ); // it is what it is.
int minClearance = constraint.GetValue().Min(); if( isNetTie( other ) )
int actual; testClearance = false;
VECTOR2I pos;
accountCheck( constraint ); BOARD_CONNECTED_ITEM* otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
// Special processing for track:track intersections if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
if( track->Type() == PCB_TRACE_T && other->Type() == PCB_TRACE_T ) testClearance = false;
if( testClearance )
{ {
SEG trackSeg( track->GetStart(), track->GetEnd() ); constraint = m_drcEngine->EvalRulesForItems( CLEARANCE_CONSTRAINT, track, other, layer );
SEG otherSeg( track->GetStart(), track->GetEnd() ); clearance = constraint.GetValue().Min();
if( OPT_VECTOR2I intersection = trackSeg.Intersect( otherSeg ) ) accountCheck( constraint );
// Special processing for track:track intersections
if( track->Type() == PCB_TRACE_T && other->Type() == PCB_TRACE_T )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING ); SEG trackSeg( track->GetStart(), track->GetEnd() );
drcItem->SetItems( track, other ); SEG otherSeg( track->GetStart(), track->GetEnd() );
drcItem->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drcItem, (wxPoint) intersection.get() ); if( OPT_VECTOR2I intersection = trackSeg.Intersect( otherSeg ) )
return true; {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
drcItem->SetItems( track, other );
drcItem->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drcItem, (wxPoint) intersection.get() );
return true;
}
}
std::shared_ptr<SHAPE> otherShape = getShape( other, layer );
if( trackShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), clearance ),
MessageTextFromValue( userUnits(), actual ) );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
drce->SetItems( track, other );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, (wxPoint) pos );
if( !m_drcEngine->GetReportAllTrackErrors() )
return false;
} }
} }
std::shared_ptr<SHAPE> otherShape = getShape( other, layer ); if( testHoles && ( other->Type() == PCB_VIA_T || other->Type() == PCB_PAD_T ) )
if( trackShape->Collide( otherShape.get(), minClearance - m_drcEpsilon, &actual, &pos ) )
{ {
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE ); std::unique_ptr<SHAPE_SEGMENT> holeShape;
m_msg.Printf( _( "(%s clearance %s; actual %s)" ), if( other->Type() == PCB_VIA_T )
constraint.GetName(), {
MessageTextFromValue( userUnits(), minClearance ), VIA* via = static_cast<VIA*>( other );
MessageTextFromValue( userUnits(), actual ) ); pos = via->GetPosition();
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg ); if( via->GetLayerSet().Contains( layer ) )
drce->SetItems( track, other ); holeShape.reset( new SHAPE_SEGMENT( pos, pos, via->GetDrill() ) );
drce->SetViolatingRule( constraint.GetParentRule() ); }
else if( other->Type() == PCB_PAD_T )
{
PAD* pad = static_cast<PAD*>( other );
reportViolation( drce, (wxPoint) pos ); if( pad->GetDrillSize().x )
holeShape.reset( new SHAPE_SEGMENT( *pad->GetEffectiveHoleShape() ) );
}
if( !m_drcEngine->GetReportAllTrackErrors() ) if( holeShape )
return false; {
constraint = m_drcEngine->EvalRulesForItems( HOLE_CLEARANCE_CONSTRAINT, other, track );
clearance = constraint.GetValue().Min();
accountCheck( constraint.GetParentRule() );
if( trackShape->Collide( holeShape.get(), clearance - m_drcEpsilon, &actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), clearance ),
MessageTextFromValue( userUnits(), actual ) );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
drce->SetItems( track, other );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, (wxPoint) pos );
}
}
} }
return true; return true;
@ -364,8 +427,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
} }
if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer, if( zoneTree->QueryColliding( itemBBox, itemShape.get(), aLayer,
clearance - m_drcEpsilon, clearance - m_drcEpsilon, &actual, &pos ) )
&actual, &pos ) )
{ {
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CLEARANCE );
@ -408,16 +470,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
// Filter: // Filter:
[&]( BOARD_ITEM* other ) -> bool [&]( BOARD_ITEM* other ) -> bool
{ {
// It would really be better to know what particular nets a nettie
// should allow, but for now it is what it is.
if( isNetTie( other ) )
return false;
auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
return false;
BOARD_ITEM* a = track; BOARD_ITEM* a = track;
BOARD_ITEM* b = other; BOARD_ITEM* b = other;
@ -483,7 +535,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
if( other->Type() == PCB_PAD_T ) if( other->Type() == PCB_PAD_T )
{ {
auto otherPad = static_cast<PAD*>( other ); PAD* otherPad = static_cast<PAD*>( other );
// If pads are equivalent (ie: from the same footprint with the same pad number)... // If pads are equivalent (ie: from the same footprint with the same pad number)...
if( pad->SameLogicalPadAs( otherPad ) ) if( pad->SameLogicalPadAs( otherPad ) )
@ -508,32 +560,55 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
return true; return true;
} }
if( testHoles ) if( testHoles && pad->FlashLayer( layer ) && otherPad->GetDrillSize().x )
{ {
if( ( pad->FlashLayer( layer ) && otherPad->GetDrillSize().x ) constraint = m_drcEngine->EvalRulesForItems( HOLE_CLEARANCE_CONSTRAINT, pad,
|| ( pad->GetDrillSize().x && otherPad->FlashLayer( layer ) ) ) otherPad );
clearance = constraint.GetValue().Min();
accountCheck( constraint.GetParentRule() );
if( padShape->Collide( otherPad->GetEffectiveHoleShape(), clearance - m_drcEpsilon,
&actual, &pos ) )
{ {
constraint = m_drcEngine->EvalRulesForItems( HOLE_CLEARANCE_CONSTRAINT, pad, std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
otherPad );
clearance = constraint.GetValue().Min();
accountCheck( constraint.GetParentRule() ); m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), clearance ),
MessageTextFromValue( userUnits(), actual ) );
if( padShape->Collide( otherShape.get(), clearance - m_drcEpsilon, &actual, &pos ) ) drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
{ drce->SetItems( pad, other );
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE ); drce->SetViolatingRule( constraint.GetParentRule() );
m_msg.Printf( _( "(%s clearance %s; actual %s)" ), reportViolation( drce, (wxPoint) pos );
constraint.GetName(), }
MessageTextFromValue( userUnits(), clearance ), }
MessageTextFromValue( userUnits(), actual ) );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg ); if( testHoles && otherPad->FlashLayer( layer ) && pad->GetDrillSize().x )
drce->SetItems( pad, other ); {
drce->SetViolatingRule( constraint.GetParentRule() ); constraint = m_drcEngine->EvalRulesForItems( HOLE_CLEARANCE_CONSTRAINT, pad,
otherPad );
clearance = constraint.GetValue().Min();
reportViolation( drce, (wxPoint) pos ); accountCheck( constraint.GetParentRule() );
}
if( otherShape->Collide( pad->GetEffectiveHoleShape(), clearance - m_drcEpsilon,
&actual, &pos ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
m_msg.Printf( _( "(%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), clearance ),
MessageTextFromValue( userUnits(), actual ) );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + m_msg );
drce->SetItems( pad, other );
drce->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drce, (wxPoint) pos );
} }
} }