Move new clearance tests into kicad.

This commit is contained in:
Jeff Young 2020-09-11 17:24:27 +01:00
parent 35d993988d
commit 5424d6fa09
14 changed files with 411 additions and 537 deletions

View File

@ -234,12 +234,16 @@ set( PCBNEW_DRC_SRCS
drc/drc_drilled_hole_tester.cpp drc/drc_drilled_hole_tester.cpp
drc/drc_keepout_tester.cpp drc/drc_keepout_tester.cpp
drc/drc_textvar_tester.cpp drc/drc_textvar_tester.cpp
drc/footprint_tester.cpp
drc/drc.cpp drc/drc.cpp
drc/drc_clearance_test_functions.cpp drc/drc_clearance_test_functions.cpp
drc/drc_engine.cpp drc/drc_engine.cpp
drc/drc_test_provider.cpp
drc/drc_rule_parser.cpp drc/drc_rule_parser.cpp
drc/footprint_tester.cpp drc/drc_test_provider.cpp
drc/drc_test_provider_clearance_base.cpp
drc/drc_test_provider_copper_clearance.cpp
drc/drc_test_provider_edge_clearance.cpp
drc/drc_test_provider_hole_clearance.cpp
) )
set( PCBNEW_NETLIST_SRCS set( PCBNEW_NETLIST_SRCS

View File

@ -44,6 +44,7 @@ void drcPrintDebugMessage( int level, wxString msg, const char *function, int li
if( wxGetEnv( "DRC_DEBUG", &valueStr ) ) if( wxGetEnv( "DRC_DEBUG", &valueStr ) )
{ {
int setLevel = wxAtoi( valueStr ); int setLevel = wxAtoi( valueStr );
if( level <= setLevel ) if( level <= setLevel )
{ {
printf("%-30s:%d | %s\n", function, line, (const char *) msg.c_str() ); printf("%-30s:%d | %s\n", function, line, (const char *) msg.c_str() );
@ -100,79 +101,6 @@ DRC_RULE* DRC_ENGINE::createInferredRule( const wxString& name, std::set<BOARD_I
return rule; return rule;
} }
#if 0
int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
wxString* aSource ) const
{
BOARD* board = GetBoard();
int clearance = 0;
wxString source;
wxString* localSource = aSource ? &source : nullptr;
BOARD_CONNECTED_ITEM* second = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
// No clearance if "this" is not (yet) linked to a board therefore no available netclass
if( !board )
return clearance;
// LEVEL 1: local overrides (pad, footprint, etc.)
//
if( GetLocalClearanceOverrides() > clearance )
clearance = GetLocalClearanceOverrides( localSource );
if( second && second->GetLocalClearanceOverrides() > clearance )
clearance = second->GetLocalClearanceOverrides( localSource );
if( clearance )
{
if( aSource )
*aSource = *localSource;
return clearance;
}
// LEVEL 2: Rules
//
if( GetRuleClearance( aItem, aLayer, &clearance, aSource ) )
return clearance;
// LEVEL 3: Accumulated local settings, netclass settings, & board design settings
//
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
NETCLASS* netclass = GetEffectiveNetclass();
NETCLASS* secondNetclass = second ? second->GetEffectiveNetclass() : nullptr;
if( bds.m_MinClearance > clearance )
{
if( aSource )
*aSource = _( "board minimum" );
clearance = bds.m_MinClearance;
}
if( netclass && netclass->GetClearance() > clearance )
clearance = netclass->GetClearance( aSource );
if( secondNetclass && secondNetclass->GetClearance() > clearance )
clearance = secondNetclass->GetClearance( aSource );
if( aItem && aItem->GetLayer() == Edge_Cuts && bds.m_CopperEdgeClearance > clearance )
{
if( aSource )
*aSource = _( "board edge" );
clearance = bds.m_CopperEdgeClearance;
}
if( GetLocalClearance() > clearance )
clearance = GetLocalClearance( aSource );
if( second && second->GetLocalClearance() > clearance )
clearance = second->GetLocalClearance( aSource );
return clearance;
}
#endif
void DRC_ENGINE::inferLegacyRules() void DRC_ENGINE::inferLegacyRules()
{ {
@ -490,11 +418,32 @@ void DRC_ENGINE::RunTests( )
} }
const DRC_CONSTRAINT& DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintId, DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintId,
BOARD_ITEM* a, BOARD_ITEM* b, BOARD_ITEM* a, BOARD_ITEM* b, PCB_LAYER_ID aLayer )
PCB_LAYER_ID aLayer )
{ {
DRC_RULE* rv; // Local overrides take precedence
if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE )
{
BOARD_CONNECTED_ITEM* ac = a->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( a )
: nullptr;
BOARD_CONNECTED_ITEM* bc = b->IsConnected() ? static_cast<BOARD_CONNECTED_ITEM*>( b )
: nullptr;
int clearance = 0;
if( ac && ac->GetLocalClearanceOverrides( nullptr ) > clearance )
clearance = ac->GetLocalClearanceOverrides( &m_msg );
if( bc && bc->GetLocalClearanceOverrides( nullptr ) > clearance )
clearance = bc->GetLocalClearanceOverrides( &m_msg );
if( clearance )
{
DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_CLEARANCE, m_msg );
constraint.m_Value.SetMin( clearance );
return constraint;
}
}
auto ruleset = m_constraintMap[ aConstraintId ]; auto ruleset = m_constraintMap[ aConstraintId ];
for( const auto& rcond : ruleset->sortedConstraints ) for( const auto& rcond : ruleset->sortedConstraints )

View File

@ -163,9 +163,9 @@ public:
return m_board; return m_board;
} }
const DRC_CONSTRAINT& EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a, DRC_CONSTRAINT EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a,
BOARD_ITEM* b = nullptr, BOARD_ITEM* b = nullptr,
PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
std::vector<DRC_CONSTRAINT> QueryConstraintsById( DRC_CONSTRAINT_TYPE_T ruleID ); std::vector<DRC_CONSTRAINT> QueryConstraintsById( DRC_CONSTRAINT_TYPE_T ruleID );
@ -173,9 +173,16 @@ public:
EDA_UNITS UserUnits() const EDA_UNITS UserUnits() const
{ {
// JEY TODO
return EDA_UNITS::MILLIMETRES; return EDA_UNITS::MILLIMETRES;
} }
bool GetTestTracksAgainstZones() const
{
// JEY TODO
return true;
}
bool CompileRules(); bool CompileRules();
void Report( std::shared_ptr<DRC_ITEM> aItem, ::MARKER_PCB *Marker ); void Report( std::shared_ptr<DRC_ITEM> aItem, ::MARKER_PCB *Marker );
@ -232,6 +239,8 @@ protected:
PROGRESS_REPORTER* m_progressReporter; PROGRESS_REPORTER* m_progressReporter;
// condition -> rule -> provider // condition -> rule -> provider
wxString m_msg; // Allocating strings gets expensive enough to want to avoid it
}; };
#endif // DRC_H #endif // DRC_H

View File

@ -118,6 +118,15 @@ const DRC_CONSTRAINT* GetConstraint( const BOARD_ITEM* aItem, const BOARD_ITEM*
} }
wxString DRC_CONSTRAINT::GetName() const
{
if( m_parentRule )
return wxString::Format( _( "rule %s" ), m_parentRule->m_Name );
else
return m_name;
}
DRC_RULE::DRC_RULE() : DRC_RULE::DRC_RULE() :
m_Unary( false ), m_Unary( false ),
m_LayerCondition( LSET::AllLayersMask() ), m_LayerCondition( LSET::AllLayersMask() ),

View File

@ -96,10 +96,12 @@ private:
class DRC_CONSTRAINT class DRC_CONSTRAINT
{ {
public: public:
DRC_CONSTRAINT( DRC_CONSTRAINT_TYPE_T aType = DRC_CONSTRAINT_TYPE_UNKNOWN ) : DRC_CONSTRAINT( DRC_CONSTRAINT_TYPE_T aType = DRC_CONSTRAINT_TYPE_UNKNOWN,
const wxString& aName = wxEmptyString ) :
m_Type( aType ), m_Type( aType ),
m_DisallowFlags( 0 ), m_DisallowFlags( 0 ),
m_parentRule( nullptr ) // fixme m_name( aName ),
m_parentRule( nullptr )
{ {
} }
@ -109,13 +111,16 @@ class DRC_CONSTRAINT
void SetParentRule( DRC_RULE *aParentRule ) { m_parentRule = aParentRule; } void SetParentRule( DRC_RULE *aParentRule ) { m_parentRule = aParentRule; }
DRC_RULE* GetParentRule() const { return m_parentRule; } DRC_RULE* GetParentRule() const { return m_parentRule; }
wxString GetName() const;
public: public:
DRC_CONSTRAINT_TYPE_T m_Type; DRC_CONSTRAINT_TYPE_T m_Type;
MINOPTMAX<int> m_Value; MINOPTMAX<int> m_Value;
int m_DisallowFlags; int m_DisallowFlags;
private: private:
DRC_RULE* m_parentRule; wxString m_name; // For just-in-time constraints
DRC_RULE* m_parentRule; // For constraints found in rules
}; };

View File

@ -22,61 +22,57 @@
*/ */
#include <common.h>
#include <class_board.h> #include <class_board.h>
#include <class_drawsegment.h> #include <class_track.h>
#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h> #include <geometry/seg.h>
#include <geometry/shape_poly_set.h> #include <drc/drc_test_provider_clearance_base.h>
#include <geometry/shape_rect.h>
#include <drc/drc_engine.h>
#include <drc_proto/drc_test_provider_clearance_base.h>
#include <drc/drc.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
const int UI_EPSILON = Mils2iu( 5 ); const int UI_EPSILON = Mils2iu( 5 );
wxPoint test::DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone )
wxPoint DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( PCB_LAYER_ID aLayer, TRACK* aTrack,
ZONE_CONTAINER* aZone )
{ {
SHAPE_POLY_SET* conflictOutline; SHAPE_POLY_SET* zonePoly = nullptr;
PCB_LAYER_ID l = aTrack->GetLayer(); if( aZone->IsFilled() && aZone->HasFilledPolysForLayer( aLayer ) )
zonePoly = const_cast<SHAPE_POLY_SET*>( &aZone->GetFilledPolysList( aLayer ) );
if( aConflictZone->IsFilled() ) if( !zonePoly || zonePoly->IsEmpty() )
conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList( l ) ); zonePoly = aZone->Outline();
else
conflictOutline = aConflictZone->Outline();
SEG trackSeg( aTrack->GetStart(), aTrack->GetEnd() );
SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
SEG closestSeg;
wxPoint pt1 = aTrack->GetPosition(); for( auto it = zonePoly->CIterateSegments( 0, -1, true ); it; it++ )
wxPoint pt2 = aTrack->GetEnd();
// If the mid-point is in the zone, then that's a fine place for the marker
if( conflictOutline->SquaredDistance( ( pt1 + pt2 ) / 2 ) == 0 )
return ( pt1 + pt2 ) / 2;
// Otherwise do a binary search for a "good enough" marker location
else
{ {
while( GetLineLength( pt1, pt2 ) > UI_EPSILON ) SEG::ecoord dist_sq = trackSeg.SquaredDistance( *it );
{
if( conflictOutline->SquaredDistance( pt1 ) < conflictOutline->SquaredDistance( pt2 ) )
pt2 = ( pt1 + pt2 ) / 2;
else
pt1 = ( pt1 + pt2 ) / 2;
}
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent" if( dist_sq < closestDist_sq )
return pt1; {
closestDist_sq = dist_sq;
closestSeg = *it;
}
} }
VECTOR2I pt1 = closestSeg.A;
VECTOR2I pt2 = closestSeg.B;
// Do a binary search for a "good enough" marker location
while( GetLineLength( (wxPoint) pt1, (wxPoint) pt2 ) > UI_EPSILON )
{
if( trackSeg.SquaredDistance( pt1 ) < trackSeg.SquaredDistance( pt2 ) )
pt2 = ( pt1 + pt2 ) / 2;
else
pt1 = ( pt1 + pt2 ) / 2;
}
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent"
return (wxPoint) pt1;
} }
wxPoint test::DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( TRACK* aTrack, const SEG& aConflictSeg ) wxPoint DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( TRACK* aTrack, const SEG& aConflictSeg )
{ {
wxPoint pt1 = aTrack->GetPosition(); wxPoint pt1 = aTrack->GetPosition();
wxPoint pt2 = aTrack->GetEnd(); wxPoint pt2 = aTrack->GetEnd();
@ -93,4 +89,3 @@ wxPoint test::DRC_TEST_PROVIDER_CLEARANCE_BASE::getLocation( TRACK* aTrack, cons
// Once we're within UI_EPSILON pt1 and pt2 are "equivalent" // Once we're within UI_EPSILON pt1 and pt2 are "equivalent"
return pt1; return pt1;
} }

View File

@ -27,11 +27,10 @@
#ifndef DRC_TEST_PROVIDER_CLEARANCE_BASE__H #ifndef DRC_TEST_PROVIDER_CLEARANCE_BASE__H
#define DRC_TEST_PROVIDER_CLEARANCE_BASE__H #define DRC_TEST_PROVIDER_CLEARANCE_BASE__H
#include <class_board.h> #include <drc/drc_test_provider.h>
#include <pcbnew/drc/drc_test_provider.h> class BOARD;
namespace test {
class DRC_TEST_PROVIDER_CLEARANCE_BASE : public DRC_TEST_PROVIDER class DRC_TEST_PROVIDER_CLEARANCE_BASE : public DRC_TEST_PROVIDER
{ {
@ -41,37 +40,24 @@ public:
m_board( nullptr ), m_board( nullptr ),
m_largestClearance( 0 ), m_largestClearance( 0 ),
m_boardOutlineValid( false ) m_boardOutlineValid( false )
{ {
}
}
virtual ~DRC_TEST_PROVIDER_CLEARANCE_BASE() virtual ~DRC_TEST_PROVIDER_CLEARANCE_BASE()
{ {
} }
protected: protected:
void testCopperDrawItem( BOARD_ITEM* aItem );
bool doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
//bool checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_PAD* pad,
// int minClearance, int* aActualDist );
//bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual );
//bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd,
// int aDist, int* aActual );
//bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCount,
// int aAllowedDist, int* actualDist );
wxPoint getLocation( TRACK* aTrack, const SEG& aConflictSeg ); wxPoint getLocation( TRACK* aTrack, const SEG& aConflictSeg );
wxPoint getLocation( TRACK* aTrack, ZONE_CONTAINER* aConflictZone ); wxPoint getLocation( PCB_LAYER_ID aLayer, TRACK* aTrack, ZONE_CONTAINER* aZone );
protected:
BOARD* m_board; BOARD* m_board;
int m_largestClearance; int m_largestClearance;
SHAPE_POLY_SET m_boardOutline; // The board outline including cutouts bool m_boardOutlineValid;
bool m_boardOutlineValid;
wxString m_msg; // Allocating strings gets expensive enough to want to avoid it
}; };
};
#endif // DRC_TEST_PROVIDER_CLEARANCE_BASE__H #endif // DRC_TEST_PROVIDER_CLEARANCE_BASE__H

View File

@ -32,12 +32,11 @@
#include <geometry/shape_rect.h> #include <geometry/shape_rect.h>
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <pcbnew/drc/drc_engine.h> #include <drc/drc_engine.h>
#include <drc/drc.h> #include <drc/drc.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc_proto/drc_rtree.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
#include <drc_proto/drc_test_provider_clearance_base.h> #include <drc/drc_test_provider_clearance_base.h>
/* /*
Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their electrical clearance. Copper clearance test. Checks all copper items (pads, vias, tracks, drawings, zones) for their electrical clearance.
@ -50,15 +49,13 @@
TODO: improve zone clearance check (super slow) TODO: improve zone clearance check (super slow)
*/ */
namespace test {
class DRC_TEST_PROVIDER_COPPER_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE class DRC_TEST_PROVIDER_COPPER_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE
{ {
public: public:
DRC_TEST_PROVIDER_COPPER_CLEARANCE () : DRC_TEST_PROVIDER_COPPER_CLEARANCE () :
DRC_TEST_PROVIDER_CLEARANCE_BASE() DRC_TEST_PROVIDER_CLEARANCE_BASE()
{ {
} }
virtual ~DRC_TEST_PROVIDER_COPPER_CLEARANCE() virtual ~DRC_TEST_PROVIDER_COPPER_CLEARANCE()
{ {
@ -80,46 +77,50 @@ public:
private: private:
void testPadClearances(); void testPadClearances();
void testTrackClearances();
void testTrackClearances( bool aTestZones );
void testCopperTextAndGraphics(); void testCopperTextAndGraphics();
void testZones(); void testZones();
void testCopperDrawItem( BOARD_ITEM* aItem ); void testCopperDrawItem( BOARD_ITEM* aItem );
void doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones ); void doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer, TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones );
bool doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit ); bool doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_limit );
}; };
};
bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
{ {
auto bds = m_drcEngine->GetDesignSettings();
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
DRC_CONSTRAINT worstClearanceConstraint; DRC_CONSTRAINT worstClearanceConstraint;
if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE,
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
{ {
m_largestClearance = worstClearanceConstraint.GetValue().Min(); m_largestClearance = worstClearanceConstraint.GetValue().Min();
} }
else else
{ {
ReportAux("No Clearance constraints found..."); ReportAux( "No Clearance constraints found..." );
return false; return false;
} }
ReportAux( "Worst clearance : %d nm", m_largestClearance ); ReportAux( "Worst clearance : %d nm", m_largestClearance );
//m_largestClearance = ReportStage( _( "Testing pad copper clerances" ), 0, 2 );
ReportStage( ("Testing pad copper clerances"), 0, 2 );
testPadClearances(); testPadClearances();
ReportStage( ("Testing track/via copper clerances"), 1, 2 );
testTrackClearances(); ReportStage( _( "Testing track/via copper clerances" ), 1, 2 );
ReportStage( ("Testing copper drawing/text clerances"), 1, 2 ); testTrackClearances( m_drcEngine->GetTestTracksAgainstZones() );
ReportStage( _( "Testing copper drawing/text clerances" ), 1, 2 );
testCopperTextAndGraphics(); testCopperTextAndGraphics();
ReportStage( ("Testing copper zone clearances"), 1, 2 );
ReportStage( _( "Testing copper zone clearances" ), 1, 2 );
testZones(); testZones();
reportRuleStatistics(); reportRuleStatistics();
@ -127,7 +128,7 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
return true; return true;
} }
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperTextAndGraphics() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperTextAndGraphics()
{ {
// Test copper items for clearance violations with vias, tracks and pads // Test copper items for clearance violations with vias, tracks and pads
@ -165,12 +166,13 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperTextAndGraphics()
} }
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem ) void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* aItem )
{ {
EDA_RECT bbox; EDA_RECT bbox;
std::shared_ptr<SHAPE> itemShape; std::shared_ptr<SHAPE> itemShape;
DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem ); DRAWSEGMENT* drawItem = dynamic_cast<DRAWSEGMENT*>( aItem );
EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem ); EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( aItem );
PCB_LAYER_ID layer = aItem->GetLayer();
if( drawItem ) if( drawItem )
{ {
@ -190,18 +192,15 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() ); SHAPE_RECT bboxShape( bbox.GetX(), bbox.GetY(), bbox.GetWidth(), bbox.GetHeight() );
//if( itemShape->Empty() )
// return;
// Test tracks and vias // Test tracks and vias
for( auto track : m_board->Tracks() ) for( TRACK* track : m_board->Tracks() )
{ {
if( !track->IsOnLayer( aItem->GetLayer() ) ) if( !track->IsOnLayer( aItem->GetLayer() ) )
continue; continue;
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
aItem, track, aItem->GetLayer() ); aItem, track, layer );
auto minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
int actual = INT_MAX; int actual = INT_MAX;
wxPoint pos; wxPoint pos;
@ -221,15 +220,13 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
if( actual < INT_MAX ) if( actual < INT_MAX )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg; m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), constraint.GetName(),
constraint.GetParentRule()->m_Name,
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), std::max( 0, actual ), true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( track, aItem ); drcItem->SetItems( track, aItem );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -238,98 +235,83 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a
} }
// Test pads // Test pads
for( auto pad : m_board->GetPads() ) for( D_PAD* pad : m_board->GetPads() )
{ {
if( !pad->IsOnLayer( aItem->GetLayer() ) ) if( !pad->IsOnLayer( layer ) )
continue; continue;
// Graphic items are allowed to act as net-ties within their own footprint // Graphic items are allowed to act as net-ties within their own footprint
if( drawItem && pad->GetParent() == drawItem->GetParent() ) if( drawItem && pad->GetParent() == drawItem->GetParent() )
continue; continue;
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
aItem, pad ); aItem, pad, layer );
auto minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
int actual;
accountCheck( constraint ); accountCheck( constraint );
int actual = INT_MAX;
int bb_radius = pad->GetBoundingRadius() + minClearance;
// Fast test to detect a pad candidate inside the text bounding box // Fast test to detect a pad candidate inside the text bounding box
// Finer test (time consumming) is made only for pads near the text. // Finer test (time consumming) is made only for pads near the text.
int bb_radius = pad->GetBoundingRadius() + minClearance;
if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) ) if( !bboxShape.Collide( SEG( pad->GetPosition(), pad->GetPosition() ), bb_radius ) )
continue; continue;
if( !pad->GetEffectiveShape()->Collide( itemShape.get(), minClearance, &actual ) ) if( !pad->GetEffectiveShape()->Collide( itemShape.get(), minClearance, &actual ) )
continue; continue;
if( actual < INT_MAX ) std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
wxString msg; drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad, aItem );
drcItem->SetViolatingRule( constraint.GetParentRule() );
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), ReportWithMarker( drcItem, pad->GetPosition() );
constraint.GetParentRule()->m_Name,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( pad, aItem );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, pad->GetPosition() );
}
} }
} }
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances( bool aTestZones )
{ {
const int delta = 500; // This is the number of tests between 2 calls to the const int delta = 500; // This is the number of tests between 2 calls to the progress bar
// progress bar int count = m_board->Tracks().size();
int count = m_board->Tracks().size();
int deltamax = count/delta;
ReportProgress(0.0); ReportProgress( 0.0 );
ReportAux("Testing %d tracks...", count ); ReportAux( "Testing %d tracks...", count );
int ii = 0; int ii = 0;
count = 0;
for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ ) for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ )
{ {
if( (ii % delta) == 0) if( (ii % delta) == 0)
{
ReportProgress( (double) ii / (double) m_board->Tracks().size() ); ReportProgress( (double) ii / (double) m_board->Tracks().size() );
}
ii++; ii++;
// Test new segment against tracks and pads, optionally against copper zones
doTrackDrc( *seg_it, seg_it + 1, m_board->Tracks().end(), false /*fixme: control for copper zones*/ ); // Test segment against tracks and pads, optionally against copper zones
for( PCB_LAYER_ID layer : (*seg_it)->GetLayerSet().Seq() )
{
doTrackDrc( *seg_it, layer, seg_it + 1, m_board->Tracks().end(), aTestZones );
}
} }
} }
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, void DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, PCB_LAYER_ID aLayer,
TRACKS::iterator aEndIt, bool aTestZones ) TRACKS::iterator aStartIt,
TRACKS::iterator aEndIt, bool aTestZones )
{ {
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() ); SHAPE_SEGMENT refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd(), aRefSeg->GetWidth() );
PCB_LAYER_ID refLayer = aRefSeg->GetLayer(); EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
LSET refLayerSet = aRefSeg->GetLayerSet(); int refSegWidth = aRefSeg->GetWidth();
EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
int refSegWidth = aRefSeg->GetWidth();
/******************************************/
/* Phase 0 : via DRC tests : */
/******************************************/
// fixme: via annulus and other nin-coppper clearance tests moved elsewhere
/******************************************/ /******************************************/
/* Phase 1 : test DRC track to pads : */ /* Phase 1 : test DRC track to pads : */
@ -351,36 +333,33 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
if( !inflatedBB.Contains( pad->GetPosition() ) ) if( !inflatedBB.Contains( pad->GetPosition() ) )
continue; continue;
if( !( pad->GetLayerSet() & refLayerSet ).any() ) /// Skip checking pad copper when it has been removed
if( !pad->IsOnLayer( aLayer ) )
continue; continue;
// No need to check pads with the same net as the refSeg. // No need to check pads with the same net as the refSeg.
if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() ) if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() )
continue; continue;
// fixme: hole to hole clearance moved elsewhere auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
aRefSeg, pad, aLayer );
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, int minClearance = constraint.GetValue().Min();
aRefSeg, pad ); int actual;
auto minClearance = constraint.GetValue().Min();
int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
int actual;
accountCheck( constraint ); accountCheck( constraint );
auto padShape = pad->GetEffectiveShape(); const std::shared_ptr<SHAPE>& padShape = pad->GetEffectiveShape();
if( padShape->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) ) if( padShape->Collide( &refSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
/*m_clearanceSource fixme*/ "", constraint.GetName(),
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, pad ); drcItem->SetItems( aRefSeg, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -405,27 +384,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
if( aRefSeg->GetNetCode() == track->GetNetCode() ) if( aRefSeg->GetNetCode() == track->GetNetCode() )
continue; continue;
// No problem if tracks are on different layers: if( !track->GetLayerSet().test( aLayer ) )
// Note that while the general case of GetLayerSet intersection always works,
// the others are much faster.
bool sameLayers;
if( aRefSeg->Type() == PCB_VIA_T )
{
if( track->Type() == PCB_VIA_T )
sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
else
sameLayers = refLayerSet.test( track->GetLayer() );
}
else
{
if( track->Type() == PCB_VIA_T )
sameLayers = track->GetLayerSet().test( refLayer );
else
sameLayers = track->GetLayer() == refLayer;
}
if( !sameLayers )
continue; continue;
// Preflight based on worst-case inflated bounding boxes: // Preflight based on worst-case inflated bounding boxes:
@ -435,21 +394,27 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
if( !trackBB.Intersects( refSegBB ) ) if( !trackBB.Intersects( refSegBB ) )
continue; continue;
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
aRefSeg, track ); aRefSeg, track, aLayer );
auto minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
int actual;
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() );
accountCheck( constraint ); accountCheck( constraint );
SHAPE_SEGMENT trackSeg( track->GetStart(), track->GetEnd(), track->GetWidth() ); /// Check to see if the via has a pad on this layer
int actual; if( track->Type() == PCB_VIA_T )
{
VIA* via = static_cast<VIA*>( track );
if( !via->IsPadOnLayer( aLayer ) )
trackSeg.SetWidth( via->GetDrillValue() );
}
// Check two tracks crossing first as it reports a DRCE without distances
if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) ) if( OPT_VECTOR2I intersection = refSeg.GetSeg().Intersect( trackSeg.GetSeg() ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACKS_CROSSING );
// fixme
drcItem->SetErrorMessage( "FIXME" );
drcItem->SetItems( aRefSeg, track ); drcItem->SetItems( aRefSeg, track );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -458,19 +423,17 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
if( isErrorLimitExceeded( DRCE_TRACKS_CROSSING ) ) if( isErrorLimitExceeded( DRCE_TRACKS_CROSSING ) )
return; return;
} }
else if( refSeg.Collide( &trackSeg, minClearance, &actual ) ) else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
{ {
wxPoint pos = getLocation( aRefSeg, trackSeg.GetSeg() ); wxPoint pos = getLocation( aRefSeg, trackSeg.GetSeg() );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
wxString msg; constraint.GetName(),
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
/*m_clearanceSource fixme*/"",
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, track ); drcItem->SetItems( aRefSeg, track );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -485,75 +448,60 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACK
/* Phase 3: test DRC with copper zones */ /* Phase 3: test DRC with copper zones */
/***************************************/ /***************************************/
// Can be *very* time consumming. // Can be *very* time consumming.
if( aTestZones ) if( aTestZones )
{ {
SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
for( ZONE_CONTAINER* zone : m_board->Zones() ) for( ZONE_CONTAINER* zone : m_board->Zones() )
{ {
if( !( refLayerSet & zone->GetLayerSet() ).any() || zone->GetIsKeepout() ) if( !zone->GetLayerSet().test( aLayer ) || zone->GetIsKeepout() )
continue; continue;
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
continue;
if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
continue;
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
aRefSeg, zone, aLayer );
int minClearance = constraint.GetValue().Min();
int halfWidth = refSegWidth / 2;
int allowedDist = minClearance + halfWidth - bds.GetDRCEpsilon();
int actual;
accountCheck( constraint );
if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
{ {
if( zone->GetFilledPolysList( layer ).IsEmpty() ) actual = std::max( 0, actual - halfWidth );
continue; std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
continue; constraint.GetName(),
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
// fixme: per-layer onLayer() property drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefSeg, zone );
drcItem->SetViolatingRule( constraint.GetParentRule() );
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, ReportWithMarker( drcItem, getLocation( aLayer, aRefSeg, zone ) );
aRefSeg, zone );
auto minClearance = constraint.GetValue().Min();
int widths = refSegWidth / 2;
accountCheck( constraint );
// to avoid false positive, due to rounding issues and approxiamtions
// in distance and clearance calculations, use a small threshold for distance
// (1 micron)
#define THRESHOLD_DIST Millimeter2iu( 0.001 )
int allowedDist = minClearance + widths + THRESHOLD_DIST;
int actual = INT_MAX;
if( zone->GetFilledPolysList( layer ).Collide( testSeg, allowedDist, &actual ) )
{
actual = std::max( 0, actual - widths );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
constraint.GetParentRule()->m_Name,
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( aRefSeg, zone );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, getLocation( aRefSeg, zone ) );
}
} }
} }
} }
// fixme: board edge clearance to another rule
} }
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( ) void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
{ {
auto bds = m_drcEngine->GetDesignSettings(); std::vector<D_PAD*> sortedPads;
std::vector<D_PAD*> sortedPads;
m_board->GetSortedPadListByXthenYCoord( sortedPads ); m_board->GetSortedPadListByXthenYCoord( sortedPads );
ReportAux("Testing %d pads...", sortedPads.size() ); ReportAux( "Testing %d pads...", sortedPads.size() );
for( auto p : sortedPads )
if( sortedPads.empty() ) if( sortedPads.empty() )
return; return;
@ -578,8 +526,9 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
D_PAD** listEnd = &sortedPads[0] + sortedPads.size(); D_PAD** listEnd = &sortedPads[0] + sortedPads.size();
int ii = 0; int ii = 0;
// Test the pads // Test the pads
for( auto& pad : sortedPads ) for( D_PAD* pad : sortedPads )
{ {
if( ii % 100 == 0 ) if( ii % 100 == 0 )
ReportProgress( (double) ii / (double) sortedPads.size() ); ReportProgress( (double) ii / (double) sortedPads.size() );
@ -591,10 +540,11 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
} }
} }
bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart,
int x_limit ) D_PAD** aEnd, int x_limit )
{ {
const static LSET all_cu = LSET::AllCuMask(); const static LSET all_cu = LSET::AllCuMask();
const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
LSET layerMask = aRefPad->GetLayerSet() & all_cu; LSET layerMask = aRefPad->GetLayerSet() & all_cu;
@ -615,24 +565,25 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D
if( pad->GetNetCode() && ( aRefPad->GetNetCode() == pad->GetNetCode() ) ) if( pad->GetNetCode() && ( aRefPad->GetNetCode() == pad->GetNetCode() ) )
continue; continue;
// if pads are from the same footprint // If pads are equivalent (ie: from the same footprint with the same pad number)...
if( pad->GetParent() == aRefPad->GetParent() ) if( pad->GetParent() == aRefPad->GetParent() && pad->PadNameEqual( aRefPad ) )
{ {
// and have the same pad number ( equivalent pads ) // ...and have nets, then they must be the same net
if( pad->PadNameEqual( aRefPad ) ) if( pad->GetNetCode() && aRefPad->GetNetCode()
&& pad->GetNetCode() != aRefPad->GetNetCode() )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SHORTING_ITEMS ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (nets %d and %d)" ),
(int) pad->GetNetCode(), (int) aRefPad->GetNetCode() );
drcItem->SetErrorMessage( msg ); m_msg.Printf( drcItem->GetErrorText() + _( " (nets %s and %s)" ),
pad->GetNetname(), aRefPad->GetNetname() );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad, aRefPad ); drcItem->SetItems( pad, aRefPad );
drcItem->SetViolatingRule( nullptr ); // fixme: is this correct?
ReportWithMarker( drcItem, aRefPad->GetPosition() ); ReportWithMarker( drcItem, aRefPad->GetPosition() );
continue;
} }
continue;
} }
// if either pad has no drill and is only on technical layers, not a clearance violation // if either pad has no drill and is only on technical layers, not a clearance violation
@ -642,34 +593,34 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D
continue; continue;
} }
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, for( PCB_LAYER_ID layer : aRefPad->GetLayerSet().Seq() )
aRefPad, pad );
auto minClearance = constraint.GetValue().Min();
accountCheck( constraint );
drc_dbg(4, "pad %p vs %p constraint %d\n", aRefPad, pad, minClearance );
int clearanceAllowed = minClearance - m_drcEngine->GetDesignSettings()->GetDRCEpsilon();
int actual;
auto refPadShape = aRefPad->GetEffectiveShape();
if( refPadShape->Collide( pad->GetEffectiveShape().get(), clearanceAllowed, &actual ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
wxString msg; aRefPad, pad, layer );
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), int minClearance = constraint.GetValue().Min();
/*m_clearanceSource fixme*/ "", int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
MessageTextFromValue( userUnits(), minClearance, true ), int actual;
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); accountCheck( constraint );
drcItem->SetItems( aRefPad, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, aRefPad->GetPosition() ); std::shared_ptr<SHAPE> refPadShape = aRefPad->GetEffectiveShape();
return false;
if( refPadShape->Collide( pad->GetEffectiveShape().get(), clearanceAllowed, &actual ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefPad, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, aRefPad->GetPosition() );
return false;
}
} }
} }
@ -677,7 +628,7 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D
} }
void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
{ {
// Test copper areas for valid netcodes -> fixme, goes to connectivity checks // Test copper areas for valid netcodes -> fixme, goes to connectivity checks
@ -727,7 +678,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
// Examine a candidate zone: compare zoneToTest to zoneRef // Examine a candidate zone: compare zoneToTest to zoneRef
// Get clearance used in zone to zone test. // Get clearance used in zone to zone test.
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_CLEARANCE,
zoneRef, zoneToTest ); zoneRef, zoneToTest );
int zone2zoneClearance = constraint.GetValue().Min(); int zone2zoneClearance = constraint.GetValue().Min();
@ -826,19 +777,17 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
else else
{ {
drcItem = DRC_ITEM::Create( DRCE_CLEARANCE ); drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
/* fixme */"", constraint.GetName(),
MessageTextFromValue( userUnits(), zone2zoneClearance, true ), MessageTextFromValue( userUnits(), zone2zoneClearance, true ),
MessageTextFromValue( userUnits(), conflict.second, true ) ); MessageTextFromValue( userUnits(), conflict.second, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
} }
drcItem->SetViolatingRule( constraint.GetParentRule() );
drcItem->SetItems( zoneRef, zoneToTest ); drcItem->SetItems( zoneRef, zoneToTest );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, conflict.first ); ReportWithMarker( drcItem, conflict.first );
} }
@ -847,7 +796,7 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
} }
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetMatchingConstraintIds() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetMatchingConstraintIds() const
{ {
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE };
} }
@ -855,5 +804,5 @@ std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetMat
namespace detail namespace detail
{ {
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_COPPER_CLEARANCE> dummy; static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_COPPER_CLEARANCE> dummy;
} }

View File

@ -23,21 +23,21 @@
#include <common.h> #include <common.h>
#include <class_board.h> #include <class_board.h>
#include <class_drawsegment.h> //#include <class_drawsegment.h>
#include <class_pad.h> //#include <class_pad.h>
#include <convert_basic_shapes_to_polygon.h> #include <convert_basic_shapes_to_polygon.h>
#include <geometry/polygon_test_point_inside.h> //#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h> //#include <geometry/seg.h>
#include <geometry/shape_poly_set.h> #include <geometry/shape_poly_set.h>
#include <geometry/shape_rect.h> //#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h> //#include <geometry/shape_segment.h>
#include <drc/drc_engine.h> #include <drc/drc_engine.h>
#include <drc/drc.h> #include <drc/drc.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
#include <drc_proto/drc_test_provider_clearance_base.h> #include <drc/drc_test_provider_clearance_base.h>
/* /*
Couartyard clearance. Tests for malformed component courtyards and overlapping footprints. Couartyard clearance. Tests for malformed component courtyards and overlapping footprints.
@ -50,8 +50,6 @@
as filled and allow open curves in the courtyard. as filled and allow open curves in the courtyard.
*/ */
namespace test {
class DRC_TEST_PROVIDER_COURTYARD_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE class DRC_TEST_PROVIDER_COURTYARD_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE
{ {
public: public:
@ -69,7 +67,7 @@ public:
virtual const wxString GetName() const override virtual const wxString GetName() const override
{ {
return "courtyard_clearance"; return "courtyard_clearance";
}; }
virtual const wxString GetDescription() const override virtual const wxString GetDescription() const override
{ {
@ -79,18 +77,15 @@ public:
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private: private:
void testFootprintCourtyardDefinitions(); void testFootprintCourtyardDefinitions();
void testOverlappingComponentCourtyards(); void testOverlappingComponentCourtyards();
};
}; };
void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions() void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions()
{ {
ReportStage( _("Testing component courtyard definitions"), 0, 2 ); ReportStage( _( "Testing component courtyard definitions" ), 0, 2 );
for( MODULE* footprint : m_board->Modules() ) for( MODULE* footprint : m_board->Modules() )
{ {
@ -103,9 +98,6 @@ void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefiniti
continue; continue;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD );
wxString msg;
msg.Printf( drcItem->GetErrorText( ));
drcItem->SetItems( footprint ); drcItem->SetItems( footprint );
ReportWithMarker( drcItem, footprint->GetPosition() ); ReportWithMarker( drcItem, footprint->GetPosition() );
@ -120,12 +112,11 @@ void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefiniti
{ {
if( !isErrorLimitExceeded( DRCE_MALFORMED_COURTYARD) ) if( !isErrorLimitExceeded( DRCE_MALFORMED_COURTYARD) )
{ {
wxString msg;
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD );
msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) ); m_msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( footprint ); drcItem->SetItems( footprint );
ReportWithMarker( drcItem, footprint->GetPosition() ); ReportWithMarker( drcItem, footprint->GetPosition() );
} }
@ -134,9 +125,9 @@ void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefiniti
} }
void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards() void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards()
{ {
ReportStage( _("Testing component courtyard overlap"), 0, 2 ); ReportStage( _( "Testing component courtyard overlap" ), 0, 2 );
for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ ) for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ )
{ {
@ -202,7 +193,7 @@ void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourty
} }
bool test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run() bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run()
{ {
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
@ -211,13 +202,14 @@ bool test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run()
//ReportAux( "Worst courtyard clearance : %d nm", m_largestClearance ); //ReportAux( "Worst courtyard clearance : %d nm", m_largestClearance );
testFootprintCourtyardDefinitions(); testFootprintCourtyardDefinitions();
testOverlappingComponentCourtyards(); testOverlappingComponentCourtyards();
return true; return true;
} }
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetMatchingConstraintIds() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetMatchingConstraintIds() const
{ {
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE };
} }
@ -225,5 +217,5 @@ std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Get
namespace detail namespace detail
{ {
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE> dummy; static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_COURTYARD_CLEARANCE> dummy;
} }

View File

@ -23,17 +23,13 @@
#include <common.h> #include <common.h>
#include <class_drawsegment.h> #include <class_drawsegment.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h> #include <geometry/seg.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <drc/drc_engine.h>
#include <pcbnew/drc/drc_engine.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
#include <drc/drc.h> #include <drc/drc.h>
#include <drc_proto/drc_test_provider_clearance_base.h> #include <drc/drc_test_provider_clearance_base.h>
/* /*
Board edge clearance test. Checks all items for their mechanical clearances against the board edge. Board edge clearance test. Checks all items for their mechanical clearances against the board edge.
@ -45,15 +41,13 @@
- tester only looks for edge crossings. it doesn't check if items are inside/outside the board area. - tester only looks for edge crossings. it doesn't check if items are inside/outside the board area.
*/ */
namespace test {
class DRC_TEST_PROVIDER_EDGE_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE class DRC_TEST_PROVIDER_EDGE_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE
{ {
public: public:
DRC_TEST_PROVIDER_EDGE_CLEARANCE () : DRC_TEST_PROVIDER_EDGE_CLEARANCE () :
DRC_TEST_PROVIDER_CLEARANCE_BASE() DRC_TEST_PROVIDER_CLEARANCE_BASE()
{ {
} }
virtual ~DRC_TEST_PROVIDER_EDGE_CLEARANCE() virtual ~DRC_TEST_PROVIDER_EDGE_CLEARANCE()
{ {
@ -64,7 +58,7 @@ public:
virtual const wxString GetName() const override virtual const wxString GetName() const override
{ {
return "edge_clearance"; return "edge_clearance";
}; }
virtual const wxString GetDescription() const override virtual const wxString GetDescription() const override
{ {
@ -72,20 +66,16 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override; virtual std::set<DRC_CONSTRAINT_TYPE_T> GetMatchingConstraintIds() const override;
private:
};
}; };
bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
{ {
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
DRC_CONSTRAINT worstClearanceConstraint; DRC_CONSTRAINT worstClearanceConstraint;
if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
{ {
m_largestClearance = worstClearanceConstraint.GetValue().Min(); m_largestClearance = worstClearanceConstraint.GetValue().Min();
@ -97,7 +87,8 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
} }
ReportAux( "Worst clearance : %d nm", m_largestClearance ); ReportAux( "Worst clearance : %d nm", m_largestClearance );
ReportStage( ("Testing all items <> Board Edge clearance"), 0, 2 );
ReportStage( _( "Testing all items <> Board Edge clearance" ), 0, 2 );
std::vector<DRAWSEGMENT*> boardOutline; std::vector<DRAWSEGMENT*> boardOutline;
std::vector<BOARD_ITEM*> boardItems; std::vector<BOARD_ITEM*> boardItems;
@ -124,37 +115,36 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
bool stop = false; bool stop = false;
for( auto outlineItem : boardOutline ) for( DRAWSEGMENT* outlineItem : boardOutline )
{ {
auto refShape = outlineItem->GetEffectiveShape(); const std::shared_ptr<SHAPE>& refShape = outlineItem->GetEffectiveShape();
for( auto boardItem : boardItems ) for( BOARD_ITEM* boardItem : boardItems )
{ {
drc_dbg( 10, "RefT %d %p %s %d\n", outlineItem->Type(), outlineItem, drc_dbg( 10, "RefT %d %p %s %d\n", outlineItem->Type(), outlineItem,
outlineItem->GetClass(), outlineItem->GetLayer() ); outlineItem->GetClass(), outlineItem->GetLayer() );
drc_dbg( 10, "BoardT %d %p %s %d\n", boardItem->Type(), boardItem, drc_dbg( 10, "BoardT %d %p %s %d\n", boardItem->Type(), boardItem,
boardItem->GetClass(), boardItem->GetLayer() ); boardItem->GetClass(), boardItem->GetLayer() );
auto shape = boardItem->GetEffectiveShape(); const std::shared_ptr<SHAPE>& shape = boardItem->GetEffectiveShape();
DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE,
outlineItem, boardItem ); outlineItem, boardItem );
int minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
int actual; int actual;
accountCheck( constraint ); accountCheck( constraint );
if( refShape->Collide( shape.get(), minClearance, &actual ) ) if( refShape->Collide( shape.get(), minClearance, &actual ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
constraint.GetParentRule()->m_Name, constraint.GetName(),
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( outlineItem, boardItem ); drcItem->SetItems( outlineItem, boardItem );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -178,7 +168,7 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
} }
std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const std::set<DRC_CONSTRAINT_TYPE_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const
{ {
return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE }; return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE };
} }
@ -186,5 +176,5 @@ std::set<DRC_CONSTRAINT_TYPE_T> test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatch
namespace detail namespace detail
{ {
static DRC_REGISTER_TEST_PROVIDER<test::DRC_TEST_PROVIDER_EDGE_CLEARANCE> dummy; static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_EDGE_CLEARANCE> dummy;
} }

View File

@ -22,20 +22,14 @@
*/ */
#include <common.h> #include <common.h>
#include <class_board.h>
#include <class_drawsegment.h> #include <class_drawsegment.h>
#include <class_pad.h> #include <class_pad.h>
#include <geometry/polygon_test_point_inside.h>
#include <geometry/seg.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <drc/drc_engine.h> #include <drc/drc_engine.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
#include <drc/drc.h> #include <drc/drc.h>
#include <drc_proto/drc_test_provider_clearance_base.h> #include <drc/drc_test_provider_clearance_base.h>
/* /*
Holes clearance test. Checks pad and via holes for their mechanical clearances. Holes clearance test. Checks pad and via holes for their mechanical clearances.
@ -78,7 +72,7 @@ public:
private: private:
void addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner ); void addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner );
void buildHoleList(); void buildDrilledHoleList();
void testHoles2Holes(); void testHoles2Holes();
void testPads2Holes(); void testPads2Holes();
@ -92,7 +86,7 @@ private:
}; };
BOARD* m_board; BOARD* m_board;
std::vector<DRILLED_HOLE> m_holes; std::vector<DRILLED_HOLE> m_drilledHoles;
int m_largestRadius; int m_largestRadius;
}; };
@ -102,7 +96,6 @@ private:
bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run() bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run()
{ {
auto bds = m_drcEngine->GetDesignSettings();
m_board = m_drcEngine->GetBoard(); m_board = m_drcEngine->GetBoard();
m_largestClearance = 0; m_largestClearance = 0;
@ -110,25 +103,25 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run()
DRC_CONSTRAINT worstClearanceConstraint; DRC_CONSTRAINT worstClearanceConstraint;
if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE, if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE,
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
{ {
m_largestClearance = worstClearanceConstraint.GetValue().Min(); m_largestClearance = worstClearanceConstraint.GetValue().Min();
} }
else else
{ {
ReportAux("No Clearance constraints found..."); ReportAux( "No Clearance constraints found..." );
return false; return false;
} }
ReportAux( "Worst hole clearance : %d nm", m_largestClearance ); ReportAux( "Worst hole clearance : %d nm", m_largestClearance );
buildHoleList(); buildDrilledHoleList();
ReportStage( ("Testing hole<->pad clearances"), 0, 2 ); ReportStage( _( "Testing hole<->pad clearances" ), 0, 2 );
testPads2Holes(); testPads2Holes();
ReportStage( ("Testing hole<->hole clearances"), 0, 2 );
ReportStage( _( "Testing hole<->hole clearances" ), 0, 2 );
testHoles2Holes(); testHoles2Holes();
reportRuleStatistics(); reportRuleStatistics();
@ -137,44 +130,45 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::Run()
} }
void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::buildHoleList() void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::buildDrilledHoleList()
{ {
bool success = true; bool success = true;
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
m_holes.clear(); m_drilledHoles.clear();
for( auto module : m_board->Modules() ) for( MODULE* module : m_board->Modules() )
{ {
for( auto pad : module->Pads() ) for( D_PAD* pad : module->Pads() )
{ {
int holeSize = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y ); int holeSize = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y );
if( holeSize == 0 ) if( holeSize == 0 )
continue; continue;
// fixme: support for non-round (i.e. slotted) holes // Milled holes (slots) aren't required to meet the minimum hole-to-hole
// distance, so we only have to collect the drilled holes.
if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ) if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
addHole( pad->GetPosition(), pad->GetDrillSize().x / 2, pad ); addHole( pad->GetPosition(), pad->GetDrillSize().x / 2, pad );
} }
} }
for( auto track : m_board->Tracks() ) for( TRACK* track : m_board->Tracks() )
{ {
if ( track->Type() == PCB_VIA_T ) if ( track->Type() == PCB_VIA_T )
{ {
auto via = static_cast<VIA*>( track ); VIA* via = static_cast<VIA*>( track );
addHole( via->GetPosition(), via->GetDrillValue() / 2, via ); addHole( via->GetPosition(), via->GetDrillValue() / 2, via );
} }
} }
ReportAux( "Total drilled holes : %d", m_holes.size() ); ReportAux( "Total drilled holes : %d", m_drilledHoles.size() );
} }
void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes() void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes()
{ {
std::vector<D_PAD*> sortedPads; std::vector<D_PAD*> sortedPads;
m_board->GetSortedPadListByXthenYCoord( sortedPads ); m_board->GetSortedPadListByXthenYCoord( sortedPads );
@ -201,23 +195,24 @@ void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testPads2Holes()
D_PAD** listEnd = &sortedPads[0] + sortedPads.size(); D_PAD** listEnd = &sortedPads[0] + sortedPads.size();
// Test the pads // Test the pads
for( auto& pad : sortedPads ) for( D_PAD* pad : sortedPads )
{ {
int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size; int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size;
drc_dbg(10,"-> %p\n", pad);
drc_dbg( 10,"-> %p\n", pad );
doPadToPadHoleDrc( pad, &pad, listEnd, x_limit ); doPadToPadHoleDrc( pad, &pad, listEnd, x_limit );
} }
} }
bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad, D_PAD** aStart,
int x_limit ) D_PAD** aEnd, int x_limit )
{ {
const static LSET all_cu = LSET::AllCuMask(); const static LSET all_cu = LSET::AllCuMask();
LSET layerMask = aRefPad->GetLayerSet() & all_cu; LSET layerMask = aRefPad->GetLayerSet() & all_cu;
for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list ) for( D_PAD** pad_list = aStart; pad_list<aEnd; ++pad_list )
{ {
D_PAD* pad = *pad_list; D_PAD* pad = *pad_list;
@ -225,18 +220,18 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
if( pad == aRefPad ) if( pad == aRefPad )
continue; continue;
// drc_dbg(10," chk against -> %p\n", pad);
// We can stop the test when pad->GetPosition().x > x_limit because the list is
// drc_dbg(10," chk against -> %p\n", pad); // sorted by X values
// We can stop the test when pad->GetPosition().x > x_limit
// because the list is sorted by X values
if( pad->GetPosition().x > x_limit ) if( pad->GetPosition().x > x_limit )
break; break;
// drc_dbg(10," chk2 against -> %p ds %d %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x ); // drc_dbg( 10," chk2 against -> %p ds %d %d\n",
// pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
drc_dbg(10," chk1 against -> %p x0 %d x2 %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x ); drc_dbg( 10," chk1 against -> %p x0 %d x2 %d\n",
pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
// No problem if pads which are on copper layers are on different copper layers, // No problem if pads which are on copper layers are on different copper layers,
// (pads can be only on a technical layer, to build complex pads) // (pads can be only on a technical layer, to build complex pads)
@ -246,7 +241,6 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
( pad->GetLayerSet() & all_cu ) != 0 && ( pad->GetLayerSet() & all_cu ) != 0 &&
( aRefPad->GetLayerSet() & all_cu ) != 0 ) ( aRefPad->GetLayerSet() & all_cu ) != 0 )
{ {
// if holes are in the same location and have the same size and shape, // if holes are in the same location and have the same size and shape,
// this can be accepted // this can be accepted
if( pad->GetPosition() == aRefPad->GetPosition() if( pad->GetPosition() == aRefPad->GetPosition()
@ -263,37 +257,31 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
drc_dbg(10," chk3 against -> %p x0 %d x2 %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x ); drc_dbg(10," chk3 against -> %p x0 %d x2 %d\n", pad, pad->GetDrillSize().x, aRefPad->GetDrillSize().x );
/* Here, we must test clearance between holes and pads if( pad->GetDrillSize().x ) // test pad has a hole
* pad size and shape is adjusted to pad drill size and shape
*/
if( pad->GetDrillSize().x )
{ {
// pad under testing has a hole, test this hole against pad reference auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE,
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE,
aRefPad, pad ); aRefPad, pad );
auto minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
int actual; int actual;
drc_dbg( 10, "check pad %p rule '%s' cl %d\n", drc_dbg( 10, "check pad %p rule '%s' cl %d\n",
pad, constraint.GetParentRule()->m_Name, minClearance ); pad, constraint.GetParentRule()->m_Name, minClearance );
accountCheck( constraint.GetParentRule() ); accountCheck( constraint.GetParentRule() );
auto refPadShape = aRefPad->GetEffectiveShape(); const std::shared_ptr<SHAPE>& refPadShape = aRefPad->GetEffectiveShape();
// fixme: pad stacks... // fixme: pad stacks...
if( refPadShape->Collide( pad->GetEffectiveHoleShape(), minClearance, &actual ) ) if( refPadShape->Collide( pad->GetEffectiveHoleShape(), minClearance, &actual ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
wxString msg; m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
constraint.GetName(),
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
"",
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( pad, aRefPad ); drcItem->SetItems( pad, aRefPad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -302,31 +290,31 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
} }
} }
if( aRefPad->GetDrillSize().x ) // pad reference has a hole if( aRefPad->GetDrillSize().x ) // reference pad has a hole
{ {
auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE,
aRefPad, pad ); aRefPad, pad );
auto minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
int actual; int actual;
accountCheck( constraint.GetParentRule() ); accountCheck( constraint.GetParentRule() );
drc_dbg( 10,"check pad %p rule '%s' cl %d\n", aRefPad, drc_dbg( 10,"check pad %p rule '%s' cl %d\n", aRefPad,
constraint.GetParentRule()->m_Name, minClearance ); constraint.GetParentRule()->m_Name, minClearance );
auto padShape = pad->GetEffectiveShape(); const std::shared_ptr<SHAPE>& padShape = pad->GetEffectiveShape();
if( padShape->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) ) if( padShape->Collide( aRefPad->GetEffectiveHoleShape(), minClearance, &actual ) )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
"", constraint.GetName(),
MessageTextFromValue( userUnits(), minClearance, true ), MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetErrorMessage( msg ); drcItem->SetErrorMessage( m_msg );
drcItem->SetItems( aRefPad, pad ); drcItem->SetItems( aRefPad, pad );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetViolatingRule( constraint.GetParentRule() );
@ -341,7 +329,8 @@ bool test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::doPadToPadHoleDrc( D_PAD* aRefPad,
} }
void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::addHole( const VECTOR2I& aLocation, int aRadius, BOARD_ITEM* aOwner ) void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::addHole( const VECTOR2I& aLocation, int aRadius,
BOARD_ITEM* aOwner )
{ {
DRILLED_HOLE hole; DRILLED_HOLE hole;
@ -351,20 +340,17 @@ void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::addHole( const VECTOR2I& aLocation,
m_largestRadius = std::max( m_largestRadius, aRadius ); m_largestRadius = std::max( m_largestRadius, aRadius );
m_holes.push_back( hole ); m_drilledHoles.push_back( hole );
} }
void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes() void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes()
{ {
// No need to check if we're ignoring DRCE_DRILLED_HOLES_TOO_CLOSE; if we are then we
// won't have collected any holes to test.
// Sort holes by X for performance. In the nested iteration we then need to look at // Sort holes by X for performance. In the nested iteration we then need to look at
// following holes only while they are within the refHole's neighborhood as defined by // following holes only while they are within the refHole's neighborhood as defined by
// the refHole radius + the minimum hole-to-hole clearance + the largest radius any of // the refHole radius + the minimum hole-to-hole clearance + the largest radius any of
// the following holes can have. // the following holes can have.
std::sort( m_holes.begin(), m_holes.end(), std::sort( m_drilledHoles.begin(), m_drilledHoles.end(),
[]( const DRILLED_HOLE& a, const DRILLED_HOLE& b ) []( const DRILLED_HOLE& a, const DRILLED_HOLE& b )
{ {
if( a.m_location.x == b.m_location.x ) if( a.m_location.x == b.m_location.x )
@ -373,14 +359,14 @@ void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes()
return a.m_location.x < b.m_location.x; return a.m_location.x < b.m_location.x;
} ); } );
for( size_t ii = 0; ii < m_holes.size(); ++ii ) for( size_t ii = 0; ii < m_drilledHoles.size(); ++ii )
{ {
DRILLED_HOLE& refHole = m_holes[ ii ]; DRILLED_HOLE& refHole = m_drilledHoles[ ii ];
int neighborhood = refHole.m_drillRadius + m_largestClearance + m_largestRadius; int neighborhood = refHole.m_drillRadius + m_largestClearance + m_largestRadius;
for( size_t jj = ii + 1; jj < m_holes.size(); ++jj ) for( size_t jj = ii + 1; jj < m_drilledHoles.size(); ++jj )
{ {
DRILLED_HOLE& checkHole = m_holes[ jj ]; DRILLED_HOLE& checkHole = m_drilledHoles[ jj ];
if( refHole.m_location.x + neighborhood < checkHole.m_location.x ) if( refHole.m_location.x + neighborhood < checkHole.m_location.x )
break; break;
@ -392,28 +378,28 @@ void test::DRC_TEST_PROVIDER_HOLE_CLEARANCE::testHoles2Holes()
int actual = ( checkHole.m_location - refHole.m_location ).EuclideanNorm(); int actual = ( checkHole.m_location - refHole.m_location ).EuclideanNorm();
actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius ); actual = std::max( 0, actual - checkHole.m_drillRadius - refHole.m_drillRadius );
DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE, auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE,
refHole.m_owner, checkHole.m_owner ); refHole.m_owner, checkHole.m_owner );
int minClearance = constraint.GetValue().Min(); int minClearance = constraint.GetValue().Min();
accountCheck( constraint.GetParentRule() ); accountCheck( constraint.GetParentRule() );
if( actual < minClearance ) if( actual < minClearance )
{ {
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_HOLE_CLEARANCE ); std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DRILLED_HOLES_TOO_CLOSE );
wxString msg;
msg.Printf( drcItem->GetErrorText() + _( " (clearance %s; actual %s)" ), m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
MessageTextFromValue( userUnits(), minClearance, true ), constraint.GetName(),
MessageTextFromValue( userUnits(), actual, true ) ); MessageTextFromValue( userUnits(), minClearance, true ),
MessageTextFromValue( userUnits(), actual, true ) );
drcItem->SetViolatingRule( constraint.GetParentRule() ); drcItem->SetErrorMessage( m_msg );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( refHole.m_owner, checkHole.m_owner ); drcItem->SetItems( refHole.m_owner, checkHole.m_owner );
drcItem->SetViolatingRule( constraint.GetParentRule() );
ReportWithMarker( drcItem, refHole.m_location ); ReportWithMarker( drcItem, refHole.m_location );
if( isErrorLimitExceeded( DRCE_HOLE_CLEARANCE ) ) if( isErrorLimitExceeded( DRCE_DRILLED_HOLES_TOO_CLOSE ) )
return; return;
} }
} }

View File

@ -39,16 +39,16 @@ add_executable( drc_proto
../../pcbnew/drc/drc_rule.cpp ../../pcbnew/drc/drc_rule.cpp
../../pcbnew/drc/drc_rule_parser.cpp ../../pcbnew/drc/drc_rule_parser.cpp
../../pcbnew/drc/drc_test_provider.cpp ../../pcbnew/drc/drc_test_provider.cpp
drc_test_provider_clearance_base.cpp ../../pcbnew/drc/drc_test_provider_clearance_base.cpp
drc_test_provider_copper_clearance.cpp ../../pcbnew/drc/drc_test_provider_copper_clearance.cpp
drc_test_provider_hole_clearance.cpp ../../pcbnew/drc/drc_test_provider_hole_clearance.cpp
drc_test_provider_edge_clearance.cpp ../../pcbnew/drc/drc_test_provider_edge_clearance.cpp
drc_test_provider_hole_size.cpp drc_test_provider_hole_size.cpp
drc_test_provider_disallow.cpp drc_test_provider_disallow.cpp
drc_test_provider_track_width.cpp drc_test_provider_track_width.cpp
drc_test_provider_annulus.cpp drc_test_provider_annulus.cpp
drc_test_provider_connectivity.cpp drc_test_provider_connectivity.cpp
drc_test_provider_courtyard_clearance.cpp ../../pcbnew/drc/drc_test_provider_courtyard_clearance.cpp
drc_test_provider_via_diameter.cpp drc_test_provider_via_diameter.cpp
drc_test_provider_lvs.cpp drc_test_provider_lvs.cpp
drc_test_provider_misc.cpp drc_test_provider_misc.cpp

View File

@ -37,7 +37,7 @@
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
#include <drc/drc.h> #include <drc/drc.h>
#include <drc_proto/drc_test_provider_clearance_base.h> #include <pcbnew/drc/drc_test_provider_clearance_base.h>
/* /*

View File

@ -37,7 +37,7 @@
#include <drc/drc.h> #include <drc/drc.h>
#include <drc/drc_item.h> #include <drc/drc_item.h>
#include <drc/drc_rule.h> #include <drc/drc_rule.h>
#include <drc_proto/drc_test_provider_clearance_base.h> #include <pcbnew/drc/drc_test_provider_clearance_base.h>
/* /*
Silk to pads clearance test. Check all pads against silkscreen (mask opening in the pad vs silkscreen) Silk to pads clearance test. Check all pads against silkscreen (mask opening in the pad vs silkscreen)
@ -88,7 +88,7 @@ bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run()
DRC_CONSTRAINT worstClearanceConstraint; DRC_CONSTRAINT worstClearanceConstraint;
m_largestClearance = 0; m_largestClearance = 0;
if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_SILK_TO_PAD, if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_PAD,
worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) )
{ {
m_largestClearance = worstClearanceConstraint.m_Value.Min(); m_largestClearance = worstClearanceConstraint.m_Value.Min();