diff --git a/src/db/db/dbEdgePairRelations.cc b/src/db/db/dbEdgePairRelations.cc index a1309898e..e5da82d64 100644 --- a/src/db/db/dbEdgePairRelations.cc +++ b/src/db/db/dbEdgePairRelations.cc @@ -93,16 +93,22 @@ 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 + db::Edge g (other); + + // s1 = side of g.p1 wrt e + // s2 = side of g.p2 wrt e + int s1, s2; if (e.is_degenerate ()) { - return false; + 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 ()); } - db::Edge g (other); - int s1 = e.side_of (g.p1 ()); - int 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; + if (e.is_degenerate ()) { - 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,17 +258,22 @@ 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 + db::Edge g (other); + // s1 = side of g.p1 wrt e + // s2 = side of g.p2 wrt e + int s1, s2; if (e.is_degenerate ()) { - return false; + 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 ()); } - db::Edge g (other); - int s1 = e.side_of (g.p1 ()); - int 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,54 @@ 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 + // 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 { db::DPoint e1d = db::DPoint (e.p1 ()) + en * double (d); @@ -306,11 +353,26 @@ 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 (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; + + allow_zero_projection = true; + } + } else { double det = db::vprod (db::DVector (g.d ()), en); @@ -330,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) { + if (allow_zero_projection ? l1 > l2 + db::epsilon : l1 > l2 - db::epsilon) { return false; } else { if (output) { @@ -410,7 +472,14 @@ 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", 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)"); 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 @@ def #{f}(*args) # # 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 @@ def #{f}(*args) 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 @@ def merged(overlap_count = 1) 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..258c5969d 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -2044,3 +2044,25 @@ 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); +} + +// 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_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 000000000..5ded0984e Binary files /dev/null and b/testdata/drc/drcSimpleTests_145.gds differ 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 000000000..bb2a9b3f9 Binary files /dev/null and b/testdata/drc/drcSimpleTests_146.gds differ diff --git a/testdata/drc/drcSimpleTests_au145.gds b/testdata/drc/drcSimpleTests_au145.gds new file mode 100644 index 000000000..3e5c58ed7 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au145.gds differ diff --git a/testdata/drc/drcSimpleTests_au145d.gds b/testdata/drc/drcSimpleTests_au145d.gds new file mode 100644 index 000000000..243f03859 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au145d.gds differ diff --git a/testdata/drc/drcSimpleTests_au146.gds b/testdata/drc/drcSimpleTests_au146.gds new file mode 100644 index 000000000..d85bb1933 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au146.gds differ diff --git a/testdata/drc/drcSimpleTests_au146d.gds b/testdata/drc/drcSimpleTests_au146d.gds new file mode 100644 index 000000000..7ea9e5329 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au146d.gds differ