From 9382e259cef9c213e8096ad9a01723274076c9f8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 22 Jul 2026 23:11:26 +0200 Subject: [PATCH] Adding support for min_coherence toggling in OriginalLayerRegion --- src/db/db/dbOriginalLayerRegion.cc | 69 +++++++++++-- src/db/db/dbOriginalLayerRegion.h | 12 ++- src/db/unit_tests/dbAsIfFlatRegionTests.cc | 112 +++++++++++++++++++++ 3 files changed, 181 insertions(+), 12 deletions(-) diff --git a/src/db/db/dbOriginalLayerRegion.cc b/src/db/db/dbOriginalLayerRegion.cc index 674ff7ec3..f96c783fb 100644 --- a/src/db/db/dbOriginalLayerRegion.cc +++ b/src/db/db/dbOriginalLayerRegion.cc @@ -142,28 +142,34 @@ OriginalLayerRegion::OriginalLayerRegion () OriginalLayerRegion::OriginalLayerRegion (const OriginalLayerRegion &other) : AsIfFlatRegion (other), m_is_merged (other.m_is_merged), + m_is_merged_min_coherence (other.m_is_merged_min_coherence), m_merged_polygons (other.m_merged_polygons), m_merged_polygons_valid (other.m_merged_polygons_valid), + m_merged_polygons_min_coherence (other.m_merged_polygons_min_coherence), m_iter (other.m_iter), m_iter_trans (other.m_iter_trans) { // .. nothing yet .. } -OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged) +OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged, bool min_coh) : AsIfFlatRegion (), m_merged_polygons (false), m_iter (si) { init (); + set_min_coherence (min_coh); m_is_merged = is_merged; + m_is_merged_min_coherence = min_coh; } -OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) +OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged, bool min_coh) : AsIfFlatRegion (), m_merged_polygons (false), m_iter (si), m_iter_trans (trans) { init (); + set_min_coherence (min_coh); m_is_merged = is_merged; + m_is_merged_min_coherence = min_coh; set_merged_semantics (merged_semantics); } @@ -183,6 +189,7 @@ OriginalLayerRegion::merged_semantics_changed () { m_merged_polygons.clear (); m_merged_polygons_valid = false; + m_merged_polygons_min_coherence = false; } void @@ -190,14 +197,13 @@ OriginalLayerRegion::join_properties_on_merge_changed () { m_merged_polygons.clear (); m_merged_polygons_valid = false; + m_merged_polygons_min_coherence = false; } void OriginalLayerRegion::min_coherence_changed () { - m_is_merged = false; - m_merged_polygons.clear (); - m_merged_polygons_valid = false; + // merged status is tracked in separate variables and is validated on inquiry } size_t @@ -309,7 +315,7 @@ OriginalLayerRegion::begin () const RegionIteratorDelegate * OriginalLayerRegion::begin_merged () const { - if (! merged_semantics () || m_is_merged) { + if (! merged_semantics () || is_merged ()) { return begin (); } else { ensure_merged_polygons_valid (); @@ -332,7 +338,7 @@ OriginalLayerRegion::begin_iter () const std::pair OriginalLayerRegion::begin_merged_iter () const { - if (! merged_semantics () || m_is_merged) { + if (! merged_semantics () || is_merged ()) { return begin_iter (); } else { ensure_merged_polygons_valid (); @@ -346,6 +352,33 @@ OriginalLayerRegion::begin_unmerged_iter () const return std::make_pair (m_iter, m_iter_trans); } +RegionDelegate * +OriginalLayerRegion::merged () const +{ + if (! is_merged ()) { + + if (! merged_polygons_valid ()) { + ensure_merged_polygons_valid (); + } + + std::unique_ptr new_region (new FlatRegion (m_merged_polygons, true, 0, 0, min_coherence ())); + + return new_region.release (); + + } else { + return clone (); + } +} + +RegionDelegate * +OriginalLayerRegion::merged (bool min_coh, unsigned int min_wc, bool jp) const +{ + std::unique_ptr new_region (new FlatRegion (true, 0, 0, min_coh)); + merge_polygons_to (new_region->raw_polygons (), min_coh, min_wc, jp); + + return new_region.release (); +} + bool OriginalLayerRegion::empty () const { @@ -355,7 +388,13 @@ OriginalLayerRegion::empty () const bool OriginalLayerRegion::is_merged () const { - return m_is_merged; + return m_is_merged && m_is_merged_min_coherence == min_coherence (); +} + +bool +OriginalLayerRegion::merged_polygons_valid () const +{ + return m_merged_polygons_valid && m_merged_polygons_min_coherence == min_coherence (); } const db::Polygon * @@ -379,7 +418,7 @@ OriginalLayerRegion::has_valid_polygons () const bool OriginalLayerRegion::has_valid_merged_polygons () const { - return merged_semantics () && ! m_is_merged; + return merged_semantics () && ! is_merged (); } const db::RecursiveShapeIterator * @@ -394,6 +433,7 @@ OriginalLayerRegion::apply_property_translator (const db::PropertiesTranslator & m_iter.apply_property_translator (pt); m_merged_polygons_valid = false; + m_merged_polygons_min_coherence = false; m_merged_polygons.clear (); } @@ -423,7 +463,9 @@ void OriginalLayerRegion::init () { m_is_merged = false; + m_is_merged_min_coherence = false; m_merged_polygons_valid = false; + m_merged_polygons_min_coherence = false; } namespace { @@ -459,15 +501,22 @@ OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell, } } +bool +OriginalLayerRegion::merged_polygons_available () const +{ + return is_merged () || merged_polygons_valid (); +} + void OriginalLayerRegion::ensure_merged_polygons_valid () const { - if (! m_merged_polygons_valid) { + if (! merged_polygons_valid ()) { m_merged_polygons.clear (); merge_polygons_to (m_merged_polygons, min_coherence (), 0, join_properties_on_merge ()); m_merged_polygons_valid = true; + m_merged_polygons_min_coherence = min_coherence (); } } diff --git a/src/db/db/dbOriginalLayerRegion.h b/src/db/db/dbOriginalLayerRegion.h index a72db588b..92d2a90ac 100644 --- a/src/db/db/dbOriginalLayerRegion.h +++ b/src/db/db/dbOriginalLayerRegion.h @@ -43,8 +43,8 @@ class DB_PUBLIC OriginalLayerRegion public: OriginalLayerRegion (); OriginalLayerRegion (const OriginalLayerRegion &other); - OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged = false); - OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false); + OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged = false, bool min_coh = false); + OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false, bool min_coh = false); virtual ~OriginalLayerRegion (); RegionDelegate *clone () const; @@ -57,6 +57,11 @@ public: virtual std::pair begin_merged_iter () const; virtual std::pair begin_unmerged_iter () const; + virtual RegionDelegate *merged () const; + virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const; + + bool merged_polygons_available () const; + virtual bool empty () const; virtual bool is_merged () const; @@ -85,13 +90,16 @@ private: OriginalLayerRegion &operator= (const OriginalLayerRegion &other); bool m_is_merged; + mutable bool m_is_merged_min_coherence; mutable db::Shapes m_merged_polygons; mutable bool m_merged_polygons_valid; + mutable bool m_merged_polygons_min_coherence; mutable db::RecursiveShapeIterator m_iter; db::ICplxTrans m_iter_trans; void init (); void ensure_merged_polygons_valid () const; + bool merged_polygons_valid () const; }; } diff --git a/src/db/unit_tests/dbAsIfFlatRegionTests.cc b/src/db/unit_tests/dbAsIfFlatRegionTests.cc index c23e0c388..1811236ac 100644 --- a/src/db/unit_tests/dbAsIfFlatRegionTests.cc +++ b/src/db/unit_tests/dbAsIfFlatRegionTests.cc @@ -2158,6 +2158,118 @@ TEST(45_min_coherence_and_merge) EXPECT_EQ (r2.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0)"); } +TEST(46_min_coherence_and_merge_from_original) +{ + db::Layout ly; + + auto &top = ly.cell (ly.add_cell ("TOP")); + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + + top.shapes (l1).insert (db::Box (0, 0, 1000, 2000)); + top.shapes (l1).insert (db::Box (1000, 2000, 10000, 3000)); + top.shapes (l1).insert (db::Box (9000, 3000, 10000, 10000)); + + db::Region r1 (db::RecursiveShapeIterator (ly, top, l1)); + + EXPECT_EQ (r1.min_coherence (), false); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), false); + EXPECT_EQ (r1.to_string (), "(0,0;0,2000;1000,2000;1000,0);(1000,2000;1000,3000;10000,3000;10000,2000);(9000,3000;9000,10000;10000,10000;10000,3000)"); + + // forces merged status + r1.sized (1); + + EXPECT_EQ (r1.min_coherence (), false); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + db::Region r2 = r1.merged (); + EXPECT_EQ (r2.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0)"); + + EXPECT_EQ (r2.min_coherence (), false); + + EXPECT_EQ (r1.min_coherence (), false); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + r1.set_min_coherence (true); + + // valid_merged_polygons is invalidated + EXPECT_EQ (r1.min_coherence (), true); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), false); + + r1.set_min_coherence (false); + + // setting min_coherence to false will bring the validation back + EXPECT_EQ (r1.min_coherence (), false); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + r1.set_min_coherence (true); + + // valid_merged_polygons is invalidated again by setting min_coherence to true + EXPECT_EQ (r1.min_coherence (), true); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), false); + + // inserting a box into the region will reset the merged valid flag and not bring it back by resetting min_coherence + db::Region r3 = r1; + r3.insert (db::Box (0, 0, 100, 100)); + EXPECT_EQ (r3.min_coherence (), true); + r3.set_min_coherence (false); + EXPECT_EQ (r3.is_merged (), false); + EXPECT_EQ (dynamic_cast (r3.delegate ())->merged_polygons_available (), false); + + // creates a intrinsically merged copy and tests if the min_coherence + // flag is inherited + r3 = r1.merged (); + EXPECT_EQ (r3.to_string (), "(0,0;0,2000;1000,2000;1000,0);(1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000)"); + EXPECT_EQ (r3.is_merged (), true); + EXPECT_EQ (r3.min_coherence (), true); + + // merged polygons are validated against min_coherence = true during r1.merged() before, so + // resetting min_coherence to false will invalidat them + r1.set_min_coherence (false); + EXPECT_EQ (r1.min_coherence (), false); + EXPECT_EQ (r1.is_merged (), false); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), false); + + // creates a intrinsically merged copy and tests if the min_coherence + // flag is inherited + r3 = r1.merged (); + EXPECT_EQ (r3.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0)"); + EXPECT_EQ (r3.is_merged (), true); + EXPECT_EQ (r3.min_coherence (), false); + + // r2 is an intrinsically merged region (with min coherence false) + EXPECT_EQ (r2.min_coherence (), false); + EXPECT_EQ (r2.is_merged (), true); + EXPECT_EQ (r2.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0)"); + + // after changing min_coherence, the merged status is no longer true + r2.set_min_coherence (true); + EXPECT_EQ (r2.min_coherence (), true); + EXPECT_EQ (r2.is_merged (), false); + EXPECT_EQ (r2.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0)"); + + // read-only experiments with r2 + + // inserting a box into the region will reset the merged state + // and not bring it back by resetting min_coherence + r3 = r2; + r3.insert (db::Box (0, 0, 100, 100)); + r3.set_min_coherence (false); + EXPECT_EQ (r3.is_merged (), false); + EXPECT_EQ (r3.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0);(0,0;0,100;100,100;100,0)"); + + // r2 merged state it can be restored by resetting min_coherence to false + r2.set_min_coherence (false); + EXPECT_EQ (r2.min_coherence (), false); + EXPECT_EQ (r2.is_merged (), true); + EXPECT_EQ (r2.to_string (), "(0,0;0,2000;1000,2000;1000,3000;9000,3000;9000,10000;10000,10000;10000,2000;1000,2000;1000,0)"); +} + TEST(100_Issue1275) { db::Point pts[] = {