diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index a2a5cb127b..2ff6948809 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -187,7 +187,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std: m_DRCSeverities[ DRCE_FOOTPRINT_FILTERS ] = RPT_SEVERITY_IGNORE; m_DRCSeverities[ DRCE_OVERLAPPING_SILK ] = RPT_SEVERITY_WARNING; - m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = RPT_SEVERITY_WARNING; + m_DRCSeverities[ DRCE_SILK_MASK_CLEARANCE ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_SILK_EDGE_CLEARANCE ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_TEXT_HEIGHT ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_TEXT_THICKNESS ] = RPT_SEVERITY_WARNING; diff --git a/pcbnew/dialogs/dialog_footprint_checker.cpp b/pcbnew/dialogs/dialog_footprint_checker.cpp index 5b2fb44d96..b8f23e4ce4 100644 --- a/pcbnew/dialogs/dialog_footprint_checker.cpp +++ b/pcbnew/dialogs/dialog_footprint_checker.cpp @@ -191,7 +191,7 @@ void DIALOG_FOOTPRINT_CHECKER::runChecks() footprint->CheckClippedSilk( [&]( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB, const VECTOR2I& aPt ) { - errorHandler( aItemA, aItemB, nullptr, DRCE_SILK_CLEARANCE, wxEmptyString, aPt ); + errorHandler( aItemA, aItemB, nullptr, DRCE_SILK_MASK_CLEARANCE, wxEmptyString, aPt ); } ); m_checksRun = true; diff --git a/pcbnew/drc/drc_item.cpp b/pcbnew/drc/drc_item.cpp index 1ea43ccdb1..4329402310 100644 --- a/pcbnew/drc/drc_item.cpp +++ b/pcbnew/drc/drc_item.cpp @@ -236,7 +236,7 @@ DRC_ITEM DRC_ITEM::solderMaskBridge( DRCE_SOLDERMASK_BRIDGE, _HKI( "Solder mask aperture bridges items with different nets" ), wxT( "solder_mask_bridge" ) ); -DRC_ITEM DRC_ITEM::silkClearance( DRCE_SILK_CLEARANCE, +DRC_ITEM DRC_ITEM::silkMaskClearance( DRCE_SILK_MASK_CLEARANCE, _HKI( "Silkscreen clipped by solder mask" ), wxT( "silk_over_copper" ) ); @@ -352,7 +352,7 @@ std::vector> DRC_ITEM::allItemTypes( DRC_ITEM::heading_readability, DRC_ITEM::silkOverlaps, - DRC_ITEM::silkClearance, + DRC_ITEM::silkMaskClearance, DRC_ITEM::silkEdgeClearance, DRC_ITEM::textHeightOutOfRange, DRC_ITEM::textThicknessOutOfRange, @@ -441,7 +441,7 @@ std::shared_ptr DRC_ITEM::Create( int aErrorCode ) case DRCE_GENERIC_ERROR: return std::make_shared( genericError ); case DRCE_COPPER_SLIVER: return std::make_shared( copperSliver ); case DRCE_OVERLAPPING_SILK: return std::make_shared( silkOverlaps ); - case DRCE_SILK_CLEARANCE: return std::make_shared( silkClearance ); + case DRCE_SILK_MASK_CLEARANCE: return std::make_shared( silkMaskClearance ); case DRCE_SILK_EDGE_CLEARANCE: return std::make_shared( silkEdgeClearance ); case DRCE_SOLDERMASK_BRIDGE: return std::make_shared( solderMaskBridge ); case DRCE_TEXT_HEIGHT: return std::make_shared( textHeightOutOfRange ); diff --git a/pcbnew/drc/drc_item.h b/pcbnew/drc/drc_item.h index bd0b476ed0..ca116b398e 100644 --- a/pcbnew/drc/drc_item.h +++ b/pcbnew/drc/drc_item.h @@ -93,12 +93,12 @@ enum PCB_DRC_CODE { DRCE_SOLDERMASK_BRIDGE, // failure to maintain min soldermask web thickness // between copper items with different nets - DRCE_SILK_CLEARANCE, // silkscreen clipped by mask (potentially leaving it + DRCE_SILK_MASK_CLEARANCE, // silkscreen clipped by mask (potentially leaving it // over pads, exposed copper, etc.) DRCE_SILK_EDGE_CLEARANCE, DRCE_TEXT_HEIGHT, DRCE_TEXT_THICKNESS, - DRCE_OVERLAPPING_SILK, // silk to silk clearance error + DRCE_OVERLAPPING_SILK, // silk-to-silk or silk-to-other clearance error DRCE_LENGTH_OUT_OF_RANGE, DRCE_SKEW_OUT_OF_RANGE, @@ -238,7 +238,7 @@ private: static DRC_ITEM genericWarning; static DRC_ITEM genericError; static DRC_ITEM copperSliver; - static DRC_ITEM silkClearance; + static DRC_ITEM silkMaskClearance; static DRC_ITEM silkEdgeClearance; static DRC_ITEM solderMaskBridge; static DRC_ITEM silkOverlaps; diff --git a/pcbnew/drc/drc_test_provider_silk_clearance.cpp b/pcbnew/drc/drc_test_provider_silk_clearance.cpp index e0603e9584..3dc65ca950 100644 --- a/pcbnew/drc/drc_test_provider_silk_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_silk_clearance.cpp @@ -75,14 +75,20 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run() { const int progressDelta = 500; - if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) ) + m_board = m_drcEngine->GetBoard(); + + // If the soldermask min width is greater than 0 then we must use a healing algorithm to generate + // a whole-board soldermask poly, and then test against that. However, that can't deal well with + // DRC exclusions (as any change anywhere on the board that affects the soldermask will null the + // associated exclusions), so we only use that when soldermask min width is > 0. + bool checkIndividualMaskItems = m_board->GetDesignSettings().m_SolderMaskMinWidth <= 0; + + if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) + && ( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE) || !checkIndividualMaskItems ) ) { - reportAux( wxT( "Overlapping silk violations ignored. Tests not run." ) ); return true; // continue with other tests } - m_board = m_drcEngine->GetBoard(); - DRC_CONSTRAINT worstClearanceConstraint; m_largestClearance = 0; @@ -182,8 +188,11 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run() std::shared_ptr hole; - if( m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) ) + if( ( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE) || !checkIndividualMaskItems ) + && m_drcEngine->IsErrorLimitExceeded( DRCE_OVERLAPPING_SILK ) ) + { return false; + } if( isInvisibleText( refItem ) || isInvisibleText( testItem ) ) return true; @@ -201,14 +210,21 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run() } } + int errorCode = DRCE_OVERLAPPING_SILK; DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( SILK_CLEARANCE_CONSTRAINT, - refItem, testItem, - aLayers.second ); + refItem, testItem, aLayers.second ); + int minClearance = -1; - if( constraint.IsNull() || constraint.GetSeverity() == RPT_SEVERITY_IGNORE ) - return true; + if( !constraint.IsNull() && constraint.GetSeverity() != RPT_SEVERITY_IGNORE ) + minClearance = constraint.GetValue().Min(); - int minClearance = constraint.GetValue().Min(); + if( aLayers.second == F_Mask || aLayers.second == B_Mask ) + { + if( checkIndividualMaskItems ) + minClearance = std::max( minClearance, 0 ); + + errorCode = DRCE_SILK_MASK_CLEARANCE; + } if( minClearance < 0 ) return true; @@ -237,7 +253,7 @@ bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run() if( refShape->Collide( testShape, minClearance, &actual, &pos ) ) { - std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_SILK ); + std::shared_ptr drcItem = DRC_ITEM::Create( errorCode ); if( minClearance > 0 ) { diff --git a/pcbnew/drc/drc_test_provider_solder_mask.cpp b/pcbnew/drc/drc_test_provider_solder_mask.cpp index e6a8bb8e9c..71dac2a8ae 100644 --- a/pcbnew/drc/drc_test_provider_solder_mask.cpp +++ b/pcbnew/drc/drc_test_provider_solder_mask.cpp @@ -40,7 +40,7 @@ Solder mask tests. Checks for silkscreen which is clipped by mask openings and for bridges between mask apertures with different nets. Errors generated: - - DRCE_SILK_CLEARANCE + - DRCE_SILK_MASK_CLEARANCE - DRCE_SOLDERMASK_BRIDGE */ @@ -224,10 +224,11 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::buildRTrees() solderMask->GetFill( F_Mask )->Simplify(); solderMask->GetFill( B_Mask )->Simplify(); - solderMask->GetFill( F_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, - m_maxError ); - solderMask->GetFill( B_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, - m_maxError ); + if( m_webWidth > 0 ) + { + solderMask->GetFill( F_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, m_maxError ); + solderMask->GetFill( B_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, m_maxError ); + } solderMask->SetFillFlag( F_Mask, true ); solderMask->SetFillFlag( B_Mask, true ); @@ -246,6 +247,11 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testSilkToMaskClearance() { LSET silkLayers( { F_SilkS, B_SilkS } ); + // If we have no minimum web width then we delegate to the silk checker which does object-to-object + // testing (instead of object-to-solder-mask-zone-fill checking that we do here). + if( m_webWidth <= 0 ) + return; + const size_t progressDelta = 250; int count = 0; int ii = 0; @@ -260,7 +266,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testSilkToMaskClearance() forEachGeometryItem( s_allBasicItems, silkLayers, [&]( BOARD_ITEM* item ) -> bool { - if( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_CLEARANCE ) ) + if( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE ) ) return false; if( !reportProgress( ii++, count, progressDelta ) ) @@ -290,7 +296,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testSilkToMaskClearance() if( m_fullSolderMaskRTree->QueryColliding( itemBBox, itemShape.get(), maskLayer, clearance, &actual, &pos ) ) { - auto drce = DRC_ITEM::Create( DRCE_SILK_CLEARANCE ); + std::shared_ptr drce = DRC_ITEM::Create( DRCE_SILK_MASK_CLEARANCE ); if( clearance > 0 ) { @@ -758,7 +764,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testMaskBridges() bool DRC_TEST_PROVIDER_SOLDER_MASK::Run() { - if( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_CLEARANCE ) + if( m_drcEngine->IsErrorLimitExceeded( DRCE_SILK_MASK_CLEARANCE ) && m_drcEngine->IsErrorLimitExceeded( DRCE_SOLDERMASK_BRIDGE ) ) { reportAux( wxT( "Solder mask violations ignored. Tests not run." ) ); diff --git a/qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp b/qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp index bd4f286fb5..c4d090bf32 100644 --- a/qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp +++ b/qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp @@ -57,7 +57,7 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperGraphicsTest, DRC_COPPER_GRAPHICS_TEST_FIXTURE bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_COPPER_SLIVER ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_STARVED_THERMAL ] = SEVERITY::RPT_SEVERITY_IGNORE; - bds.m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[ DRCE_SILK_MASK_CLEARANCE ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_ISOLATED_COPPER ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_MIRRORED_TEXT_ON_FRONT_LAYER ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER ] = SEVERITY::RPT_SEVERITY_IGNORE; diff --git a/qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp b/qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp index f6b0eb78a7..6065634e5a 100644 --- a/qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp +++ b/qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp @@ -55,7 +55,7 @@ BOOST_FIXTURE_TEST_CASE( DRCSolderMaskBridgingTest, DRC_SOLDER_MASK_BRIDGING_TES bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_COPPER_SLIVER ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCSeverities[ DRCE_STARVED_THERMAL ] = SEVERITY::RPT_SEVERITY_IGNORE; - bds.m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = SEVERITY::RPT_SEVERITY_IGNORE; + bds.m_DRCSeverities[ DRCE_SILK_MASK_CLEARANCE ] = SEVERITY::RPT_SEVERITY_IGNORE; bds.m_DRCEngine->SetViolationHandler( [&]( const std::shared_ptr& aItem, VECTOR2I aPos, int aLayer,