diff --git a/common/drc_rules.keywords b/common/drc_rules.keywords index 0c14bf5cf6..63304f9560 100644 --- a/common/drc_rules.keywords +++ b/common/drc_rules.keywords @@ -29,8 +29,7 @@ zone edge_clearance hole_clearance courtyard_clearance -silk_to_mask -silk_to_silk +silk_clearance skew diff_pair_gap diff_pair_uncoupled diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 98f11eda06..b54e8069b9 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -251,7 +251,7 @@ set( PCBNEW_DRC_SRCS drc/drc_test_provider_track_width.cpp drc/drc_test_provider_via_diameter.cpp drc/drc_test_provider_silk_to_mask.cpp - drc/drc_test_provider_silk_to_silk.cpp + drc/drc_test_provider_silk_clearance.cpp drc/drc_test_provider_matched_length.cpp drc/drc_test_provider_diff_pair_coupling.cpp ) diff --git a/pcbnew/dialogs/panel_setup_rules.cpp b/pcbnew/dialogs/panel_setup_rules.cpp index 4a82bb5c5f..d59ec651d8 100644 --- a/pcbnew/dialogs/panel_setup_rules.cpp +++ b/pcbnew/dialogs/panel_setup_rules.cpp @@ -236,8 +236,8 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent ) "length " "hole " "hole_clearance " - "silk_to_mask " - "silk_to_silk skew " + "silk_clearance " + "skew " "track_width " "via_count "; } diff --git a/pcbnew/dialogs/panel_setup_rules_help.md b/pcbnew/dialogs/panel_setup_rules_help.md index 9e6e33d346..58bd81956c 100644 --- a/pcbnew/dialogs/panel_setup_rules_help.md +++ b/pcbnew/dialogs/panel_setup_rules_help.md @@ -18,9 +18,18 @@ * annular_width * clearance + * courtyard_clearance + * diff_pair_gap + * diff_pair_uncoupled * disallow + * edge_clearance + * length * hole + * hole_clearance + * silk_clearance + * skew * track_width + * via_count ### Item Types diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index e37ec20e58..3d19affe94 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -129,14 +129,10 @@ void DRC_ENGINE::loadImplicitRules() holeClearanceConstraint.Value().SetMin( 0 ); rule->AddConstraint( courtyardClearanceConstraint ); - DRC_CONSTRAINT silkToPadClearanceConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_MASK ); + DRC_CONSTRAINT silkToPadClearanceConstraint( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE ); silkToPadClearanceConstraint.Value().SetMin( 0 ); rule->AddConstraint( silkToPadClearanceConstraint ); - DRC_CONSTRAINT silkToSilkClearanceConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_SILK ); - silkToSilkClearanceConstraint.Value().SetMin( 0 ); - rule->AddConstraint( silkToSilkClearanceConstraint ); - DRC_CONSTRAINT diffPairGapConstraint( DRC_CONSTRAINT_TYPE_DIFF_PAIR_GAP ); diffPairGapConstraint.Value().SetMin( bds.GetDefault()->GetClearance() ); diffPairGapConstraint.Value().SetOpt( bds.GetDefault()->GetClearance() ); @@ -363,8 +359,7 @@ static wxString formatConstraint( const DRC_CONSTRAINT& constraint ) { DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, "edge_clearance", formatMinMax }, { DRC_CONSTRAINT_TYPE_HOLE_SIZE, "hole_size", formatMinMax }, { DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE, "courtyard_clearance", formatMinMax }, - { DRC_CONSTRAINT_TYPE_SILK_TO_MASK, "silk_to_mask", formatMinMax }, - { DRC_CONSTRAINT_TYPE_SILK_TO_SILK, "silk_to_silk", formatMinMax }, + { DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, "silk_clearance", formatMinMax }, { DRC_CONSTRAINT_TYPE_TRACK_WIDTH, "track_width", formatMinMax }, { DRC_CONSTRAINT_TYPE_ANNULAR_WIDTH, "annular_width", formatMinMax }, { DRC_CONSTRAINT_TYPE_DISALLOW, "disallow", nullptr }, @@ -615,30 +610,30 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRulesForItems( DRC_CONSTRAINT_TYPE_T aConstraintI if( m_constraintMap.count( aConstraintId ) ) { - std::vector* ruleset = m_constraintMap[ aConstraintId ]; + std::vector* ruleset = m_constraintMap[ aConstraintId ]; - // Last matching rule wins, so process in reverse order - for( int ii = (int) ruleset->size() - 1; ii >= 0; --ii ) - { - const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->at( ii ); - implicit = rcons->parentRule && rcons->parentRule->m_Implicit; + // Last matching rule wins, so process in reverse order + for( int ii = (int) ruleset->size() - 1; ii >= 0; --ii ) + { + const CONSTRAINT_WITH_CONDITIONS* rcons = ruleset->at( ii ); + implicit = rcons->parentRule && rcons->parentRule->m_Implicit; - REPORT( "" ) + REPORT( "" ) if( aConstraintId == DRC_CONSTRAINT_TYPE_CLEARANCE ) - { + { int clearance = rcons->constraint.m_Value.Min(); REPORT( wxString::Format( implicit ? _( "Checking %s; clearance: %s." ) : _( "Checking rule %s; clearance: %s."), rcons->constraint.GetName(), MessageTextFromValue( UNITS, clearance ) ) ) - } - else - { + } + else + { REPORT( wxString::Format( implicit ? _( "Checking %s." ) : _( "Checking rule %s."), rcons->constraint.GetName() ) ) - } + } if( aLayer != UNDEFINED_LAYER && !rcons->layerTest.test( aLayer ) ) { diff --git a/pcbnew/drc/drc_rtree.h b/pcbnew/drc/drc_rtree.h index 03e9d6058e..ee606f1aae 100644 --- a/pcbnew/drc/drc_rtree.h +++ b/pcbnew/drc/drc_rtree.h @@ -250,24 +250,22 @@ public: int count = 0; - auto visit = [&] ( ITEM_WITH_SHAPE* aItem ) -> bool - { - int actual; + auto visit = + [&] ( ITEM_WITH_SHAPE* aItem ) -> bool + { + if( !aFilter || aFilter( aItem->parent ) ) + { + int actual; - // keep searching - if( aFilter && ! aFilter( aItem->parent ) ) - return true; + if( aRefShape->Collide( aItem->shape, aClearance, &actual ) ) + { + count++; + return false; + } + } - bool colliding = aRefShape->Collide( aItem->shape, aClearance, &actual ); - - if( colliding ) - { - count++; - return false; - } - - return true; - }; + return true; + }; this->m_tree[aTargetLayer]->Search( min, max, visit ); return count > 0; @@ -278,8 +276,7 @@ public: PCB_LAYER_ID aTargetLayer, std::function aFilter = nullptr, std::function aVisitor = nullptr, - int aClearance = 0 - ) + int aClearance = 0 ) { // keep track of BOARD_ITEMs that have been already found to collide (some items // might be build of COMPOUND/triangulated shapes and a single subshape collision @@ -296,35 +293,28 @@ public: int count = 0; - auto visit = [&] ( ITEM_WITH_SHAPE* aItem ) -> bool - { - if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() ) - return true; - - if( aFilter && !aFilter( aItem->parent ) ) - return true; - - int actual; - - bool colliding = refShape->Collide( aItem->shape, aClearance, &actual ); - - if( colliding ) - { - collidingCompounds.insert( aItem->parent ); - count++; - if( aVisitor ) - { - return aVisitor( aItem->parent, actual ); - } - else + auto visit = + [&]( ITEM_WITH_SHAPE* aItem ) -> bool { + if( collidingCompounds.find( aItem->parent ) != collidingCompounds.end() ) + return true; + + if( !aFilter || aFilter( aItem->parent ) ) + { + int actual; + + if( refShape->Collide( aItem->shape, aClearance, &actual ) ) + { + collidingCompounds.insert( aItem->parent ); + count++; + + if( aVisitor ) + return aVisitor( aItem->parent, actual ); + } + } + return true; - } - } - - - return true; - }; + }; this->m_tree[aTargetLayer]->Search( min, max, visit ); return count; @@ -389,8 +379,7 @@ public: #if 0 std::vector> GetNearest( const wxPoint &aPoint, - PCB_LAYER_ID aLayer, - int aLimit ) + PCB_LAYER_ID aLayer, int aLimit ) { const int point[2] = { aPoint.x, aPoint.y }; diff --git a/pcbnew/drc/drc_rule.h b/pcbnew/drc/drc_rule.h index 346750df77..8ed33ed045 100644 --- a/pcbnew/drc/drc_rule.h +++ b/pcbnew/drc/drc_rule.h @@ -46,8 +46,7 @@ enum DRC_CONSTRAINT_TYPE_T DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, DRC_CONSTRAINT_TYPE_HOLE_SIZE, DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE, - DRC_CONSTRAINT_TYPE_SILK_TO_MASK, - DRC_CONSTRAINT_TYPE_SILK_TO_SILK, + DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, DRC_CONSTRAINT_TYPE_TRACK_WIDTH, DRC_CONSTRAINT_TYPE_ANNULAR_WIDTH, DRC_CONSTRAINT_TYPE_DISALLOW, diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index 0482a5c20c..29893a3f98 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -276,8 +276,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) case T_edge_clearance: constraint.m_Type = DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE; break; case T_hole: constraint.m_Type = DRC_CONSTRAINT_TYPE_HOLE_SIZE; break; case T_courtyard_clearance: constraint.m_Type = DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE; break; - case T_silk_to_mask: constraint.m_Type = DRC_CONSTRAINT_TYPE_SILK_TO_MASK; break; - case T_silk_to_silk: constraint.m_Type = DRC_CONSTRAINT_TYPE_SILK_TO_SILK; break; + case T_silk_clearance: constraint.m_Type = DRC_CONSTRAINT_TYPE_SILK_CLEARANCE; break; case T_track_width: constraint.m_Type = DRC_CONSTRAINT_TYPE_TRACK_WIDTH; break; case T_annular_width: constraint.m_Type = DRC_CONSTRAINT_TYPE_ANNULAR_WIDTH; break; case T_disallow: constraint.m_Type = DRC_CONSTRAINT_TYPE_DISALLOW; break; diff --git a/pcbnew/drc/drc_test_provider_edge_clearance.cpp b/pcbnew/drc/drc_test_provider_edge_clearance.cpp index 86f8b05236..088162dac5 100644 --- a/pcbnew/drc/drc_test_provider_edge_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_edge_clearance.cpp @@ -190,7 +190,7 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() const std::shared_ptr& shape = boardItem->GetEffectiveShape(); - auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_TO_MASK, + auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, outlineItem, boardItem ); int minClearance = constraint.GetValue().Min(); @@ -235,7 +235,7 @@ int DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetNumPhases() const std::set DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const { - return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE }; + return { DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, DRC_CONSTRAINT_TYPE_SILK_CLEARANCE }; } diff --git a/pcbnew/drc/drc_test_provider_silk_to_silk.cpp b/pcbnew/drc/drc_test_provider_silk_clearance.cpp similarity index 56% rename from pcbnew/drc/drc_test_provider_silk_to_silk.cpp rename to pcbnew/drc/drc_test_provider_silk_clearance.cpp index e6e8bcab7e..afc9341b93 100644 --- a/pcbnew/drc/drc_test_provider_silk_to_silk.cpp +++ b/pcbnew/drc/drc_test_provider_silk_clearance.cpp @@ -42,14 +42,14 @@ */ -class DRC_TEST_PROVIDER_SILK_TO_SILK : public DRC_TEST_PROVIDER +class DRC_TEST_PROVIDER_SILK_CLEARANCE : public DRC_TEST_PROVIDER { public: - DRC_TEST_PROVIDER_SILK_TO_SILK () + DRC_TEST_PROVIDER_SILK_CLEARANCE () { } - virtual ~DRC_TEST_PROVIDER_SILK_TO_SILK() + virtual ~DRC_TEST_PROVIDER_SILK_CLEARANCE() { } @@ -57,7 +57,7 @@ public: virtual const wxString GetName() const override { - return "silk_to_silk"; + return "silk_clearance"; }; virtual const wxString GetDescription() const override @@ -79,14 +79,14 @@ private: }; -bool DRC_TEST_PROVIDER_SILK_TO_SILK::Run() +bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run() { m_board = m_drcEngine->GetBoard(); DRC_CONSTRAINT worstClearanceConstraint; m_largestClearance = 0; - if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_SILK, + if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) { m_largestClearance = worstClearanceConstraint.m_Value.Min(); @@ -97,15 +97,22 @@ bool DRC_TEST_PROVIDER_SILK_TO_SILK::Run() if( !reportPhase( _( "Checking silkscreen for overlapping items..." ) ) ) return false; - DRC_RTREE silkTree; + DRC_RTREE silkTree, targetTree; - auto addToTree = + auto addToSilkTree = [&silkTree]( BOARD_ITEM *item ) -> bool { silkTree.insert( item ); return true; }; + auto addToTargetTree = + [&targetTree]( BOARD_ITEM *item ) -> bool + { + targetTree.insert( item ); + return true; + }; + auto checkClearance = [&]( const DRC_RTREE::LAYER_PAIR& aLayers, DRC_RTREE::ITEM_WITH_SHAPE* aRefItem, DRC_RTREE::ITEM_WITH_SHAPE* aTestItem, bool* aCollisionDetected ) -> bool @@ -113,53 +120,59 @@ bool DRC_TEST_PROVIDER_SILK_TO_SILK::Run() if( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_SILK_CLEARANCE ) ) return false; - auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_TO_SILK, + auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, aRefItem->parent, - aTestItem->parent ); + aTestItem->parent, + aLayers.second ); int minClearance = constraint.GetValue().Min(); int actual; VECTOR2I pos; accountCheck( constraint ); - // only check for silkscreen collisions belonging to different footprints or - // overlapping texts - - KICAD_T typeRef = aRefItem->parent->Type(); - KICAD_T typeTest = aTestItem->parent->Type(); - - MODULE *parentModRef = nullptr; - MODULE *parentModTest = nullptr; - - if ( isInvisibleText( aRefItem->parent ) ) - return true; - - if ( isInvisibleText( aTestItem->parent ) ) - return true; - - if( typeRef == PCB_FP_SHAPE_T || typeRef == PCB_FP_TEXT_T ) + if( minClearance == 0 ) { - parentModRef = static_cast ( aRefItem->parent->GetParent() ); - } + // MinClearance == 0 means the author didn't specify anything and we want to + // use heuristics for a silk : silk collision. + // + // MinClearance > 0 means we're in an author-specified condition that the + // rule matched, and we don't want any heuristics. - if( typeTest == PCB_FP_SHAPE_T || typeTest == PCB_FP_TEXT_T ) - { - parentModTest = static_cast ( aTestItem->parent->GetParent() ); - } - - // silkscreen drawings within the same module (or globally on the board) - // don't report clearance errors. Everything else does. - - if( parentModRef && parentModRef == parentModTest ) - { - if( typeRef == PCB_FP_SHAPE_T && typeTest == PCB_FP_SHAPE_T ) + // We know that aLayers.first is a silk layer, so we just need to check that + // aLayers.second matches. + if( aLayers.second != aLayers.first ) return true; - } - if( !parentModRef && !parentModTest ) - { - if( typeRef == PCB_SHAPE_T && typeTest == PCB_SHAPE_T ) + KICAD_T refType = aRefItem->parent->Type(); + KICAD_T testType = aTestItem->parent->Type(); + + MODULE *parentModRef = nullptr; + MODULE *parentModTest = nullptr; + + if ( isInvisibleText( aRefItem->parent ) ) return true; + + if ( isInvisibleText( aTestItem->parent ) ) + return true; + + if( refType == PCB_FP_SHAPE_T || refType == PCB_FP_TEXT_T ) + parentModRef = static_cast ( aRefItem->parent->GetParent() ); + + if( testType == PCB_FP_SHAPE_T || testType == PCB_FP_TEXT_T ) + parentModTest = static_cast ( aTestItem->parent->GetParent() ); + + // Silkscreen drawings within the same module (or globally on the board) + // don't report clearance errors. Everything else does. + if( parentModRef && parentModRef == parentModTest ) + { + if( refType == PCB_FP_SHAPE_T && testType == PCB_FP_SHAPE_T ) + return true; + } + else if( !parentModRef && !parentModTest ) + { + if( refType == PCB_SHAPE_T && testType == PCB_SHAPE_T ) + return true; + } } if( !aRefItem->shape->Collide( aTestItem->shape, minClearance, &actual, &pos ) ) @@ -187,17 +200,32 @@ bool DRC_TEST_PROVIDER_SILK_TO_SILK::Run() }; int numSilk = forEachGeometryItem( { PCB_SHAPE_T, PCB_FP_SHAPE_T, PCB_TEXT_T, PCB_FP_TEXT_T }, - LSET( 2, F_SilkS, B_SilkS ), addToTree ); + LSET( 2, F_SilkS, B_SilkS ), addToSilkTree ); + forEachGeometryItem( {}, LSET::FrontMask() | LSET::BackMask(), addToTargetTree ); reportAux( _("Testing %d silkscreen features."), numSilk ); const std::vector layerPairs = { DRC_RTREE::LAYER_PAIR( F_SilkS, F_SilkS ), - DRC_RTREE::LAYER_PAIR( B_SilkS, B_SilkS ) + DRC_RTREE::LAYER_PAIR( F_SilkS, F_Mask ), + DRC_RTREE::LAYER_PAIR( F_SilkS, F_Adhes ), + DRC_RTREE::LAYER_PAIR( F_SilkS, F_Paste ), + DRC_RTREE::LAYER_PAIR( F_SilkS, F_CrtYd ), + DRC_RTREE::LAYER_PAIR( F_SilkS, F_Fab ), + DRC_RTREE::LAYER_PAIR( F_SilkS, F_Cu ), + DRC_RTREE::LAYER_PAIR( F_SilkS, Edge_Cuts ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_SilkS ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_Mask ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_Adhes ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_Paste ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_CrtYd ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_Fab ), + DRC_RTREE::LAYER_PAIR( B_SilkS, B_Cu ), + DRC_RTREE::LAYER_PAIR( B_SilkS, Edge_Cuts ), }; - silkTree.QueryCollidingPairs( &silkTree, layerPairs, checkClearance, m_largestClearance ); + silkTree.QueryCollidingPairs( &targetTree, layerPairs, checkClearance, m_largestClearance ); reportRuleStatistics(); @@ -205,13 +233,13 @@ bool DRC_TEST_PROVIDER_SILK_TO_SILK::Run() } -std::set DRC_TEST_PROVIDER_SILK_TO_SILK::GetConstraintTypes() const +std::set DRC_TEST_PROVIDER_SILK_CLEARANCE::GetConstraintTypes() const { - return { DRC_CONSTRAINT_TYPE_SILK_TO_SILK }; + return { DRC_CONSTRAINT_TYPE_SILK_CLEARANCE }; } namespace detail { - static DRC_REGISTER_TEST_PROVIDER dummy; + static DRC_REGISTER_TEST_PROVIDER dummy; } diff --git a/pcbnew/drc/drc_test_provider_silk_to_mask.cpp b/pcbnew/drc/drc_test_provider_silk_to_mask.cpp index 3d448ee5a2..1fd2e1cc9f 100644 --- a/pcbnew/drc/drc_test_provider_silk_to_mask.cpp +++ b/pcbnew/drc/drc_test_provider_silk_to_mask.cpp @@ -87,7 +87,7 @@ bool DRC_TEST_PROVIDER_SILK_TO_MASK::Run() DRC_CONSTRAINT worstClearanceConstraint; m_largestClearance = 0; - if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_SILK_TO_MASK, + if( m_drcEngine->QueryWorstConstraint( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) { m_largestClearance = worstClearanceConstraint.m_Value.Min(); @@ -121,7 +121,7 @@ bool DRC_TEST_PROVIDER_SILK_TO_MASK::Run() if( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE ) ) return false; - auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_TO_MASK, + auto constraint = m_drcEngine->EvalRulesForItems( DRC_CONSTRAINT_TYPE_SILK_CLEARANCE, aRefItem->parent, aTestItem->parent ); @@ -192,7 +192,7 @@ bool DRC_TEST_PROVIDER_SILK_TO_MASK::Run() std::set DRC_TEST_PROVIDER_SILK_TO_MASK::GetConstraintTypes() const { - return { DRC_CONSTRAINT_TYPE_SILK_TO_MASK }; + return { DRC_CONSTRAINT_TYPE_SILK_CLEARANCE }; } diff --git a/qa/drc_proto/CMakeLists.txt b/qa/drc_proto/CMakeLists.txt index 8d094c0e47..6a0ee2b229 100644 --- a/qa/drc_proto/CMakeLists.txt +++ b/qa/drc_proto/CMakeLists.txt @@ -53,7 +53,7 @@ add_executable( drc_proto ../../pcbnew/drc/drc_test_provider_lvs.cpp ../../pcbnew/drc/drc_test_provider_misc.cpp ../../pcbnew/drc/drc_test_provider_silk_to_mask.cpp - ../../pcbnew/drc/drc_test_provider_silk_to_silk.cpp + ../../pcbnew/drc/drc_test_provider_silk_clearance.cpp ../../pcbnew/drc/drc_test_provider_matched_length.cpp ../../pcbnew/drc/drc_test_provider_diff_pair_coupling.cpp ../../pcbnew/drc/drc_engine.cpp