From 2435e774f45597e2e3f9a0affed8951ab7c8ba81 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Apr 2025 19:05:40 +0200 Subject: [PATCH 1/2] Preventing an internal error when using report after 'input' --- src/drc/drc/built-in-macros/_drc_engine.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index fa5cf402c..15c6356a4 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -1585,7 +1585,8 @@ module DRC self._context("report") do # finish what we got so far - _finish(false) + view = RBA::LayoutView::current + @def_output && @def_output.finish(false, view) @def_output = nil @def_output = _make_report(description, filename, cellname) From ffa42653feb97acfa4e665bc09a35db08771de9e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Apr 2025 22:04:50 +0200 Subject: [PATCH 2/2] Addressing issue #2011 - "report" can now be late in DRC without internal error Yet, the report will only capture the output layers after the report statement has been called. - Text objects don't create zero-area polygons in deep mode XOR now. --- src/db/db/dbLocalOperationUtils.cc | 8 +++++-- src/db/db/dbPolygon.h | 18 ++++++++++++++++ src/db/db/dbRegionLocalOperations.cc | 22 +++++++++++++++---- src/db/unit_tests/dbPolygonTests.cc | 29 ++++++++++++++++++++++++++ src/drc/unit_tests/drcSimpleTests.cc | 10 +++++++++ testdata/drc/drcSimpleTests_94.drc | 26 +++++++++++++++++++++++ testdata/drc/drcSimpleTests_94.gds | Bin 0 -> 606 bytes testdata/drc/drcSimpleTests_au94.gds | Bin 0 -> 734 bytes testdata/drc/drcSimpleTests_au94d.gds | Bin 0 -> 692 bytes 9 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_94.drc create mode 100644 testdata/drc/drcSimpleTests_94.gds create mode 100644 testdata/drc/drcSimpleTests_au94.gds create mode 100644 testdata/drc/drcSimpleTests_au94d.gds diff --git a/src/db/db/dbLocalOperationUtils.cc b/src/db/db/dbLocalOperationUtils.cc index c338dbe6d..51d98807d 100644 --- a/src/db/db/dbLocalOperationUtils.cc +++ b/src/db/db/dbLocalOperationUtils.cc @@ -39,7 +39,9 @@ PolygonRefToShapesGenerator::PolygonRefToShapesGenerator (db::Layout *layout, db void PolygonRefToShapesGenerator::put (const db::Polygon &polygon) { tl::MutexLocker locker (&mp_layout->lock ()); - if (m_prop_id != 0) { + if (polygon.is_empty ()) { + // ignore empty polygons + } else if (m_prop_id != 0) { mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id)); } else { mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); @@ -58,7 +60,9 @@ PolygonSplitter::PolygonSplitter (PolygonSink &sink, double max_area_ratio, size void PolygonSplitter::put (const db::Polygon &poly) { - if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) { + if (poly.is_empty ()) { + // ignore empty polygons + } else if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) { std::vector split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 134412e8e..b56a36271 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -1771,6 +1771,14 @@ public: return true; } + /** + * @brief Returns a value indicating that the polygon is an empty one + */ + bool is_empty () const + { + return m_ctrs.size () == size_t (1) && m_ctrs[0].size () == 0; + } + /** * @brief Returns the number of points in the polygon */ @@ -1879,6 +1887,7 @@ public: for (typename contour_list_type::iterator h = m_ctrs.begin (); h != m_ctrs.end (); ++h) { h->transform (db::unit_trans (), true /*compress*/, remove_reflected); } + m_bbox = m_ctrs [0].bbox (); return *this; } @@ -2804,6 +2813,7 @@ public: { // compress the polygon by employing the transform method m_hull.transform (db::unit_trans (), true, remove_reflected); + m_bbox = m_hull.bbox (); return *this; } @@ -3022,6 +3032,14 @@ public: return m_hull.is_halfmanhattan (); } + /** + * @brief Returns a value indicating that the polygon is an empty one + */ + bool is_empty () const + { + return m_hull.size () == 0; + } + /** * @brief The number of holes * diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index 48d974563..64849b712 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -1618,18 +1618,34 @@ bool_and_or_not_local_operation::do_compute_local (db::Layout *layou } } + db::polygon_ref_generator pr (layout, result); + db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ()); + for (auto i = interactions.begin (); i != interactions.end (); ++i) { const TR &subject = interactions.subject_shape (i->first); if (others.find (subject) != others.end ()) { + + // shortcut (and: keep, not: drop) + // Note that we still normalize and split the polygon, so we get a uniform + // behavior. if (m_is_and) { - result.insert (subject); + db::Polygon poly; + subject.instantiate (poly); + splitter.put (poly); } + } else if (i->second.empty ()) { + // shortcut (not: keep, and: drop) + // Note that we still normalize and split the polygon, so we get a uniform + // behavior. if (! m_is_and) { - result.insert (subject); + db::Polygon poly; + subject.instantiate (poly); + splitter.put (poly); } + } else { for (auto e = subject.begin_edge (); ! e.at_end(); ++e) { ep.insert (*e, p1); @@ -1649,8 +1665,6 @@ bool_and_or_not_local_operation::do_compute_local (db::Layout *layou } db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB); - db::polygon_ref_generator pr (layout, result); - db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ()); db::PolygonGenerator pg (splitter, true, true); ep.set_base_verbosity (50); ep.process (pg, op); diff --git a/src/db/unit_tests/dbPolygonTests.cc b/src/db/unit_tests/dbPolygonTests.cc index c9e277d77..dc518c7bd 100644 --- a/src/db/unit_tests/dbPolygonTests.cc +++ b/src/db/unit_tests/dbPolygonTests.cc @@ -69,6 +69,7 @@ TEST(1) EXPECT_EQ (empty == p, true); EXPECT_EQ (p.is_box (), false); + EXPECT_EQ (p.is_empty (), true); std::vector c1, c2, c3; c1.push_back (db::Point (0, 0)); @@ -76,6 +77,7 @@ TEST(1) c1.push_back (db::Point (100, 1000)); c1.push_back (db::Point (100, 0)); p.assign_hull (c1.begin (), c1.end ()); + EXPECT_EQ (p.is_empty (), false); b = p.box (); EXPECT_EQ (p.holes (), size_t (0)); EXPECT_EQ (p.area (), 1000*100); @@ -1404,3 +1406,30 @@ TEST(28) db::Polygon b (db::Box (-1000000000, -1000000000, 1000000000, 1000000000)); EXPECT_EQ (b.perimeter (), 8000000000.0); } + +TEST(29) +{ + // Degenerated boxes and compress + + db::Polygon b (db::Box (10, 20, 10, 20)); + EXPECT_EQ (b.is_empty (), false); + EXPECT_EQ (b == db::Polygon (), false); + EXPECT_EQ (b.to_string (), "(10,20;10,20;10,20;10,20)"); + EXPECT_EQ (double (b.area ()), 0.0); + + b.compress (true); + + EXPECT_EQ (b.is_empty (), true); + EXPECT_EQ (b == db::Polygon (), true); + + db::SimplePolygon sb (db::Box (10, 20, 10, 20)); + EXPECT_EQ (sb.is_empty (), false); + EXPECT_EQ (sb == db::SimplePolygon (), false); + EXPECT_EQ (sb.to_string (), "(10,20;10,20;10,20;10,20)"); + EXPECT_EQ (double (sb.area ()), 0.0); + + sb.compress (true); + + EXPECT_EQ (sb.is_empty (), true); + EXPECT_EQ (sb == db::SimplePolygon (), true); +} diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index f88392542..c618af869 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1694,6 +1694,16 @@ TEST(93d_withAngle) run_test (_this, "93", true); } +TEST(94_texts_in_region_xor) +{ + run_test (_this, "94", false); +} + +TEST(94d_texts_in_region_xor) +{ + run_test (_this, "94", true); +} + TEST(100_edge_interaction_with_count) { run_test (_this, "100", false); diff --git a/testdata/drc/drcSimpleTests_94.drc b/testdata/drc/drcSimpleTests_94.drc new file mode 100644 index 000000000..5809b64af --- /dev/null +++ b/testdata/drc/drcSimpleTests_94.drc @@ -0,0 +1,26 @@ + +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) + +x = l1 ^ l2 + +# we detect point-like polygons here by explicitly +# iterating. The enlargement makes sure, we have something +# to write to the output layout. +boxes = x.data.each.collect do |p| + RBA::Box::new(p.bbox.enlarged(10, 10)) +end +x.data = RBA::Region::new(boxes) + +x.output(10, 0) + diff --git a/testdata/drc/drcSimpleTests_94.gds b/testdata/drc/drcSimpleTests_94.gds new file mode 100644 index 0000000000000000000000000000000000000000..7e3a7cd5206cda09c06762097b7c95bc20b1b6ba GIT binary patch literal 606 zcmZQzV_;&6V31*CVt>iN!XU*U#=yY9gUn{&U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLWX&V`B^P4`5(m;b353<7HxCWMJcC0-CNP!2JLJe-#D>rUnSjybUPY#J~Wf zVd6{;3@m~`{XB5}Vj%r&;*1O&3_KuH{!UZ{lq9~Xmg;@F#DJ57bSlHWG2>yXwkwQ}V z0sezUy8J*~=eS#M*POv>j=7n=nc0JZ$ORH5^$8-h(S$)Ju*ZtwK{ zWxC%@cb*>?;sjd;Bi3Sv6|BRZL+v{`SP*=`+PbW9a z_s!`=a{M|Q^buFK_>Ae_-2+h#FuTI z{q@xU{Q{^jm?P7pqFhAR0J}KV{xap!#=XPvy7AclF!zRAueud+h|hG?{C}y@>jg hIiCx3yo`cgLO=UdN!F_j>E|!w(D5qC{8grn@Cy^pZF2ws literal 0 HcmV?d00001