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 000000000..7e3a7cd52 Binary files /dev/null and b/testdata/drc/drcSimpleTests_94.gds differ diff --git a/testdata/drc/drcSimpleTests_au94.gds b/testdata/drc/drcSimpleTests_au94.gds new file mode 100644 index 000000000..eeddc48bf Binary files /dev/null and b/testdata/drc/drcSimpleTests_au94.gds differ diff --git a/testdata/drc/drcSimpleTests_au94d.gds b/testdata/drc/drcSimpleTests_au94d.gds new file mode 100644 index 000000000..bb39fbbcc Binary files /dev/null and b/testdata/drc/drcSimpleTests_au94d.gds differ