diff --git a/qa/CMakeLists.txt b/qa/CMakeLists.txt index 4dc8336668..8167bd1bee 100644 --- a/qa/CMakeLists.txt +++ b/qa/CMakeLists.txt @@ -54,6 +54,7 @@ add_subdirectory( eeschema ) add_subdirectory( libs ) add_subdirectory( utils/kicad2step ) add_subdirectory( libeval_compiler ) +add_subdirectory( drc_proto ) # Utility/debugging/profiling programs add_subdirectory( common_tools ) diff --git a/qa/drc_proto/drc_clearance_test.cpp b/qa/drc_proto/drc_clearance_test.cpp index 1db010e23a..6171035811 100644 --- a/qa/drc_proto/drc_clearance_test.cpp +++ b/qa/drc_proto/drc_clearance_test.cpp @@ -20,8 +20,8 @@ namespace test { class DRC_TEST_PROVIDER_CLEARANCE : public DRC_TEST_PROVIDER { public: - DRC_TEST_PROVIDER_CLEARANCE ( DRC_ENGINE *aDrc ) : - DRC_TEST_PROVIDER( aDrc ) + DRC_TEST_PROVIDER_CLEARANCE () : + DRC_TEST_PROVIDER() { } @@ -38,7 +38,11 @@ public: virtual std::set GetMatchingRuleIds() const override; private: - void testPadClearances( ); + void testPadClearances(); + void testTrackClearances(); + + void doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, + TRACKS::iterator aEndIt, bool aTestZones ); 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, @@ -49,6 +53,8 @@ private: bool poly2polyDRC( wxPoint* aTref, int aTrefCount, wxPoint* aTtest, int aTtestCount, int aAllowedDist, int* actualDist ); + wxPoint getLocation( TRACK* aTrack, const SEG& aConflictSeg ); + BOARD* m_board; int m_largestClearance; SHAPE_POLY_SET m_boardOutline; // The board outline including cutouts @@ -59,6 +65,27 @@ private: }; +const int UI_EPSILON = Mils2iu( 5 ); + +wxPoint test::DRC_TEST_PROVIDER_CLEARANCE::getLocation( TRACK* aTrack, const SEG& aConflictSeg ) +{ + wxPoint pt1 = aTrack->GetPosition(); + wxPoint pt2 = aTrack->GetEnd(); + + // Do a binary search along the track for a "good enough" marker location + while( GetLineLength( pt1, pt2 ) > UI_EPSILON ) + { + if( aConflictSeg.SquaredDistance( pt1 ) < aConflictSeg.SquaredDistance( pt2 ) ) + pt2 = ( pt1 + pt2 ) / 2; + else + pt1 = ( pt1 + pt2 ) / 2; + } + + // Once we're within UI_EPSILON pt1 and pt2 are "equivalent" + return pt1; +} + + bool test::DRC_TEST_PROVIDER_CLEARANCE::Run() { auto bds = m_drcEngine->GetDesignSettings(); @@ -66,11 +93,271 @@ bool test::DRC_TEST_PROVIDER_CLEARANCE::Run() m_board = m_drcEngine->GetBoard(); m_largestClearance = bds->GetBiggestClearanceValue(); + ReportStage(_("Testing pad copper clerances"), 0, 2 ); testPadClearances(); + ReportStage(_("Testing track/via copper clerances"), 0, 2 ); + testTrackClearances(); - return false; + return true; } +void test::DRC_TEST_PROVIDER_CLEARANCE::testTrackClearances() +{ + const int delta = 500; // This is the number of tests between 2 calls to the + // progress bar + int count = m_board->Tracks().size(); + int deltamax = count/delta; + + ReportProgress(0.0); + + int ii = 0; + count = 0; + + for( auto seg_it = m_board->Tracks().begin(); seg_it != m_board->Tracks().end(); seg_it++ ) + { + if( ii++ > delta ) + { + ii = 0; + count++; + + ReportProgress( (double) ii / (double ) count ); + } + + // Test new segment against tracks and pads, optionally against copper zones + doTrackDrc( *seg_it, seg_it + 1, m_board->Tracks().end(), true ); + } +} + +void test::DRC_TEST_PROVIDER_CLEARANCE::doTrackDrc( TRACK* aRefSeg, TRACKS::iterator aStartIt, + TRACKS::iterator aEndIt, bool aTestZones ) +{ + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + + SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); + PCB_LAYER_ID refLayer = aRefSeg->GetLayer(); + LSET refLayerSet = aRefSeg->GetLayerSet(); + + 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 : */ + /******************************************/ + + // Compute the min distance to pads + for( MODULE* mod : m_board->Modules() ) + { + // Don't preflight at the module level. Getting a module's bounding box goes + // through all its pads anyway (so it's no faster), and also all its drawings + // (so it's in fact slower). + + for( D_PAD* pad : mod->Pads() ) + { + // Preflight based on bounding boxes. + EDA_RECT inflatedBB = refSegBB; + inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance ); + + if( !inflatedBB.Contains( pad->GetPosition() ) ) + continue; + + if( !( pad->GetLayerSet() & refLayerSet ).any() ) + continue; + + // No need to check pads with the same net as the refSeg. + if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() ) + continue; + + // fixme: hole to hole clearance moved elsewhere + + auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aRefSeg, pad ); + auto minClearance = rule->GetConstraint().GetValue().Min(); + int clearanceAllowed = minClearance - bds.GetDRCEpsilon(); + int actual; + + if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) ) + { + actual = std::max( 0, actual ); + SEG padSeg( pad->GetPosition(), pad->GetPosition() ); + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_PAD ); + + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + /*m_clearanceSource fixme*/ "", + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( aRefSeg, pad ); + + ReportWithMarker( drcItem, rule, getLocation( aRefSeg, padSeg ) ); + + if( isErrorLimitExceeded( DRCE_TRACK_NEAR_PAD ) ) + return; + } + } + } + + /***********************************************/ + /* Phase 2: test DRC with other track segments */ + /***********************************************/ + + // Test the reference segment with other track segments + for( auto it = aStartIt; it != aEndIt; it++ ) + { + TRACK* track = *it; + + // No problem if segments have the same net code: + if( aRefSeg->GetNetCode() == track->GetNetCode() ) + continue; + + // No problem if tracks are on different layers: + // 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; + + // Preflight based on worst-case inflated bounding boxes: + EDA_RECT trackBB = track->GetBoundingBox(); + trackBB.Inflate( m_largestClearance ); + + if( !trackBB.Intersects( refSegBB ) ) + continue; + + auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aRefSeg, track ); + auto minClearance = rule->GetConstraint().GetValue().Min(); + + SEG trackSeg( track->GetStart(), track->GetEnd() ); + int widths = ( refSegWidth + track->GetWidth() ) / 2; + int center2centerAllowed = minClearance + widths; + + // Avoid square-roots if possible (for performance) + SEG::ecoord center2center_squared = refSeg.SquaredDistance( trackSeg ); + OPT_VECTOR2I intersection = refSeg.Intersect( trackSeg ); + + // Check two tracks crossing first as it reports a DRCE without distances + if( intersection ) + { + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACKS_CROSSING ); + + // fixme + drcItem->SetErrorMessage( "FIXME" ); + drcItem->SetItems( aRefSeg, track ); + + ReportWithMarker( drcItem, rule, (wxPoint) intersection.get() ); + + if( isErrorLimitExceeded( DRCE_TRACKS_CROSSING ) ) + return; + } + else if( center2center_squared < SEG::Square( center2centerAllowed ) ) + { + int errorCode = DRCE_TRACK_ENDS; + + if( aRefSeg->Type() == PCB_VIA_T && track->Type() == PCB_VIA_T ) + errorCode = DRCE_VIA_NEAR_VIA; + else if( aRefSeg->Type() == PCB_VIA_T || track->Type() == PCB_VIA_T ) + errorCode = DRCE_VIA_NEAR_TRACK; + else if( refSeg.ApproxParallel( trackSeg ) ) + errorCode = DRCE_TRACK_SEGMENTS_TOO_CLOSE; + + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); + DRC_ITEM* drcItem = new DRC_ITEM( errorCode ); + + wxString msg; + msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + /*m_clearanceSource fixme*/"", + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( aRefSeg, track ); + + ReportWithMarker( drcItem, rule, getLocation( aRefSeg, trackSeg ) ); + + if( isErrorLimitExceeded( errorCode ) ) + return; + } + } + + #if 0 + + /***************************************/ + /* Phase 3: test DRC with copper zones */ + /***************************************/ + // Can be *very* time consumming. + if( aTestZones ) + { + SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() ); + + for( ZONE_CONTAINER* zone : m_pcb->Zones() ) + { + if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() ) + continue; + + if( !( refLayerSet & zone->GetLayerSet() ).any() ) + continue; + + if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() ) + continue; + + int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource ); + int widths = refSegWidth / 2; + int center2centerAllowed = minClearance + widths; + SHAPE_POLY_SET* outline = const_cast( &zone->GetFilledPolysList() ); + + SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg ); + + // 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 ) + + if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) ) + { + int actual = std::max( 0.0, sqrt( center2center_squared ) - widths ); + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_ZONE ); + + m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + m_clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( m_msg ); + drcItem->SetItems( aRefSeg, zone ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) ); + addMarkerToPcb( aCommit, marker ); + } + } + } +#endif + +// fixme: board edge clearance to another rule +} void test::DRC_TEST_PROVIDER_CLEARANCE::testPadClearances( ) @@ -80,6 +367,10 @@ void test::DRC_TEST_PROVIDER_CLEARANCE::testPadClearances( ) m_board->GetSortedPadListByXthenYCoord( sortedPads ); + //Report("testing pads: %d pads\n", sortedPads.size() ); + + for( auto p : sortedPads ) + if( sortedPads.empty() ) return; @@ -102,10 +393,14 @@ void test::DRC_TEST_PROVIDER_CLEARANCE::testPadClearances( ) // Upper limit of pad list (limit not included) D_PAD** listEnd = &sortedPads[0] + sortedPads.size(); + int ii = 0; // Test the pads for( auto& pad : sortedPads ) { + if( ii % 100 == 0 ) + ReportProgress( (double) ii / (double) sortedPads.size() ); + ii++; #if 0 // fixme: move Board outline clearance to separate provider if( m_boardOutlineValid ) @@ -192,7 +487,7 @@ bool test::DRC_TEST_PROVIDER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** // fixme move hole clearance check to another provider // 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 p on a technical layer, to build complex pads) // but their hole (if any ) can create DRC error because they are on all // copper layers, so we test them if( ( pad->GetLayerSet() & layerMask ) == 0 && @@ -314,10 +609,10 @@ bool test::DRC_TEST_PROVIDER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** continue; } - auto constraint = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aRefPad, pad ); + auto rule = m_drcEngine->EvalRulesForItems( test::DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE, aRefPad, pad ); + auto minClearance = rule->GetConstraint().GetValue().Min(); - //int minClearance = aRefPad->GetClearance( pad, *&m_clearanceSource ); - int minClearance; // fixme + drc_dbg(4, "pad %p vs %p constraint %d\n", aRefPad, pad, minClearance ); int clearanceAllowed = minClearance - m_drcEngine->GetDesignSettings()->GetDRCEpsilon(); int actual; @@ -334,9 +629,7 @@ bool test::DRC_TEST_PROVIDER_CLEARANCE::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** drcItem->SetErrorMessage( msg ); drcItem->SetItems( aRefPad, pad ); - MARKER_PCB* marker = nullptr; // fixme new MARKER_PCB( drcItem, aRefPad->GetPosition() ); - AddMarkerToPcb( marker ); - + ReportWithMarker( drcItem, rule, aRefPad->GetPosition() ); return false; } } @@ -752,7 +1045,8 @@ std::set test::DRC_TEST_PROVIDER_CLEARANCE::GetMatchingRule return { DRC_RULE_ID_T::DRC_RULE_ID_CLEARANCE }; } -test::DRC_TEST_PROVIDER *drcCreateClearanceTestProvider( test::DRC_ENGINE *engine ) + +namespace detail { - return new test::DRC_TEST_PROVIDER_CLEARANCE( engine ); + static test::DRC_REGISTER_TEST_PROVIDER dummy; } \ No newline at end of file diff --git a/qa/drc_proto/drc_engine.cpp b/qa/drc_proto/drc_engine.cpp index afd067f347..7826ab5700 100644 --- a/qa/drc_proto/drc_engine.cpp +++ b/qa/drc_proto/drc_engine.cpp @@ -121,10 +121,6 @@ bool test::DRC_ENGINE::LoadRules( wxFileName aPath ) test::DRC_TEST_PROVIDER *drcCreateClearanceTestProvider( test::DRC_ENGINE *engine ); -void test::DRC_ENGINE::loadTestProviders() -{ - m_testProviders.push_back( drcCreateClearanceTestProvider( this ) ); -} void test::DRC_ENGINE::inferImplicitRules() @@ -133,10 +129,12 @@ void test::DRC_ENGINE::inferImplicitRules() } -static void drc_dbg( int level, const char* fmt, ... ) +static const int drc_debug_level = 0; + +void test::drc_dbg( int level, const char* fmt, ... ) { #ifdef DEBUG - if(level < 10) // fixme: tom's debugging. + if(level < drc_debug_level) // fixme: tom's debugging. { va_list ap; va_start( ap, fmt ); @@ -161,6 +159,7 @@ bool test::DRC_ENGINE::CompileRules() m_ruleMap[id] = new RULE_SET; m_ruleMap[ id ]->provider = provider; + m_ruleMap[ id ]->defaultRule = nullptr; for( auto rule : m_rules ) { @@ -171,6 +170,12 @@ bool test::DRC_ENGINE::CompileRules() { auto rcons = new RULE_WITH_CONDITIONS; + if( rule->GetPriority() == 0 ) + { + m_ruleMap[ id ]->defaultRule = rule; + continue; + } + for( auto condition : m_ruleConditions ) { if( condition->m_TargetRuleName == rule->GetName() ) @@ -200,20 +205,48 @@ void test::DRC_ENGINE::RunTests( ) { //m_largestClearance = m_designSettings->GetBiggestClearanceValue(); - loadTestProviders(); + m_testProviders = DRC_TEST_PROVIDER_REGISTRY::Instance().GetTestProviders(); + + for( auto provider : m_testProviders ) + provider->SetDRCEngine( this ); + inferImplicitRules(); CompileRules(); + for( auto provider : m_testProviders ) + { + drc_dbg(0, "Running test provider: '%s'\n", (const char *) provider->GetName().c_str() ); + provider->Run(); + } } -test::DRC_CONSTRAINT test::DRC_ENGINE::EvalRulesForItems( test::DRC_RULE_ID_T ruleID, const BOARD_ITEM* a, const BOARD_ITEM* b ) +test::DRC_RULE* test::DRC_ENGINE::EvalRulesForItems( test::DRC_RULE_ID_T ruleID, BOARD_ITEM* a, BOARD_ITEM* b ) { - test::DRC_CONSTRAINT rv; + test::DRC_RULE* rv; auto ruleset = m_ruleMap[ ruleID ]; + for( auto rcond : ruleset->sortedRules ) + { + for( auto condition : rcond->conditions ) + { + bool result = condition->EvaluateFor( a, b ); + if( result ) + { + drc_dbg(8, " -> rule '%s' matches, triggered by condition '%s'\n", (const char*) rcond->rule->m_Name.c_str(), (const char*) condition->m_Expression ); + return rcond->rule; + } + } + } - return rv; + if( ruleset->defaultRule ) + { + drc_dbg(8, " -> default rule '%s' matches\n", (const char*) ruleset->defaultRule->m_Name.c_str() ); + return ruleset->defaultRule; + } + + assert(false); // should never hapen + return nullptr; } diff --git a/qa/drc_proto/drc_engine.h b/qa/drc_proto/drc_engine.h index 58f316f4b2..fc19f47f4d 100644 --- a/qa/drc_proto/drc_engine.h +++ b/qa/drc_proto/drc_engine.h @@ -51,10 +51,8 @@ class NETCLASS; class EDA_TEXT; class DRAWSEGMENT; class NETLIST; -class wxWindow; -class wxString; -class wxTextCtrl; class PROGRESS_REPORTER; +class REPORTER; namespace test { @@ -181,10 +179,8 @@ public: return m_board; } - DRC_CONSTRAINT EvalRulesForItems( - DRC_RULE_ID_T ruleID, const BOARD_ITEM* a, const BOARD_ITEM* b = nullptr ); - - //void IterateOverMatchingRules( DRC_RULE_ID_IT ruleID ); + DRC_RULE* EvalRulesForItems( + DRC_RULE_ID_T ruleID, BOARD_ITEM* a, BOARD_ITEM* b = nullptr ); EDA_UNITS UserUnits() const { @@ -204,6 +200,7 @@ private: struct RULE_SET { std::vector sortedRules; + DRC_RULE* defaultRule; DRC_TEST_PROVIDER* provider; }; @@ -220,12 +217,16 @@ private: std::vector m_ruleConditions; std::vector m_rules; std::vector m_testProviders; + std::unordered_map m_implicitRules; std::vector<::MARKER_PCB*> m_markers; RULE_MAP m_ruleMap; + REPORTER* m_reporter; + PROGRESS_REPORTER* m_progressReporter; // condition -> rule -> provider }; +void drc_dbg( int level, const char* fmt, ... ); }; // namespace test diff --git a/qa/drc_proto/drc_proto_test.cpp b/qa/drc_proto/drc_proto_test.cpp index 7f9304a0fd..8ea0439cfe 100644 --- a/qa/drc_proto/drc_proto_test.cpp +++ b/qa/drc_proto/drc_proto_test.cpp @@ -12,6 +12,9 @@ int main( int argc, char *argv[] ) { + PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); + propMgr.Rebuild(); + auto brd = KI_TEST::ReadBoardFromFileOrStream(argv[1]); test::DRC_ENGINE drcEngine( brd.get(), &brd->GetDesignSettings() ); diff --git a/qa/drc_proto/drc_rule.cpp b/qa/drc_proto/drc_rule.cpp index b6fafb8a83..fa232c5002 100644 --- a/qa/drc_proto/drc_rule.cpp +++ b/qa/drc_proto/drc_rule.cpp @@ -55,7 +55,10 @@ test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION() bool test::DRC_RULE_CONDITION::EvaluateFor( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB ) { + m_ucode->SetItems( aItemA, aItemB ); +// fixme: handle error conditions + return m_ucode->Run()->AsDouble() != 0.0; } bool test::DRC_RULE_CONDITION::Compile() diff --git a/qa/drc_proto/drc_rule.h b/qa/drc_proto/drc_rule.h index b65fd67497..19cbed4438 100644 --- a/qa/drc_proto/drc_rule.h +++ b/qa/drc_proto/drc_rule.h @@ -37,6 +37,8 @@ class UCODE; class ERROR_STATUS; }; +class PCB_EXPR_UCODE; + namespace test { @@ -73,6 +75,10 @@ private: class DRC_CONSTRAINT { + public: + const MINOPTMAX& GetValue() const { return m_Value; } + bool Allowed() const { return m_Allow; } + public: MINOPTMAX m_Value; bool m_Allow; @@ -128,7 +134,7 @@ public: private: LIBEVAL::ERROR_STATUS m_compileError; - LIBEVAL::UCODE* m_ucode; + PCB_EXPR_UCODE* m_ucode; }; diff --git a/qa/drc_proto/drc_test_provider.cpp b/qa/drc_proto/drc_test_provider.cpp index 582486d600..f3e839ef24 100644 --- a/qa/drc_proto/drc_test_provider.cpp +++ b/qa/drc_proto/drc_test_provider.cpp @@ -1,8 +1,7 @@ #include #include -test::DRC_TEST_PROVIDER::DRC_TEST_PROVIDER ( DRC_ENGINE *aDrc ) : - m_drcEngine( aDrc ) +test::DRC_TEST_PROVIDER::DRC_TEST_PROVIDER () { } @@ -20,12 +19,41 @@ bool test::DRC_TEST_PROVIDER::IsEnabled() const const wxString test::DRC_TEST_PROVIDER::GetName() const { return ""; } const wxString test::DRC_TEST_PROVIDER::GetDescription() const { return ""; } -void test::DRC_TEST_PROVIDER::AddMarkerToPcb( MARKER_PCB* aMarker ) +void test::DRC_TEST_PROVIDER::Report( DRC_ITEM* item, test::DRC_RULE* violatingRule ) { } +void test::DRC_TEST_PROVIDER::ReportWithMarker( DRC_ITEM* item, test::DRC_RULE* violatingRule, wxPoint aMarkerPos ) +{ + +} + +void test::DRC_TEST_PROVIDER::ReportProgress( double aProgress ) +{ + +} + +void test::DRC_TEST_PROVIDER::ReportStage ( const wxString& aStageName, int index, int total ) +{ + +} + +bool test::DRC_TEST_PROVIDER::isErrorLimitExceeded( int error_code ) +{ + return false; +} + EDA_UNITS test::DRC_TEST_PROVIDER::userUnits() const { return m_drcEngine->UserUnits(); -} \ No newline at end of file +} + +void test::DRC_TEST_PROVIDER::accountCheck( test::DRC_RULE* ruleToTest ) +{ + auto it = m_stats.find( ruleToTest ); + if( it == m_stats.end() ) + m_stats[ ruleToTest ] = 0; + else + it->second++; +} diff --git a/qa/drc_proto/drc_test_provider.h b/qa/drc_proto/drc_test_provider.h index 041ff6dff1..cfaef8c74e 100644 --- a/qa/drc_proto/drc_test_provider.h +++ b/qa/drc_proto/drc_test_provider.h @@ -35,6 +35,36 @@ namespace test { class DRC_ENGINE; +class DRC_TEST_PROVIDER_REGISTRY +{ + public: + DRC_TEST_PROVIDER_REGISTRY() {}; + ~DRC_TEST_PROVIDER_REGISTRY() {}; + + static DRC_TEST_PROVIDER_REGISTRY& Instance() + { + static DRC_TEST_PROVIDER_REGISTRY self; + return self; + } + + void RegisterTestProvider(DRC_TEST_PROVIDER* provider) { m_providers.push_back(provider); } + std::vector GetTestProviders() const { return m_providers; } + + private: + std::vector m_providers; + +}; + +template class DRC_REGISTER_TEST_PROVIDER +{ + public: + DRC_REGISTER_TEST_PROVIDER() + { + T* provider = new T; + DRC_TEST_PROVIDER_REGISTRY::Instance().RegisterTestProvider( provider ); + } +}; + /** * DRC_TEST_PROVIDER * is a base class that represents a DRC "provider" which runs some DRC functions over a @@ -43,9 +73,14 @@ class DRC_ENGINE; class DRC_TEST_PROVIDER { public: - DRC_TEST_PROVIDER ( DRC_ENGINE *aDrc ); + DRC_TEST_PROVIDER (); virtual ~DRC_TEST_PROVIDER() {} + void SetDRCEngine( DRC_ENGINE *engine ) + { + m_drcEngine = engine; + } + /** * Runs this provider against the given PCB with configured options (if any). * @@ -53,8 +88,6 @@ public: * or polygon coalescing) */ - void SetRule ( DRC_RULE *aRule ); - virtual bool Run() = 0; virtual void Enable( bool enable ); @@ -63,228 +96,25 @@ public: virtual const wxString GetName() const; virtual const wxString GetDescription() const; - virtual void AddMarkerToPcb( MARKER_PCB* aMarker ); + virtual void Report( DRC_ITEM* item, test::DRC_RULE* violatingRule ); + virtual void ReportWithMarker( DRC_ITEM* item, test::DRC_RULE* violatingRule, wxPoint aMarkerPos ); + virtual void ReportProgress( double aProgress ); + virtual void ReportStage ( const wxString& aStageName, int index, int total ); virtual std::set GetMatchingRuleIds() const = 0; protected: - EDA_UNITS userUnits() const; + virtual void accountCheck( test::DRC_RULE* ruleToTest ); + virtual bool isErrorLimitExceeded( int error_code ); - DRC_RULE *m_rule; + EDA_UNITS userUnits() const; DRC_ENGINE *m_drcEngine; + std::unordered_map m_stats; bool m_enable; }; -#if 0 -/** - * BOARD_DRC_ITEMS_PROVIDER - * is an implementation of the RC_ITEMS_PROVIDER interface which uses a BOARD instance - * to fulfill the interface. - */ -class BOARD_DRC_ITEMS_PROVIDER : public RC_ITEMS_PROVIDER -{ -private: - BOARD* m_board; - - int m_severities; - std::vector m_filteredMarkers; - -public: - BOARD_DRC_ITEMS_PROVIDER( BOARD* aBoard ) : - m_board( aBoard ), - m_severities( 0 ) - { - } - - void SetSeverities( int aSeverities ) override - { - m_severities = aSeverities; - - BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); - - m_filteredMarkers.clear(); - - for( MARKER_PCB* marker : m_board->Markers() ) - { - int markerSeverity; - - if( marker->IsExcluded() ) - markerSeverity = RPT_SEVERITY_EXCLUSION; - else - markerSeverity = bds.GetSeverity( marker->GetRCItem()->GetErrorCode() ); - - if( markerSeverity & m_severities ) - m_filteredMarkers.push_back( marker ); - } - } - - int GetCount( int aSeverity = -1 ) override - { - if( aSeverity < 0 ) - return m_filteredMarkers.size(); - - BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); - - int count = 0; - - for( MARKER_PCB* marker : m_board->Markers() ) - { - int markerSeverity; - - if( marker->IsExcluded() ) - markerSeverity = RPT_SEVERITY_EXCLUSION; - else - markerSeverity = bds.GetSeverity( marker->GetRCItem()->GetErrorCode() ); - - if( markerSeverity == aSeverity ) - count++; - } - - return count; - } - - DRC_ITEM* GetItem( int aIndex ) override - { - MARKER_PCB* marker = m_filteredMarkers[ aIndex ]; - - return marker ? static_cast( marker->GetRCItem() ) : nullptr; - } - - void DeleteItem( int aIndex, bool aDeep ) override - { - MARKER_PCB* marker = m_filteredMarkers[ aIndex ]; - m_filteredMarkers.erase( m_filteredMarkers.begin() + aIndex ); - - if( aDeep ) - m_board->Delete( marker ); - } - - void DeleteAllItems() override - { - m_board->DeleteMARKERs(); - m_filteredMarkers.clear(); - } -}; - - -/** - * VECTOR_DRC_ITEMS_PROVIDER - * is an implementation of the interface named DRC_ITEMS_PROVIDER which uses a vector - * of pointers to DRC_ITEMs to fulfill the interface. No ownership is taken of the - * vector. - */ -class VECTOR_DRC_ITEMS_PROVIDER : public RC_ITEMS_PROVIDER -{ - PCB_BASE_FRAME* m_frame; - std::vector* m_sourceVector; // owns its DRC_ITEMs - - int m_severities; - std::vector m_filteredVector; // does not own its DRC_ITEMs - -public: - - VECTOR_DRC_ITEMS_PROVIDER( PCB_BASE_FRAME* aFrame, std::vector* aList ) : - m_frame( aFrame ), - m_sourceVector( aList ), - m_severities( 0 ) - { - } - - void SetSeverities( int aSeverities ) override - { - m_severities = aSeverities; - - BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); - - m_filteredVector.clear(); - - if( m_sourceVector ) - { - for( DRC_ITEM* item : *m_sourceVector ) - { - if( bds.GetSeverity( item->GetErrorCode() ) & aSeverities ) - m_filteredVector.push_back( item ); - } - } - } - - int GetCount( int aSeverity = -1 ) override - { - if( aSeverity < 0 ) - return m_filteredVector.size(); - - int count = 0; - BOARD_DESIGN_SETTINGS& bds = m_frame->GetBoard()->GetDesignSettings(); - - if( m_sourceVector ) - { - for( DRC_ITEM* item : *m_sourceVector ) - { - if( bds.GetSeverity( item->GetErrorCode() ) == aSeverity ) - count++; - } - } - - return count; - } - - DRC_ITEM* GetItem( int aIndex ) override - { - return (m_filteredVector)[aIndex]; - } - - void DeleteItem( int aIndex, bool aDeep ) override - { - DRC_ITEM* item = m_filteredVector[aIndex]; - m_filteredVector.erase( m_filteredVector.begin() + aIndex ); - - if( aDeep ) - { - for( size_t i = 0; i < m_sourceVector->size(); ++i ) - { - if( m_sourceVector->at( i ) == item ) - { - delete item; - m_sourceVector->erase( m_sourceVector->begin() + i ); - break; - } - } - } - } - - void DeleteAllItems() override - { - if( m_sourceVector ) - { - for( DRC_ITEM* item : *m_sourceVector ) - delete item; - - m_sourceVector->clear(); - } - - m_filteredVector.clear(); // no ownership of DRC_ITEM pointers - } -}; - - -/** - * RATSNEST_DRC_ITEMS_PROVIDER - */ -class RATSNEST_DRC_ITEMS_PROVIDER : public VECTOR_DRC_ITEMS_PROVIDER -{ - // TODO: for now this is just a vector, but we need to map it to some board-level - // data-structure so that deleting/excluding things can do a deep delete/exclusion - // which will be reflected in the ratsnest.... -public: - RATSNEST_DRC_ITEMS_PROVIDER( PCB_BASE_FRAME* aFrame, std::vector* aList ) : - VECTOR_DRC_ITEMS_PROVIDER( aFrame, aList ) - { } -}; - -#endif - }; #endif // DRC_PROVIDER__H