diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index f809cdafd..bb739ed54 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -179,8 +179,10 @@ DeepRegion::~DeepRegion () DeepRegion::DeepRegion (const DeepRegion &other) : MutableRegion (other), DeepShapeCollectionDelegateBase (other), m_merged_polygons_valid (other.m_merged_polygons_valid), + m_merged_polygons_min_coherence (other.m_merged_polygons_min_coherence), m_merged_polygons_boc_hash (other.m_merged_polygons_boc_hash), - m_is_merged (other.m_is_merged) + m_is_merged (other.m_is_merged), + m_is_merged_min_coherence (other.m_is_merged_min_coherence) { if (m_merged_polygons_valid) { m_merged_polygons = other.m_merged_polygons.copy (); @@ -196,8 +198,10 @@ DeepRegion::operator= (const DeepRegion &other) DeepShapeCollectionDelegateBase::operator= (other); m_merged_polygons_valid = other.m_merged_polygons_valid; + m_merged_polygons_min_coherence = other.m_merged_polygons_min_coherence; m_merged_polygons_boc_hash = other.m_merged_polygons_boc_hash; m_is_merged = other.m_is_merged; + m_is_merged_min_coherence = other.m_is_merged_min_coherence; if (m_merged_polygons_valid) { m_merged_polygons = other.m_merged_polygons.copy (); } @@ -210,9 +214,11 @@ DeepRegion::operator= (const DeepRegion &other) void DeepRegion::init () { m_merged_polygons_valid = false; + m_merged_polygons_min_coherence = false; m_merged_polygons_boc_hash = 0; m_merged_polygons = db::DeepLayer (); m_is_merged = false; + m_is_merged_min_coherence = false; } RegionDelegate * @@ -228,7 +234,7 @@ void DeepRegion::merged_semantics_changed () void DeepRegion::min_coherence_changed () { - set_is_merged (false); + // merged status is tracked in separate variables and is validated on inquiry } void DeepRegion::join_properties_on_merge_changed () @@ -468,7 +474,7 @@ DeepRegion::empty () const bool DeepRegion::is_merged () const { - return m_is_merged; + return m_is_merged && (m_is_merged_min_coherence == min_coherence ()); } const db::Polygon * @@ -739,18 +745,21 @@ DeepRegion::merged_deep_layer () const bool DeepRegion::merged_polygons_available () const { - return m_is_merged || (m_merged_polygons_valid && m_merged_polygons_boc_hash == deep_layer ().breakout_cells_hash ()); + return (m_is_merged && m_is_merged_min_coherence == min_coherence ()) || + (m_merged_polygons_valid && m_merged_polygons_min_coherence == min_coherence () && m_merged_polygons_boc_hash == deep_layer ().breakout_cells_hash ()); } void DeepRegion::ensure_merged_polygons_valid () const { - if (! m_merged_polygons_valid || (! m_is_merged && m_merged_polygons_boc_hash != deep_layer ().breakout_cells_hash ())) { + if (! m_merged_polygons_valid || m_merged_polygons_min_coherence != min_coherence () || + ((! m_is_merged || m_is_merged_min_coherence != min_coherence ()) && m_merged_polygons_boc_hash != deep_layer ().breakout_cells_hash ())) { - if (m_is_merged) { + if (m_is_merged && m_is_merged_min_coherence == min_coherence ()) { // NOTE: this will reuse the deep layer reference m_merged_polygons = deep_layer (); + m_merged_polygons_min_coherence = min_coherence (); } else { @@ -796,6 +805,7 @@ DeepRegion::ensure_merged_polygons_valid () const } m_merged_polygons_valid = true; + m_merged_polygons_min_coherence = min_coherence (); m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash (); } @@ -813,7 +823,9 @@ DeepRegion::ensure_unmerged_polygons_valid () const db::DeepLayer &polygons = const_cast (deep_layer ()); m_merged_polygons_valid = true; + m_merged_polygons_min_coherence = m_is_merged_min_coherence; m_is_merged = false; + m_is_merged_min_coherence = min_coherence (); m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash (); db::Layout &layout = polygons.layout (); @@ -845,6 +857,7 @@ void DeepRegion::set_is_merged (bool f) { m_is_merged = f; + m_is_merged_min_coherence = min_coherence (); m_merged_polygons_valid = false; m_merged_polygons_boc_hash = 0; m_merged_polygons = db::DeepLayer (); @@ -2026,6 +2039,7 @@ DeepRegion::merged () const res->deep_layer ().layer (); + res->set_min_coherence (min_coherence ()); res->set_is_merged (true); return res.release (); } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 10a9277f1..8a18ef34e 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -179,8 +179,10 @@ private: mutable DeepLayer m_merged_polygons; mutable bool m_merged_polygons_valid; + mutable bool m_merged_polygons_min_coherence; mutable size_t m_merged_polygons_boc_hash; mutable bool m_is_merged; + mutable bool m_is_merged_min_coherence; void init (); void ensure_merged_polygons_valid () const; diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 108b5ed4b..32e831239 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -3341,3 +3341,132 @@ TEST(deep_region_peel) db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_peel_au.gds"); } +TEST(min_coherence_and_merge) +{ + 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::DeepShapeStore dss; + + db::Region r1 (db::RecursiveShapeIterator (ly, top, l1), dss); + + 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)); + 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)"); + + // unmerge after resetting min coherence + r3 = r2; + r3.set_min_coherence (false); + EXPECT_EQ (r3.is_merged (), true); + r3.begin_unmerged (); + EXPECT_EQ (r3.is_merged (), false); + EXPECT_EQ (r3.to_string (), "(1000,2000;1000,3000;10000,3000;10000,2000);(9000,3000;9000,10000;10000,10000;10000,3000);(0,0;0,2000;1000,2000;1000,0)"); + + // r2 still remembers it is merged, even though it does not say so and + // will unmerge + r3 = r2; + EXPECT_EQ (r3.is_merged (), false); + // unmerge + r3.begin_unmerged (); + EXPECT_EQ (r3.is_merged (), false); + EXPECT_EQ (r3.to_string (), "(1000,2000;1000,3000;10000,3000;10000,2000);(9000,3000;9000,10000;10000,10000;10000,3000);(0,0;0,2000;1000,2000;1000,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)"); +}