From 0ba719ad84959e5fd927964754f0096fe03dca5a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 8 Jan 2023 22:44:23 +0100 Subject: [PATCH] WIP: properties for regions, tests for flat and original layer regions --- src/db/db/dbAsIfFlatRegion.cc | 2 +- src/db/db/dbOriginalLayerEdgePairs.cc | 2 +- src/db/db/dbOriginalLayerEdges.cc | 2 +- src/db/db/dbOriginalLayerRegion.cc | 6 +- src/db/db/dbOriginalLayerTexts.cc | 2 +- src/db/db/dbShapes.h | 37 +++--- src/db/db/dbShapes2.cc | 2 +- src/db/db/gsiDeclDbShapes.cc | 5 + src/db/unit_tests/dbRegionTests.cc | 173 ++++++++++++++++++++++++++ 9 files changed, 209 insertions(+), 22 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 1b8deb2ca..cf27c3fee 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -279,7 +279,7 @@ void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, if (need_split_props) { - db::Shapes result; + db::Shapes result (output.is_editable ()); std::vector > polygons_by_prop_id; polygons_by_prop_id.reserve (n); diff --git a/src/db/db/dbOriginalLayerEdgePairs.cc b/src/db/db/dbOriginalLayerEdgePairs.cc index 475e9e9a7..e70da5b9c 100644 --- a/src/db/db/dbOriginalLayerEdgePairs.cc +++ b/src/db/db/dbOriginalLayerEdgePairs.cc @@ -115,7 +115,7 @@ namespace if (! m_rec_iter.at_end ()) { m_rec_iter->edge_pair (m_shape); m_shape.transform (m_iter_trans * m_rec_iter.trans ()); - m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::Properties) != 0 ? m_rec_iter->prop_id () : 0; + m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::RegardProperties) != 0 ? m_rec_iter->prop_id () : 0; } } diff --git a/src/db/db/dbOriginalLayerEdges.cc b/src/db/db/dbOriginalLayerEdges.cc index 41a8ae769..f927cb262 100644 --- a/src/db/db/dbOriginalLayerEdges.cc +++ b/src/db/db/dbOriginalLayerEdges.cc @@ -116,7 +116,7 @@ namespace if (! m_rec_iter.at_end ()) { m_rec_iter->edge (m_shape); m_shape.transform (m_iter_trans * m_rec_iter.trans ()); - m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::Properties) != 0 ? m_rec_iter->prop_id () : 0; + m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::RegardProperties) != 0 ? m_rec_iter->prop_id () : 0; } } diff --git a/src/db/db/dbOriginalLayerRegion.cc b/src/db/db/dbOriginalLayerRegion.cc index 7d30e8079..318e41686 100644 --- a/src/db/db/dbOriginalLayerRegion.cc +++ b/src/db/db/dbOriginalLayerRegion.cc @@ -119,7 +119,7 @@ namespace if (! m_rec_iter.at_end ()) { m_rec_iter->polygon (m_polygon); m_polygon.transform (m_iter_trans * m_rec_iter.trans (), false); - m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::Properties) != 0 ? m_rec_iter->prop_id () : 0; + m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::RegardProperties) != 0 ? m_rec_iter->prop_id () : 0; } } @@ -240,10 +240,10 @@ OriginalLayerRegion::count () const size_t nn = 0; if (iter.multiple_layers ()) { for (std::vector::const_iterator l = iter.layers ().begin (); l != iter.layers ().end (); ++l) { - nn += layout.cell (*c).shapes (*l).size (iter.shape_flags () & db::ShapeIterator::Regions); + nn += layout.cell (*c).shapes (*l).size (iter.shape_flags () & (db::ShapeIterator::Regions | db::ShapeIterator::Properties)); } } else if (iter.layer () < layout.layers ()) { - nn += layout.cell (*c).shapes (iter.layer ()).size (iter.shape_flags () & db::ShapeIterator::Regions); + nn += layout.cell (*c).shapes (iter.layer ()).size (iter.shape_flags () & (db::ShapeIterator::Regions | db::ShapeIterator::Properties)); } n += cc.weight (*c) * nn; } diff --git a/src/db/db/dbOriginalLayerTexts.cc b/src/db/db/dbOriginalLayerTexts.cc index 739635791..2f0099970 100644 --- a/src/db/db/dbOriginalLayerTexts.cc +++ b/src/db/db/dbOriginalLayerTexts.cc @@ -115,7 +115,7 @@ namespace if (! m_rec_iter.at_end ()) { m_rec_iter->text (m_shape); m_shape.transform (m_iter_trans * m_rec_iter.trans ()); - m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::Properties) != 0 ? m_rec_iter->prop_id () : 0; + m_prop_id = (m_rec_iter.shape_flags () & db::ShapeIterator::RegardProperties) != 0 ? m_rec_iter->prop_id () : 0; } } diff --git a/src/db/db/dbShapes.h b/src/db/db/dbShapes.h index 197150b5a..110646b54 100644 --- a/src/db/db/dbShapes.h +++ b/src/db/db/dbShapes.h @@ -171,6 +171,7 @@ public: Properties = (1 << Null), All = (1 << Null) - 1, AllWithProperties = (1 << (Null + 1)) - 1, + RegardProperties = (1 << (Null + 1)), // special flag, not evaluated on query but in receiver (indicates to regard shapes with different properties as different entities) Nothing = 0 }; @@ -1266,7 +1267,8 @@ public: { size_t n = 0; for (tl::vector::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { - if ((flags & (*l)->type_mask ()) != 0) { + unsigned int tm = (*l)->type_mask (); + if (((flags & db::ShapeIterator::Properties) == 0 || (tm & db::ShapeIterator::Properties) != 0) && (flags & tm) != 0) { n += (*l)->size (); } } @@ -1465,6 +1467,25 @@ public: return (db::Cell *) (size_t (mp_cell) & ~3); } + /** + * @brief Gets a flag indicating whether an update is needed + * + * This flag means that the shape collection has been modified and the bounding box + * and the quad trees will be recomputed (internally). + */ + bool is_dirty () const + { + return (size_t (mp_cell) & 1) != 0; + } + + /** + * @brief Gets a value indicating that the shape collection is constructed with editable scope + */ + bool is_editable () const + { + return (size_t (mp_cell) & 2) != 0; + } + /** * @brief Gets the pointer to layout that the shapes container belongs to * @@ -1472,7 +1493,7 @@ public: */ db::Layout *layout () const; - /** + /** * @brief Implementation of the redo method */ void redo (db::Op *op); @@ -1504,18 +1525,6 @@ private: return m_layers; } - // extract dirty flag from mp_cell - bool is_dirty () const - { - return (size_t (mp_cell) & 1) != 0; - } - - // extract editable flag from mp_cell - bool is_editable () const - { - return (size_t (mp_cell) & 2) != 0; - } - // get the shape repository associated with this container db::GenericRepository &shape_repository () const; diff --git a/src/db/db/dbShapes2.cc b/src/db/db/dbShapes2.cc index 59cfe2260..29f2edabd 100644 --- a/src/db/db/dbShapes2.cc +++ b/src/db/db/dbShapes2.cc @@ -755,7 +755,7 @@ inline unsigned int iterator_type_mask (ShapeIterator::user_object_type::tag) template inline unsigned int iterator_type_mask (db::object_tag< db::object_with_properties >) { - return iterator_type_mask (typename Sh::tag ()); + return iterator_type_mask (typename Sh::tag ()) | ShapeIterator::Properties; } template diff --git a/src/db/db/gsiDeclDbShapes.cc b/src/db/db/gsiDeclDbShapes.cc index e711fe0c6..dcc24a0fd 100644 --- a/src/db/db/gsiDeclDbShapes.cc +++ b/src/db/db/gsiDeclDbShapes.cc @@ -448,6 +448,7 @@ static db::Layout *layout (db::Shapes *sh) static unsigned int s_all () { return db::ShapeIterator::All; } static unsigned int s_all_with_properties () { return db::ShapeIterator::AllWithProperties; } +static unsigned int s_regard_properties () { return db::ShapeIterator::RegardProperties; } static unsigned int s_properties () { return db::ShapeIterator::Properties; } static unsigned int s_polygons () { return db::ShapeIterator::Polygons; } static unsigned int s_regions () { return db::ShapeIterator::Regions; } @@ -1335,6 +1336,10 @@ Class decl_Shapes ("db", "Shapes", gsi::method ("SProperties|#s_properties", &s_properties, "@brief Indicates that only shapes with properties shall be retrieved" ) + + gsi::method ("SRegardProperties|#s_regard_properties", &s_regard_properties, + "@brief Special option to regard shapes with different properties as different entities (used by \\Region for example).\n" + "This option has been introduced in version 0.28.4.\n" + ) + gsi::method_ext ("dump_mem_statistics", &dump_mem_statistics, gsi::arg ("detailed", false), "@hide" ), diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 826e8a48b..9ff50a5e1 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -2026,6 +2026,179 @@ TEST(40_with_holes) EXPECT_EQ (r.filtered (db::HoleCountFilter (3, 5, true)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)"); } +TEST(50_PropertiesFlat) +{ + db::Region r; + + // Fill flat region with parts with properties + + r.insert (db::Box (0, 0, 100, 200)); + r.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1)); + r.insert (db::Box (10, 20, 110, 220)); + r.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), 42)); + + EXPECT_EQ (r.count (), size_t (4)); + + db::Region::const_iterator s = r.begin (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (1)); + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (42)); + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + EXPECT_EQ (s.at_end (), true); + + s = r.begin_merged (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + // property #0 elements are merged + EXPECT_EQ (s->to_string (), "(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)"); + ++s; + + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (1)); + // a single property #1 element + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (42)); + // a single property #42 element + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + + EXPECT_EQ (s.at_end (), true); +} + +TEST(51_PropertiesFlatFromLayout) +{ + db::Layout ly; + unsigned int li = ly.insert_layer (); + db::Cell &top = ly.cell (ly.add_cell ("TOP")); + + db::Shapes &si = top.shapes (li); + si.insert (db::Box (0, 0, 100, 200)); + si.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1)); + si.insert (db::Box (10, 20, 110, 220)); + si.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), 42)); + + // NOTE: without specific "property only" selector -> properties are ignored. + + db::Region r (db::RecursiveShapeIterator (ly, top, li)); + + EXPECT_EQ (r.count (), size_t (4)); + + db::Region::const_iterator s = r.begin (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + EXPECT_EQ (s.at_end (), true); + + s = r.begin_merged (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + // property #0 elements are merged + EXPECT_EQ (s->to_string (), "(0,0;0,200;1,200;1,202;10,202;10,220;110,220;110,212;111,212;111,12;101,12;101,2;100,2;100,0)"); + ++s; + + EXPECT_EQ (s.at_end (), true); + + // NOTE: now with explicit propertly-only source + db::RecursiveShapeIterator rsi (ly, top, li); + rsi.shape_flags (db::ShapeIterator::AllWithProperties); + r = db::Region (rsi); + + EXPECT_EQ (r.count (), size_t (2)); + + s = r.begin (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + EXPECT_EQ (s.at_end (), true); + + s = r.begin_merged (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + // property #0 elements are merged + EXPECT_EQ (s->to_string (), "(1,2;1,202;11,202;11,212;111,212;111,12;101,12;101,2)"); + ++s; + + // NOTE: now with regarding properties + rsi = db::RecursiveShapeIterator (ly, top, li); + rsi.shape_flags (db::ShapeIterator::All | db::ShapeIterator::RegardProperties); + r = db::Region (rsi); + + EXPECT_EQ (r.count (), size_t (4)); + + s = r.begin (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (1)); + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (42)); + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + EXPECT_EQ (s.at_end (), true); + + s = r.begin_merged (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + // property #0 elements are merged + EXPECT_EQ (s->to_string (), "(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)"); + ++s; + + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (1)); + // a single property #1 element + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (42)); + // a single property #42 element + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + + EXPECT_EQ (s.at_end (), true); +} + TEST(100_Processors) { db::Region r;