From af6762b52d4aea8e6f75c15df0c58be8c0fa28dd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 4 Sep 2025 21:58:46 +0200 Subject: [PATCH 1/4] Fixing issue #2134 ('merged' on edge layers not working in DRC) --- src/drc/drc/built-in-macros/_drc_layer.rb | 17 +++++++++++++++-- src/drc/unit_tests/drcSimpleTests.cc | 11 +++++++++++ testdata/drc/drcSimpleTests_145.drc | 22 ++++++++++++++++++++++ testdata/drc/drcSimpleTests_145.gds | Bin 0 -> 842 bytes testdata/drc/drcSimpleTests_au145.gds | Bin 0 -> 3290 bytes testdata/drc/drcSimpleTests_au145d.gds | Bin 0 -> 2084 bytes 6 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_145.drc create mode 100644 testdata/drc/drcSimpleTests_145.gds create mode 100644 testdata/drc/drcSimpleTests_au145.gds create mode 100644 testdata/drc/drcSimpleTests_au145d.gds diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 6c119936d..7eee5f905 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -5079,6 +5079,7 @@ CODE # # This method works both on edge or polygon layers. Edge merging forms # single, continuous edges from coincident and connected individual edges. + # The overlap count is only available on polygon layers. # # A version that modifies the input layer is \merge. # @@ -5106,7 +5107,13 @@ CODE def merged(overlap_count = 1) @engine._context("merged") do requires_edges_or_region - aa = [ @engine._prep_value(overlap_count) ] + oc = @engine._prep_value(overlap_count) + if self.data.is_a?(RBA::Edges) + oc == 1 || raise("'overlap_count' (merged) is only available on polygon layers") + aa = [] + else + aa = [ oc ] + end DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :merged, *aa)) end end @@ -5114,7 +5121,13 @@ CODE def merge(overlap_count = 1) @engine._context("merge") do requires_edges_or_region - aa = [ @engine._prep_value(overlap_count) ] + oc = @engine._prep_value(overlap_count) + if self.data.is_a?(RBA::Edges) + oc == 1 || raise("'overlap_count' (merged) is only available on polygon layers") + aa = [] + else + aa = [ oc ] + end if @engine.is_tiled? # in tiled mode, no modifying versions are available self.data = @engine._tcmd(self.data, 0, self.data.class, :merged, *aa) diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 8e46d2d74..85547ab6b 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -2044,3 +2044,14 @@ TEST(144d_combined_antennas) run_test (_this, "144", true); } +// issue 2134 +TEST(145_edges_merge) +{ + run_test (_this, "145", false); +} + +TEST(145d_edges_merge) +{ + run_test (_this, "145", true); +} + diff --git a/testdata/drc/drcSimpleTests_145.drc b/testdata/drc/drcSimpleTests_145.drc new file mode 100644 index 000000000..c5c5e094e --- /dev/null +++ b/testdata/drc/drcSimpleTests_145.drc @@ -0,0 +1,22 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) + +l1.raw.edges.merged.output(100, 0) +l2.raw.edges.merged.output(101, 0) +l3e = l3.raw.edges +l3e.merge +l3e.output(102, 0) + diff --git a/testdata/drc/drcSimpleTests_145.gds b/testdata/drc/drcSimpleTests_145.gds new file mode 100644 index 0000000000000000000000000000000000000000..5ded0984e1f99889e8a1733705d08d0530737163 GIT binary patch literal 842 zcmb7?F;2rU7=>SK$1y6AQT`M7$V3;24FMgTEFL7zbGQmx&@MFM>i)zEO|W(^&e}b z(VE!o1N_y~&5dWNPw-bt^KYVIQZ7?oxgMF6^I2Rx8q!iNN*^Ihxg9hH-&pQ6tH(wP zkVlRG@X&fRA&)vMjq$LtVcWJoY}>ZC#*S`Yp2jSVDJi?BXVcD1d(+PLQ)5f3(ixqu z-_Px9v)ax=kD_NSsvbAF^{BDT`*p*D8)ExCHy^0y%MoyW=;`K$zv}5$k)EFX%G1pa IU0*`r6Sp~u1ONa4 literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au145.gds b/testdata/drc/drcSimpleTests_au145.gds new file mode 100644 index 0000000000000000000000000000000000000000..3e5c58ed74658dcd2db1a2bd4505a7045ad75e21 GIT binary patch literal 3290 zcmb7`F>6#o6opS_H!r)0CPIW1DYOzK5V0_^2^dls5>zCG3W7yUCunIQ*!mmNq)Tg= zGL_^f#4LU@hUxv+4BDaN>iO-%Fen1pVB zcN0c3tNio3apk-7$V(MB9pvekKIQwX-HQIHir4&;V;(B= zl9MVvE59K<&$`J=6*tZOhrItc&VX0;V5n~{fzQvbRdLfQKl&AU-s9n?_?@b_=^)QF z5B|ipk1irBRot}7^B&4Y5Bex>TIE?M*Rp=~fvR||e)fw#sr3D2N|P* zpejBqKfRNuXL3@-i~2|T^XDGX#eK)UBURiq@83WC$MHRi!QpHqgpg2Q#X@>ZEs3+jBtC%|t4%I_V zDW5~lDAR^qqO2heRNuh(C#OCP@55q>IVrwxeCMe)3mPa*JU_*ET$JWZ>U^axQgZ00 zSdTt-hlaYCFZI$%akX-pIw=yImQ6UJbLpgtQ@(*3IEgBCgVm|2Gz_D`Wfx6g3bp literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au145d.gds b/testdata/drc/drcSimpleTests_au145d.gds new file mode 100644 index 0000000000000000000000000000000000000000..243f03859f60045368f869281b9f8eef258a9af0 GIT binary patch literal 2084 zcmb7Ezfaph7=1ZA7XvLx3zecOLprfkB@?tur9g*PRDh}sfW$^S)1gBLcK91u*jO1D zGIr|R43#o=OgF|3NbdLUeE4iIIZkq(b@|@+^ZA2@Qak9>RO2sZ5aStMW7dC1qV&fP zYrtYuf7?G<-S~Na_2%7h`RsIWfKI)dr?u__aRTVa3N`3?1>j{XO4EP6H2s|rfrVqB z@ynsRCnA25^OeuPZj+Oy#O4_gO>%Vi;?wYFZ2W_auU{xAB+W>2k(z8aF1kUV^|_i= zifvd8OzVjBF`ko*p0YRkc};S7)Tyssnrwh%ft{+M)3W(tZfO7U&_oLLvDAX`QNjoK zNYn8ZeU!1#-O4`M*>FD5#LO$WyR^0w7IrYpk5|x7-iHvOny zs+Cak7R+)n4F<7*Vy1<@RAxxl?YgFDHPL#owSA*j(QU5Qy}Q))0IwU*G5G?gj7VQ=8=T=^f_i?n~;c+#|M} zl?&iVUIqP$-ov6bzfK;(Ko+gJ`N$RwWYK!FD?f4s16j1*|6yYZ2C^8-J3ed5w%{bc zx6LF2S+wT7IWsr!Z0}Er>R!JidU@^Pw31m^v%#ig72C`_)IAjY3vNCJKa Date: Thu, 4 Sep 2025 23:30:39 +0200 Subject: [PATCH 2/4] First solution, needs more testing --- src/db/db/dbEdgePairRelations.cc | 165 +++++++++++++++++-------- src/drc/unit_tests/drcSimpleTests.cc | 11 ++ testdata/drc/drcSimpleTests_146.drc | 51 ++++++++ testdata/drc/drcSimpleTests_146.gds | Bin 0 -> 510 bytes testdata/drc/drcSimpleTests_au146.gds | Bin 0 -> 7546 bytes testdata/drc/drcSimpleTests_au146d.gds | Bin 0 -> 8910 bytes 6 files changed, 174 insertions(+), 53 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_146.drc create mode 100644 testdata/drc/drcSimpleTests_146.gds create mode 100644 testdata/drc/drcSimpleTests_au146.gds create mode 100644 testdata/drc/drcSimpleTests_au146d.gds diff --git a/src/db/db/dbEdgePairRelations.cc b/src/db/db/dbEdgePairRelations.cc index a1309898e..5d32bcc27 100644 --- a/src/db/db/dbEdgePairRelations.cc +++ b/src/db/db/dbEdgePairRelations.cc @@ -93,15 +93,21 @@ static bool include_zero_flag (zero_distance_mode zd_mode, const db::Edge &a, co */ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output) { - // Handle the case of point-like basic edge: cannot determine - // orientation - if (e.is_degenerate ()) { - return false; - } - db::Edge g (other); - int s1 = e.side_of (g.p1 ()); - int s2 = e.side_of (g.p2 ()); + + // s1 = side of g.p1 wrt e + // s2 = side of g.p2 wrt e + int s1, s2; + if (e.is_degenerate ()) { + if (g.contains (e.p1 ())) { + s1 = s2 = 0; + } else { + s1 = s2 = -1; + } + } else { + s1 = e.side_of (g.p1 ()); + s2 = e.side_of (g.p2 ()); + } bool include_zero = include_zero_flag (zd_mode, e, g); int thr = include_zero ? 0 : -1; @@ -115,33 +121,49 @@ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits thr) { - return false; - } - - double a = e.double_sq_length (); - double b = db::sprod (db::Vector (e.p1 () - o), e.d ()) / a; - double c = (e.p1 ().sq_double_distance (o) - double (d) * double (d)) / a; - - double s = b * b - c; - if (s >= -db::epsilon) { - double l1 = std::max (0.0, (-b - sqrt (s))); - double l2 = std::min (1.0, (-b + sqrt (s))); - if (l1 <= l2) { + // point vs. point + if (e.p1 ().distance (g.p1 ()) < double (d)) { if (output) { *output = g; } return true; } - } - return false; + return false; + + } else { + + db::Point o = g.p1 (); + + if (e.side_of (o) > thr) { + return false; + } + + double a = e.double_sq_length (); + double b = db::sprod (db::Vector (e.p1 () - o), e.d ()) / a; + double c = (e.p1 ().sq_double_distance (o) - double (d) * double (d)) / a; + + double s = b * b - c; + if (s >= -db::epsilon) { + double l1 = std::max (0.0, (-b - sqrt (s))); + double l2 = std::min (1.0, (-b + sqrt (s))); + if (l1 <= l2) { + if (output) { + *output = g; + } + return true; + } + } + + return false; + + } } @@ -150,10 +172,13 @@ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::max (), l2 = -std::numeric_limits::max (); // handle the parallel case + // NOTE: a point is "parallel" to an edge. if (e.parallel (g)) { + if (std::abs (double (e.distance (g.p1 ()))) >= double (d)) { return false; } + } else { double ef = 1.0 / e.double_length (); @@ -233,16 +258,21 @@ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits::distance_type d, db::coord_traits::distance_type dd, const db::Edge &e, const db::Edge &other, db::Edge *output) { - // Handle the case of point-like basic edge: cannot determine - // orientation - - if (e.is_degenerate ()) { - return false; - } - db::Edge g (other); - int s1 = e.side_of (g.p1 ()); - int s2 = e.side_of (g.p2 ()); + + // s1 = side of g.p1 wrt e + // s2 = side of g.p2 wrt e + int s1, s2; + if (e.is_degenerate ()) { + if (g.contains (e.p1 ())) { + s1 = s2 = 0; + } else { + s1 = s2 = -1; + } + } else { + s1 = e.side_of (g.p1 ()); + s2 = e.side_of (g.p2 ()); + } bool include_zero = include_zero_flag (zd_mode, e, g); int thr = include_zero ? 0 : -1; @@ -259,37 +289,53 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< // Handle the case of point vs. edge if (g.is_degenerate ()) { - if (e.side_of (g.p1 ()) > thr) { - return false; - } - if (double (e.distance (g.p1 ())) <= -double (d)) { - return false; - } - if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ())) { - return false; - } - if (db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) { - return false; + + if (! e.is_degenerate ()) { + if (e.side_of (g.p1 ()) > thr) { + return false; + } + if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ())) { + return false; + } + if (db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) { + return false; + } + if (double (e.distance (g.p1 ())) <= -double (d)) { + return false; + } + } else { + // point to point + if (e.p1 ().distance (g.p1 ()) >= double (d)) { + return false; + } } + if (output) { *output = g; } return true; + } // Determine body interactions (projected mode) - double l1 = std::numeric_limits::min (), l2 = std::numeric_limits::max (); + double l1 = std::numeric_limits::lowest (), l2 = std::numeric_limits::max (); - double ef = 1.0 / e.double_length (); - db::DVector ep = db::DVector (ef * e.dx (), ef * e.dy ()); - db::DVector en = db::DVector (ef * e.dy (), -ef * e.dx ()); + db::DVector ep, en; + double ef = 0.0; + if (! e.is_degenerate ()) { + ef = 1.0 / e.double_length (); + ep = db::DVector (ef * e.dx (), ef * e.dy ()); + en = db::DVector (ef * e.dy (), -ef * e.dx ()); + } // handle the parallel case if (e.parallel (g)) { + if (std::abs (double (e.distance (g.p1 ()))) >= double (d)) { return false; } + } else { db::DPoint e1d = db::DPoint (e.p1 ()) + en * double (d); @@ -307,10 +353,21 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< } if (db::sprod_sign (e, g) == 0) { - if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ()) || - db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) { - return false; + + if (! g.is_degenerate ()) { + + if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ()) || + db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) { + return false; + } + + double l = db::sprod (db::DVector (e.p1 () - g.p1 ()), db::DVector (g.d ())) / g.double_sq_length (); + double dl = double (dd) / g.double_length (); + l1 = l - dl; + l2 = l + dl; + } + } else { double det = db::vprod (db::DVector (g.d ()), en); @@ -410,7 +467,9 @@ EdgeRelationFilter::check (const db::Edge &a, const db::Edge &b, db::EdgePair *o // Check whether the edges have an angle less than the ignore_angle parameter - if (m_ignore_angle == 90.0) { + if (a.is_degenerate () || b.is_degenerate ()) { + // accept dots as "always good" + } else if (m_ignore_angle == 90.0) { if (db::sprod_sign (aa, b) >= 0) { return false; } diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 85547ab6b..258c5969d 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -2055,3 +2055,14 @@ TEST(145d_edges_merge) run_test (_this, "145", true); } +// issue 2141 +TEST(146_edges_and_corners) +{ + run_test (_this, "146", false); +} + +TEST(146d_edges_and_corners) +{ + run_test (_this, "146", true); +} + diff --git a/testdata/drc/drcSimpleTests_146.drc b/testdata/drc/drcSimpleTests_146.drc new file mode 100644 index 000000000..b52cb8548 --- /dev/null +++ b/testdata/drc/drcSimpleTests_146.drc @@ -0,0 +1,51 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l2 = input(2, 0) + +l1.output(1, 0) +l2.output(2, 0) +l1e = l1.edges +l2e = l2.edges +l1c = l1.corners(as_dots) +l2c = l2.corners(as_dots) + +l1e.sep(l2c, 0.6).output(100, 0) +l1c.sep(l2e, 0.6).output(101, 0) +l1c.sep(l2c, 0.6).output(102, 0) +l1e.enc(l2c, 0.6).output(103, 0) +l1c.enc(l2e, 0.6).output(104, 0) +l1c.enc(l2c, 0.6).output(105, 0) +l2e.width(1.0).output(106, 0) +l2c.width(1.0).output(107, 0) +l2e.space(2.0).output(108, 0) +l2c.space(2.0).output(109, 0) + +l1e.sep(l2c, 0.6, square).output(110, 0) +l1c.sep(l2e, 0.6, square).output(111, 0) +l1c.sep(l2c, 0.6, square).output(112, 0) +l1e.enc(l2c, 0.6, square).output(113, 0) +l1c.enc(l2e, 0.6, square).output(114, 0) +l1c.enc(l2c, 0.6, square).output(115, 0) +l2e.width(1.0, square).output(116, 0) +l2c.width(1.0, square).output(117, 0) +l2e.space(2.0, square).output(118, 0) +l2c.space(2.0, square).output(119, 0) + +l1e.sep(l2c, 0.6, projection).output(120, 0) +l1c.sep(l2e, 0.6, projection).output(121, 0) +l1c.sep(l2c, 0.6, projection).output(122, 0) +l1e.enc(l2c, 0.6, projection).output(123, 0) +l1c.enc(l2e, 0.6, projection).output(124, 0) +l1c.enc(l2c, 0.6, projection).output(125, 0) +l2e.width(1.0, projection).output(126, 0) +l2c.width(1.0, projection).output(127, 0) +l2e.space(2.0, projection).output(128, 0) +l2c.space(2.0, projection).output(129, 0) + diff --git a/testdata/drc/drcSimpleTests_146.gds b/testdata/drc/drcSimpleTests_146.gds new file mode 100644 index 0000000000000000000000000000000000000000..bb2a9b3f9b8ddce688a24ee8778406f9e4a57242 GIT binary patch literal 510 zcma)&y-q?w5Ju1b4VM7sip0X)!Ur&+Bs3-{jgdqO3gh$G*xA$A*;rWe1U`iYrF8U0 z*STCag2v!(CTB9)`M#Y&u=bk5*xG_RofIeVE=% zD8k=;BBEVB18G?-vS)#l+{O4YjPbKs65K8557tcelK6e?ud&Nz@a gx|KJLZLTzaZxtFdF!vQh2U<@$@0zKuOk4GyFLOy$B>(^b literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au146.gds b/testdata/drc/drcSimpleTests_au146.gds new file mode 100644 index 0000000000000000000000000000000000000000..66262fc23a950bd571f55429ba6cf32ffdf6c9b7 GIT binary patch literal 7546 zcmbtYJC7Vi5U!ouo7=nP5XeRZn2Zb~G7t$87702_5I6u52+SMvG`55UhJXNJWD}xG zkZeQ%#2Aqf@k=1EL_kPlL4DO#GgZCw>e-QQ>$bbUsn^$4bw@Q-)$?>}QSIHPeOl7} z^Z-5Pf2UPdpMB;G(aD|NC!hNA@uNR}_~(hIZ$0|m@r&o^)b0STuFpOD9MN(`R3BEf zp!)8Lh)&X=4StmeR}oTfyKi~&*JwaJ8-Z1d>(w=#*>*s zYqb~til1rU>kW8X0FQ??F}~4ncFTT^KtDjk~@F{&? z9{1sx>;I-R#$)qe*S(+4PS*8j!hy5k+v>dPO6xs1oWYaq1Frfzt)$Oj=j&};8h%aT zT{mu=cLCS%XPkH4xN+XSu_f;Ueg^N}^!kP8e6JvP@8deg95M;s>%PzHw)nS#e$-Lu zf#mvtI@(BEzZUor@P|M0dFB(O)M40ny$f0WbdXIq{!yxbMKrz1Q_YJnH|6 zWWU6X?Qf*5p9uQj_Wsv5*iQBnvi@H6a~`bj=)SlAg2$Wxx%~tF2fX>8$8W&@O}yE! zKA0cKqr5-nFW_<3{I~OnpX7n#r~AGBOaH|=^ib%BL>!S9yeH+S7cYIg125~i56EZC zU$kHIhk7r$;<^F-VmJFgmOtxj)-S{d#oPNhKE3wKy|H^T?fwM&jX!z*r}9Vo0P>H1 z(4k-V`|U@4F1vrh{#?Jr1H3~$F}p_MS9pJee(BS!MO=Jc<7_@l>*F|^2mWH8IbR)fXwVnt0oG^tRo8p< zH8|vl^}trh4%~abp4%LTI82;F1AfLl@O~TLFq6>^=TrE5-PS{1G91r_M>xkb;hlu5 zZ>I0dqdpwZp)aK~a$mt4ox^qA$Jgm=bqUuQx4L7xME2mYhsXTlS^JB$l0Ji-AGC34 zcp`io;axXwoOc0dL;>G~J1kMp^zr_6aM&$&H({0{Z{dIeq;^}c<=^ug!E77*FGxi z-E(Nb>zuiP&+_Q=AMlpHf;lwct*;f#p#d-VhT~Uoe*)h4ljnabf20o}f0%tZ-}(L3 z{oeQ)|8o9Lsv|x+!lW&=r8Y|0YBsZ2mFlt z8}a4$?=$be)nCY_Zw&X(&pqD!&+E@X{R?>WKd+wy^=lJf);|M&M*j?W)XBpB8Spdu zXTV$j3i@Zj&*+~4Z+*i0M&7@4-`C%OH~!@LpUR)Sf93i+`d83z{LA?}m4CT@i-W~w iRDb#X4ffCIp8>D^v7~)!8tr@pH5-8((hr*``o zt+m>7f6y-K(kk6VciR8cpxuAqz5_(NJH31NzjN39-*5kU_r}%RKEC|$5nAh&$i`vo_BrBU-7seAnh|A^pkS?&t zz6u=T&NA0KR$qd{zMxBIFL>r8V$XH?+S}ke&HIdT0^g&feqh}%qkaXS*2lX3T3okv zCV14d8S4vmD(@BKA7XsCZt;&feZfPw1CM^T{=)tE-1#O(s zKgYc5=Sj;~_{h$s03xbc1t?qFQV+xilm^z&%+j|v|-HDf;$e0D#d zb^7A`vX{B%f}CsQZM_K&y}TT8>Ob8F*$+a#5*Oyr`p-`hm-vt4qia&9!SOnhFX02` zYsMKLIUYa9ysPgyr;GZ?^tnrLSU>fV$#a+BYR_GQi+t_rbNBp=bC=**$1ERtWk&u4 zpUr=IM*aj}pC7LyQ{MUx-~h;5UwgDmxaLNj+?@?5eU=FCof0+A(M|DF4iDGuoWVUm z5Dh*Aerpst&+gkfwqNANl9cM}Cg=_(gB+KlhRMFLMz3!2PJ;pVaqM|M_zj_4E94 z|2cC1kC~|XO8s#^-T<`^Mcq6%A%8ZY+){d#T??fmLFis#Dlzclh6>ATLa%xy8hdanHZzC6OmdR1rj3!UFl9~{5IgFoND z9DY*&m0$Oh_?N-6{^)P;Pw6B33HOovAN-WBSL~ntJtaIS$v$_8<9*=T|-da{LYa%i)7>sZZ7OFOOg6^C@%8&kNQwM9p)ou3vph&z(li zBU=A4{GuQGMScG=cGc%iyv1eE)iL&w64KlnFT;lEn6 zXpR5kz~7in_z7CYHSk;Slr{KUsm|~C@zLsSeqSb9xQcI<-;1%gn`r5Ce5)c+^N1Gj z-uIV26a2RkxA2|dzleFcUW#7;j(PaLzzZBlUMKL!>!o<*Pw`82`B8swMe5%p^=s7p zN_qXde~!9ujdk`P^uHi|ct7&DG;02W<2TRSsGIUAFUN}d9bWgJ>Q|w^!#B|1;ko`y z{XJghCqsXa=lNHiRdU;iiV`(DtG`^4vu z&n^3h#L!pXpYPwS_!Evle|{alLH`_H=O@%JzNtQ-zJO@`)8q5?f5Fus_07?LR{V>O wKVN@`Z=k=!H_+eX^Ywq-)t|5btoSz^f4=?>-#~wdZ=k=&XXuajy>6HO2j2tKlmGw# literal 0 HcmV?d00001 From a9d52b7a70b746137ca6cd477c3903c5382ad59c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 5 Sep 2025 08:05:27 +0200 Subject: [PATCH 3/4] Fixing case of point vs. edge in projecting mode --- src/db/db/dbEdgePairRelations.cc | 3 ++- testdata/drc/drcSimpleTests_au146.gds | Bin 7546 -> 7930 bytes testdata/drc/drcSimpleTests_au146d.gds | Bin 8910 -> 9294 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbEdgePairRelations.cc b/src/db/db/dbEdgePairRelations.cc index 5d32bcc27..de4f46078 100644 --- a/src/db/db/dbEdgePairRelations.cc +++ b/src/db/db/dbEdgePairRelations.cc @@ -330,6 +330,7 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< } // handle the parallel case + // NOTE: a point is "parallel" to an edge if (e.parallel (g)) { if (std::abs (double (e.distance (g.p1 ()))) >= double (d)) { @@ -387,7 +388,7 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< l1 = std::max (0.0, l1); l2 = std::min (1.0, l2); - if (l1 >= l2) { + if (l1 > l2 + db::epsilon) { return false; } else { if (output) { diff --git a/testdata/drc/drcSimpleTests_au146.gds b/testdata/drc/drcSimpleTests_au146.gds index 66262fc23a950bd571f55429ba6cf32ffdf6c9b7..d85bb1933ae7815c9da5a0f5f58d47d1fe5744ac 100644 GIT binary patch delta 459 zcmZvYJr05}7>3_gsHo9s8kn3&oWu)|cn{-AOdJ|_6C@sicmU&~qepS{3QYDFN^pAM z{rY@;q0Z}V3IkzvjtF9Q_Wmi|(K)?M7HimSEwP^s E0N?BmMF0Q* diff --git a/testdata/drc/drcSimpleTests_au146d.gds b/testdata/drc/drcSimpleTests_au146d.gds index 8621421d653e54fb6efaa41ea90a9c9f53ee2d1f..7ea9e5329918294c7d7637c7f741075eb3000fbe 100644 GIT binary patch delta 508 zcmZvZI|>3p42J(5bsvhN*jNZYz|I4B0m0HzJc+Q%Vq-5`ig!>fyoI%eU~MhhD8__g za7MQJhCh6hker66Q5QaxnxN^a;D!hVgz!+e-|KF#o)Pb-*D#sEuP6ZhY7WS?fWk#H z2$>zg(B#Z~4ajrZFDqC+5pBfR3_|8sd`*+PemaPjN$kwf2E04>7CyMq&Z5ch&J2G( z(K{BOxe(u?$z$73;C|2|dW~fXEY4*KKbo9rFTwJOJ|*!r-*aYJd`*)(etL{nS@$`N Mi)kgZ@NAr;FZ(5a5&!@I delta 124 zcmX@-an4nVfsKKQDS| Date: Fri, 5 Sep 2025 23:48:49 +0200 Subject: [PATCH 4/4] Excluding degenerated edges from polygons so we don't consider them corners, addressing duplicate corners with zero distance. --- src/db/db/dbEdgePairRelations.cc | 13 +++++++++++-- src/db/db/dbRegionCheckUtils.cc | 8 +++++--- src/db/unit_tests/dbEdgePairRelationsTests.cc | 10 ++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/db/db/dbEdgePairRelations.cc b/src/db/db/dbEdgePairRelations.cc index de4f46078..e5da82d64 100644 --- a/src/db/db/dbEdgePairRelations.cc +++ b/src/db/db/dbEdgePairRelations.cc @@ -353,6 +353,8 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< } + bool allow_zero_projection = false; + if (db::sprod_sign (e, g) == 0) { if (! g.is_degenerate ()) { @@ -367,6 +369,8 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< l1 = l - dl; l2 = l + dl; + allow_zero_projection = true; + } } else { @@ -388,7 +392,7 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits< l1 = std::max (0.0, l1); l2 = std::min (1.0, l2); - if (l1 > l2 + db::epsilon) { + if (allow_zero_projection ? l1 > l2 + db::epsilon : l1 > l2 - db::epsilon) { return false; } else { if (output) { @@ -469,7 +473,12 @@ EdgeRelationFilter::check (const db::Edge &a, const db::Edge &b, db::EdgePair *o // Check whether the edges have an angle less than the ignore_angle parameter if (a.is_degenerate () || b.is_degenerate ()) { - // accept dots as "always good" + // accept dots as "always good", expect if they are identical and the zero distance mode does not include this case + if (a == b && (m_zero_distance_mode == NeverIncludeZeroDistance || + m_zero_distance_mode == IncludeZeroDistanceWhenCollinearAndTouching || + m_zero_distance_mode == IncludeZeroDistanceWhenOverlapping)) { + return false; + } } else if (m_ignore_angle == 90.0) { if (db::sprod_sign (aa, b) >= 0) { return false; diff --git a/src/db/db/dbRegionCheckUtils.cc b/src/db/db/dbRegionCheckUtils.cc index f57ef287e..7f71edb4c 100644 --- a/src/db/db/dbRegionCheckUtils.cc +++ b/src/db/db/dbRegionCheckUtils.cc @@ -463,8 +463,10 @@ void poly2poly_check::enter (const PolygonType &o, size_t p) { for (typename PolygonType::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) { - m_edge_heap.push_back (*e); - m_scanner.insert (& m_edge_heap.back (), p); + if (! (*e).is_degenerate ()) { + m_edge_heap.push_back (*e); + m_scanner.insert (& m_edge_heap.back (), p); + } } } @@ -497,7 +499,7 @@ poly2poly_check::enter (const PolygonType &o, size_t p, const poly2 } for (typename PolygonType::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) { - if (interact (box, *e)) { + if (! (*e).is_degenerate () && interact (box, *e)) { m_edge_heap.push_back (*e); m_scanner.insert (& m_edge_heap.back (), p); } diff --git a/src/db/unit_tests/dbEdgePairRelationsTests.cc b/src/db/unit_tests/dbEdgePairRelationsTests.cc index 42bc669d3..c0809bbda 100644 --- a/src/db/unit_tests/dbEdgePairRelationsTests.cc +++ b/src/db/unit_tests/dbEdgePairRelationsTests.cc @@ -135,7 +135,8 @@ TEST(3) EXPECT_EQ (output.to_string (), "(80,0;-60,-100)"); EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true); EXPECT_EQ (output.to_string (), "(-100,0;-100,-100)"); - EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false); + EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true); + EXPECT_EQ (output.to_string (), "(-100,100;-100,-100)"); // dot vs. line (issue #2141) EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false); EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true); EXPECT_EQ (output.to_string (), "(100,-50;100,-50)"); @@ -170,14 +171,15 @@ TEST(4) EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), false); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), false); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true); - EXPECT_EQ (output.to_string (), "(100,0;100,-100)"); + EXPECT_EQ (output.to_string (), "(100,0;100,0)"); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true); - EXPECT_EQ (output.to_string (), "(80,0;80,-100)"); + EXPECT_EQ (output.to_string (), "(80,0;80,0)"); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), false); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true); EXPECT_EQ (output.to_string (), "(80,0;0,-57)"); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false); - EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false); + EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true); + EXPECT_EQ (output.to_string (), "(-100,0;-100,0)"); // dot vs. line (issue #2141) EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false); EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true); EXPECT_EQ (output.to_string (), "(100,-50;100,-50)");