File Use-individual-silk-mask-collision-checking-if-solde.patch of Package kicad.8

From 86f3703c3cb00c838bb19936678d999b3630ee53 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  | 39 +++++++++++++------
 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, 51 insertions(+), 28 deletions(-)

diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp
index 4b418cdea8..5f38b0be97 100644
--- a/pcbnew/board_design_settings.cpp
+++ b/pcbnew/board_design_settings.cpp
@@ -179,7 +179,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
     m_DRCSeverities[ DRCE_SCHEMATIC_PARITY_ISSUES ] = RPT_SEVERITY_WARNING;
 
     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 c32f0c2cf8..e7314f8185 100644
--- a/pcbnew/drc/drc_item.cpp
+++ b/pcbnew/drc/drc_item.cpp
@@ -213,7 +213,7 @@ DRC_ITEM DRC_ITEM::solderMaskBridge( DRCE_SOLDERMASK_BRIDGE,
         _( "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,
         _( "Silkscreen clipped by solder mask" ),
         wxT( "silk_over_copper" ) );
 
@@ -310,7 +310,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,
@@ -380,7 +380,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
     case DRCE_ASSERTION_FAILURE:        return std::make_shared<DRC_ITEM>( assertionFailure );
     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 9031b73286..78dddd79a4 100644
--- a/pcbnew/drc/drc_item.h
+++ b/pcbnew/drc/drc_item.h
@@ -87,12 +87,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,
@@ -196,7 +196,7 @@ private:
     static DRC_ITEM unresolvedVariable;
     static DRC_ITEM assertionFailure;
     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 b80e08f8a5..c64053d62d 100644
--- a/pcbnew/drc/drc_test_provider_silk_clearance.cpp
+++ b/pcbnew/drc/drc_test_provider_silk_clearance.cpp
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <board.h>
+#include <board_design_settings.h>
 #include <footprint.h>
 #include <pcb_shape.h>
 #include <pcb_track.h>
@@ -77,14 +78,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;
 
@@ -184,8 +191,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;
@@ -203,14 +213,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;
@@ -228,7 +245,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 7e20ae4337..dd4627e90a 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
 */
 
@@ -225,10 +225,11 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::buildRTrees()
     solderMask->GetFill( F_Mask )->Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
     solderMask->GetFill( B_Mask )->Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
 
-    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 );
@@ -247,6 +248,11 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testSilkToMaskClearance()
 {
     LSET   silkLayers = { 2, 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;
@@ -261,7 +267,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 ) )
@@ -291,7 +297,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 8da5fd15e0..5ecf49e97b 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_DRCEngine->SetViolationHandler(
diff --git a/qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp b/qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp
index f6bf1794ad..17b803d6eb 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

openSUSE Build Service is sponsored by