From 38e9217d5416c67ce8786ee4996df4d0e719c1b0 Mon Sep 17 00:00:00 2001
From: Jeff Young <jeff@rokeby.ie>
Date: Wed, 2 Sep 2020 23:15:30 +0100
Subject: [PATCH] Consolidate all DRC epsilon/threshold values to a single
 advancedCfg setting.

Fixes https://gitlab.com/kicad/code/kicad/issues/5464
---
 common/advanced_config.cpp                  | 15 ++++++++++++++-
 include/advanced_config.h                   |  9 ++++++++-
 include/board_design_settings.h             | 10 +++++-----
 pcbnew/board_design_settings.cpp            |  8 +++++++-
 pcbnew/drc/drc_clearance_test_functions.cpp | 15 ++++-----------
 5 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/common/advanced_config.cpp b/common/advanced_config.cpp
index 7fbc8f2211..1d4ac15b63 100644
--- a/common/advanced_config.cpp
+++ b/common/advanced_config.cpp
@@ -67,6 +67,13 @@ namespace AC_KEYS
  */
 static const wxChar ExtraFillMargin[] = wxT( "ExtraFillMargin" );
 
+/**
+ * A fudge factor for DRC.  Required to prevent false positives due to rounding errors, errors
+ * in polygonalization, etc.
+ * Previous versions hard-coded various values from 0.000005mm to 0.002mm.
+ */
+static const wxChar DRCEpsilon[] = wxT( "DRCEpsilon" );
+
 /**
  * Testing mode for new connectivity algorithm.  Setting this to on will cause all modifications
  * to the netlist to be recalculated on the fly.  This may be slower than the standard process
@@ -203,6 +210,9 @@ ADVANCED_CFG::ADVANCED_CFG()
     m_DrawTriangulationOutlines = false;
     m_PluginAltiumSch           = false;
 
+    m_extraClearance            = 0.0005;
+    m_DRCEpsilon                = 0.0005;   // 500nm is small enough not to materially violate
+                                            // any constraints.
     loadFromConfigFile();
 }
 
@@ -244,7 +254,10 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
                                                 &m_realTimeConnectivity, true ) );
 
     configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::ExtraFillMargin,
-                                                  &m_extraClearance, 0.001, 0.0, 1.0 ) );
+                                                  &m_extraClearance, 0.0005, 0.0, 1.0 ) );
+
+    configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::DRCEpsilon,
+                                                  &m_DRCEpsilon, 0.0005, 0.0, 1.0 ) );
 
     configParams.push_back( new PARAM_CFG_INT( true, AC_KEYS::CoroutineStackSize,
                                                &m_coroutineStackSize, AC_STACK::default_stack,
diff --git a/include/advanced_config.h b/include/advanced_config.h
index 177191e4ee..410b1104a7 100644
--- a/include/advanced_config.h
+++ b/include/advanced_config.h
@@ -83,10 +83,17 @@ public:
     double m_drawArcCenterMaxAngle;
 
     /**
-     * Extra fill clearance for zone fills
+     * Extra fill clearance for zone fills.  Note that for zone tests this is essentially
+     * additive with m_DRCEpsilon.
      */
     double m_extraClearance;
 
+    /**
+     * Epsilon for DRC tests.  Note that for zone tests this is essentially additive with
+     * m_extraClearance.
+     */
+    double m_DRCEpsilon;
+
     /**
      * Do real-time connectivity
      */
diff --git a/include/board_design_settings.h b/include/board_design_settings.h
index 36c770393f..5ef0766406 100644
--- a/include/board_design_settings.h
+++ b/include/board_design_settings.h
@@ -89,8 +89,8 @@
 #define MINIMUM_ERROR_SIZE_MM         0.001
 #define MAXIMUM_ERROR_SIZE_MM         0.1
 
-#define DRC_EPSILON                   5;      // An epsilon to account for rounding errors, etc.
-                                              // 5nm is small enough not to materially violate
+#define DRC_EPSILON                   500;    // An epsilon to account for rounding errors, etc.
+                                              // 500nm is small enough not to materially violate
                                               // any constraints.
 
 /**
@@ -797,10 +797,10 @@ public:
 
     /*
      * Function GetDRCEpsilon
-     * an epsilon which accounts for rounding errors, etc.  While currently a global, going
-     * through this API allows us to easily change it to board-specific if so desired.
+     * an epsilon which accounts for rounding errors, etc.  While currently an advanced cfg,
+     * going through this API allows us to easily change it to board-specific if so desired.
      */
-    int GetDRCEpsilon() const { return DRC_EPSILON; }
+    int GetDRCEpsilon() const;
 
     /**
      * Function GetLineThickness
diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp
index 73324859aa..9c9f2730dc 100644
--- a/pcbnew/board_design_settings.cpp
+++ b/pcbnew/board_design_settings.cpp
@@ -33,7 +33,7 @@
 #include <drc/drc_rule.h>
 #include <settings/parameters.h>
 #include <project/project_file.h>
-
+#include <advanced_config.h>
 
 const int bdsSchemaVersion = 0;
 
@@ -960,6 +960,12 @@ int BOARD_DESIGN_SETTINGS::GetLayerClass( PCB_LAYER_ID aLayer ) const
 }
 
 
+int BOARD_DESIGN_SETTINGS::GetDRCEpsilon() const
+{
+    return Millimeter2iu( ADVANCED_CFG::GetCfg().m_DRCEpsilon );
+}
+
+
 int BOARD_DESIGN_SETTINGS::GetLineThickness( PCB_LAYER_ID aLayer ) const
 {
     return m_LineThickness[ GetLayerClass( aLayer ) ];
diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp
index 11ed5ace6d..09df34a7a5 100644
--- a/pcbnew/drc/drc_clearance_test_functions.cpp
+++ b/pcbnew/drc/drc_clearance_test_functions.cpp
@@ -33,7 +33,6 @@
 #include <geometry/polygon_test_point_inside.h>
 #include <geometry/shape_rect.h>
 #include <geometry/shape_segment.h>
-#include <convert_basic_shapes_to_polygon.h>
 
 void DRC::doSingleViaDRC( BOARD_COMMIT& aCommit, VIA* aRefVia )
 {
@@ -419,7 +418,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
             if( !m_reportAllTrackErrors )
                 return;
         }
-        else if( refSeg.Collide( &trackSeg, minClearance, &actual ) )
+        else if( refSeg.Collide( &trackSeg, minClearance - bds.GetDRCEpsilon(), &actual ) )
         {
             wxPoint   pos = GetLocation( aRefSeg, trackSeg.GetSeg() );
             std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_CLEARANCE );
@@ -458,14 +457,8 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
             if( zone->GetFilledPolysList( aLayer ).IsEmpty() )
                 continue;
 
-            // 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 )
-
-
             int minClearance = aRefSeg->GetClearance( aLayer, zone, &m_clearanceSource );
-            int allowedDist  = minClearance + halfWidth - THRESHOLD_DIST;
+            int allowedDist  = minClearance + halfWidth - bds.GetDRCEpsilon();
             int actual;
 
             if( zone->GetFilledPolysList( aLayer ).Collide( testSeg, allowedDist, &actual ) )
@@ -502,7 +495,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
         aRefSeg->GetRuleClearance( &dummyEdge, aRefSeg->GetLayer(), &minClearance,
                                    &m_clearanceSource );
 
-        int center2centerAllowed = minClearance + halfWidth;
+        int center2centerAllowed = minClearance + halfWidth - bds.GetDRCEpsilon();
 
         for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
         {
@@ -534,7 +527,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
                 // Best-efforts search for edge segment
                 BOARD::IterateForward<BOARD_ITEM*>( m_pcb->Drawings(), inspector, nullptr, types );
 
-                int       actual  = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
+                int actual  = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
                 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE );
 
                 m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),