File Use-individual-silk-mask-collision-checking-if-solde.patch of Package kicad.9
From dae8f8e83620e86fdda9ebe5cb380d872fddd4d4 Mon Sep 17 00:00:00 2001
From: Jeff Young <jeff@rokeby.ie>
Date: Mon, 14 Apr 2025 13:51:16 +0100
Subject: [PATCH] Use individual silk/mask collision checking if solder mask
min width is 0.
Using the combinde solder mask doesn't deal well
with exclusions since almost any change will affect
the combined mask.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/17429
---
pcbnew/board_design_settings.cpp | 2 +-
pcbnew/drc/drc_item.cpp | 6 +--
pcbnew/drc/drc_item.h | 6 +--
.../drc/drc_test_provider_silk_clearance.cpp | 38 +++++++++++++------
pcbnew/drc/drc_test_provider_solder_mask.cpp | 22 +++++++----
.../pcbnew/drc/test_drc_copper_graphics.cpp | 2 +-
.../pcbnew/drc/test_solder_mask_bridging.cpp | 2 +-
7 files changed, 50 insertions(+), 28 deletions(-)
diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp
index 3bec219a04..de451928db 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/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<std::reference_wrapper<RC_ITEM>> 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> DRC_ITEM::Create( int aErrorCode )
case DRCE_GENERIC_ERROR: return std::make_shared<DRC_ITEM>( genericError );
case DRCE_COPPER_SLIVER: return std::make_shared<DRC_ITEM>( copperSliver );
case DRCE_OVERLAPPING_SILK: return std::make_shared<DRC_ITEM>( silkOverlaps );
- case DRCE_SILK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkClearance );
+ case DRCE_SILK_MASK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkMaskClearance );
case DRCE_SILK_EDGE_CLEARANCE: return std::make_shared<DRC_ITEM>( silkEdgeClearance );
case DRCE_SOLDERMASK_BRIDGE: return std::make_shared<DRC_ITEM>( solderMaskBridge );
case DRCE_TEXT_HEIGHT: return std::make_shared<DRC_ITEM>( 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<SHAPE> 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<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_SILK );
+ std::shared_ptr<DRC_ITEM> 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<DRC_ITEM> 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<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
--
2.47.1