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.
This commit is contained in:
Matthias Koefferlein 2025-04-26 22:04:50 +02:00
parent 2435e774f4
commit ffa42653fe
9 changed files with 107 additions and 6 deletions

View File

@ -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 <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);

View File

@ -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<C> (), 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<C> (), 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
*

View File

@ -1618,18 +1618,34 @@ bool_and_or_not_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layou
}
}
db::polygon_ref_generator<TR> 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<TS, TI, TR>::do_compute_local (db::Layout *layou
}
db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::polygon_ref_generator<TR> 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);

View File

@ -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 <db::Point> 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);
}

View File

@ -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);

26
testdata/drc/drcSimpleTests_94.drc vendored Normal file
View File

@ -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)

BIN
testdata/drc/drcSimpleTests_94.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au94.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au94d.gds vendored Normal file

Binary file not shown.