From b9bdcf6facb65c87b76ebf1dd1cc17c4ccfa58e6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Mar 2024 19:01:36 +0100 Subject: [PATCH] Preparations: recursive shape iterator shortcuts if hierarchy traversal, needs testing. --- src/db/db/dbAsIfFlatRegion.cc | 2 + src/db/db/dbFlatRegion.cc | 12 ++- src/db/db/dbFlatRegion.h | 3 +- src/db/db/dbRecursiveShapeIterator.cc | 103 +++++++++++++++---- src/db/db/dbRecursiveShapeIterator.h | 51 +++++++-- src/db/db/dbRegion.cc | 36 ++++++- src/db/db/dbRegion.h | 20 +++- src/db/db/gsiDeclDbRecursiveShapeIterator.cc | 18 +++- src/db/db/gsiDeclDbRegion.cc | 54 ++++++---- src/db/unit_tests/dbRegionTests.cc | 29 ++++++ testdata/ruby/dbRegionTest.rb | 41 ++++++++ 11 files changed, 307 insertions(+), 62 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 9ee803c2a..2171c4f37 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -219,6 +219,8 @@ AsIfFlatRegion::area (const db::Box &box) const for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { if (box.empty () || p->box ().inside (box)) { a += p->area (); + } else if (p->is_box ()) { + a += (p->box () & box).area (); } else { std::vector clipped; clip_poly (*p, box, clipped); diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index d96bb8a22..0d79dbe3e 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -43,7 +43,6 @@ FlatRegion::FlatRegion (const FlatRegion &other) : MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons), mp_properties_repository (other.mp_properties_repository) { init (); - m_is_merged = other.m_is_merged; m_merged_polygons_valid = other.m_merged_polygons_valid; } @@ -52,15 +51,22 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged) : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ()) { init (); - m_is_merged = is_merged; } +FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) + : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ()) +{ + init (); + m_is_merged = is_merged; + transform_generic (trans); + set_merged_semantics (merged_semantics); +} + FlatRegion::FlatRegion (bool is_merged) : MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ()) { init (); - m_is_merged = is_merged; } diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index d89e53173..55805a8a5 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -52,7 +52,8 @@ public: typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type; FlatRegion (); - FlatRegion (const db::Shapes &polygons, bool is_merged); + FlatRegion (const db::Shapes &polygons, bool is_merged = false); + FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false); FlatRegion (bool is_merged); FlatRegion (const FlatRegion &other); diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index 9a8f6052f..0534ebd3f 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -48,6 +48,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI mp_shape_prop_sel = d.mp_shape_prop_sel; m_shape_inv_prop_sel = d.m_shape_inv_prop_sel; m_overlapping = d.m_overlapping; + m_for_merged_input = d.m_for_merged_input; + m_start = d.m_start; m_stop = d.m_stop; @@ -99,6 +101,7 @@ RecursiveShapeIterator::RecursiveShapeIterator () mp_cell = 0; m_current_layer = 0; m_overlapping = false; + m_for_merged_input = false; m_max_depth = std::numeric_limits::max (); // all m_min_depth = 0; m_shape_flags = shape_iterator::All; @@ -116,6 +119,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes) mp_shapes = &shapes; mp_top_cell = 0; m_overlapping = false; + m_for_merged_input = false; init (); init_region (box_type::world ()); } @@ -127,6 +131,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const mp_shapes = &shapes; mp_top_cell = 0; m_overlapping = overlapping; + m_for_merged_input = false; init (); init_region (region); } @@ -138,11 +143,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const mp_shapes = &shapes; mp_top_cell = 0; m_overlapping = overlapping; + m_for_merged_input = false; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping, bool for_merged_input) : m_box_convert (layout, layer) { m_layer = layer; @@ -151,11 +157,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; + m_for_merged_input = for_merged_input; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping, bool for_merged_input) : m_box_convert (layout, layer) { m_layer = layer; @@ -164,11 +171,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; + m_for_merged_input = for_merged_input; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input) : m_box_convert (layout, layer) { m_layer = layer; @@ -177,11 +185,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = false; + m_for_merged_input = for_merged_input; init (); init_region (box_type::world ()); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const box_type ®ion, bool overlapping) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const box_type ®ion, bool overlapping, bool for_merged_input) : m_box_convert (layout) { m_layer = 0; @@ -191,11 +200,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; + m_for_merged_input = for_merged_input; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const region_type ®ion, bool overlapping) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const region_type ®ion, bool overlapping, bool for_merged_input) : m_box_convert (layout) { m_layer = 0; @@ -205,11 +215,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; + m_for_merged_input = for_merged_input; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, bool for_merged_input) : m_box_convert (layout) { m_layer = 0; @@ -219,11 +230,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = false; + m_for_merged_input = for_merged_input; init (); init_region (box_type::world ()); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const box_type ®ion, bool overlapping) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const box_type ®ion, bool overlapping, bool for_merged_input) : m_box_convert (layout) { m_layer = 0; @@ -233,11 +245,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; + m_for_merged_input = for_merged_input; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const region_type ®ion, bool overlapping) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const region_type ®ion, bool overlapping, bool for_merged_input) : m_box_convert (layout) { m_layer = 0; @@ -247,11 +260,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; + m_for_merged_input = for_merged_input; init (); init_region (region); } -RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers) +RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, bool for_merged_input) : m_box_convert (layout) { m_layer = 0; @@ -261,6 +275,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const mp_shapes = 0; mp_top_cell = &cell; m_overlapping = false; + m_for_merged_input = for_merged_input; init (); init_region (box_type::world ()); } @@ -721,13 +736,9 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const } - if (is_empty) { - + if (is_empty || !down (receiver)) { ++m_inst; new_inst (receiver); - - } else { - down (receiver); } } else { @@ -755,7 +766,7 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const } } -void +bool RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const { tl_assert (mp_layout); @@ -783,6 +794,40 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const new_region = m_trans.inverted () * m_region; new_region &= cell_bbox (cell_index ()); } + + // try some optimization - only consider optimizing by dropping the shape-covered area under certain circumstances: + // - single layer + // - less than 32 shapes to consider + // - total shape bbox in current region covers at least a third of it + // - total area of shapes in current region is at least a third of it + // TODO: the current implementation does not touch the complex search region + + if (m_for_merged_input && (! m_has_layers || m_layers.size () == 1) && ! new_region.empty ()) { + + unsigned int l = m_has_layers ? m_layers.front () : m_layer; + const shapes_type &shapes = m_cells.back ()->shapes (l); + box_type region_in_parent = m_inst->complex_trans (*m_inst_array) * new_region; + + // NOTE: new_region is already in the coordinate system of the child cell + + if (shapes.size () < 32 && + 3 * (shapes.bbox () & region_in_parent).area () > region_in_parent.area ()) { + + region_type shapes_region (shapes); + if (3 * shapes_region.area (region_in_parent) > region_in_parent.area ()) { + + shapes_region.transform (m_inst->complex_trans (*m_inst_array).inverted ()); + + // reduce the search region for less instances to look up + region_type new_complex_region = region_type (new_region) - shapes_region; + new_region = new_complex_region.bbox (); + + } + + } + + } + m_local_region_stack.push_back (new_region); if (! m_local_complex_region_stack.empty ()) { @@ -817,11 +862,25 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const } - if (receiver) { - receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ()); - } + // do not descend if the box is empty - new_cell (receiver); + if (m_local_region_stack.back ().empty ()) { + + pop (); + + return false; + + } else { + + if (receiver) { + receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ()); + } + + new_cell (receiver); + + return true; + + } } void @@ -831,6 +890,12 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const receiver->leave_cell (this, cell ()); } + pop (); +} + +void +RecursiveShapeIterator::pop () const +{ m_shape = shape_iterator (); m_shape_quad_id = 0; diff --git a/src/db/db/dbRecursiveShapeIterator.h b/src/db/db/dbRecursiveShapeIterator.h index 43f913b1a..b8e6a640a 100644 --- a/src/db/db/dbRecursiveShapeIterator.h +++ b/src/db/db/dbRecursiveShapeIterator.h @@ -122,12 +122,13 @@ public: * @param layer The layer from which to deliver the shapes * @param region The region from which to select the shapes * @param overlapping Specify overlapping mode + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others * * By default the iterator operates in touching mode - i.e. shapes that touch the given region * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that * overlap the given region by at least one database unit. */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping = false); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping = false, bool for_merged_input = false); /** * @brief Standard constructor @@ -137,13 +138,14 @@ public: * @param layer The layer from which to deliver the shapes * @param region The complex region from which to select the shapes * @param overlapping Specify overlapping mode + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others * * By default the iterator operates in touching mode - i.e. shapes that touch the given region * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that * overlap the given region by at least one database unit. It allows specification of a complex * search region. */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping = false); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping = false, bool for_merged_input = false); /** * @brief Standard constructor for "world" iteration @@ -153,8 +155,9 @@ public: * @param layout The layout from which to get the cell hierarchy * @param cell The starting cell * @param layer The layer from which to deliver the shapes + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input = false); /** * @brief Standard constructor with a layer selection @@ -164,12 +167,13 @@ public: * @param layers The layers from which to deliver the shapes * @param region The region from which to select the shapes * @param overlapping Specify overlapping mode + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others * * By default the iterator operates in touching mode - i.e. shapes that touch the given region * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that * overlap the given region by at least one database unit. */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const box_type ®ion, bool overlapping = false); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const box_type ®ion, bool overlapping = false, bool for_merged_input = false); /** * @brief Standard constructor with a layer selection @@ -179,13 +183,14 @@ public: * @param layers The layers from which to deliver the shapes * @param region The complex region from which to select the shapes * @param overlapping Specify overlapping mode + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others * * By default the iterator operates in touching mode - i.e. shapes that touch the given region * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that * overlap the given region by at least one database unit. It allows specification of a complex * search region. */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const region_type ®ion, bool overlapping = false); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, const region_type ®ion, bool overlapping = false, bool for_merged_input = false); /** * @brief Standard constructor with a layer selection @@ -195,12 +200,13 @@ public: * @param layers The layers from which to deliver the shapes * @param region The region from which to select the shapes * @param overlapping Specify overlapping mode + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others * * By default the iterator operates in touching mode - i.e. shapes that touch the given region * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that * overlap the given region by at least one database unit. */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const box_type ®ion, bool overlapping = false); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const box_type ®ion, bool overlapping = false, bool for_merged_input = false); /** * @brief Standard constructor with a layer selection @@ -210,13 +216,14 @@ public: * @param layers The layers from which to deliver the shapes * @param region The complex region from which to select the shapes * @param overlapping Specify overlapping mode + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others * * By default the iterator operates in touching mode - i.e. shapes that touch the given region * are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that * overlap the given region by at least one database unit. It allows specification of a complex * search region. */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const region_type ®ion, bool overlapping = false); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, const region_type ®ion, bool overlapping = false, bool for_merged_input = false); /** * @brief Standard constructor for "world" iteration with a layer set @@ -226,8 +233,9 @@ public: * @param layout The layout from which to get the cell hierarchy * @param cell The starting cell * @param layers The layers from which to deliver the shapes + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector &layers, bool for_merged_input = false); /** * @brief Standard constructor for "world" iteration with a layer set @@ -237,8 +245,9 @@ public: * @param layout The layout from which to get the cell hierarchy * @param cell The starting cell * @param layers The layers from which to deliver the shapes + * @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others */ - RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers); + RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set &layers, bool for_merged_input = false); /** * @brief Destructor @@ -427,6 +436,25 @@ public: } } + /** + * @brief Gets a flag indicating whether optimizing for merged input + */ + bool for_merged_input () const + { + return m_for_merged_input; + } + + /** + * @brief Sets a flag indicating whether optimizing for merged input + */ + void set_for_merged_input (bool f) + { + if (m_for_merged_input != f) { + m_for_merged_input = f; + m_needs_reinit = true; + } + } + /** * @brief Sets a global transformation * @@ -812,7 +840,7 @@ private: unsigned int m_shape_flags; const shape_iterator::property_selector *mp_shape_prop_sel; bool m_shape_inv_prop_sel; - bool m_overlapping; + bool m_overlapping, m_for_merged_input; std::set m_start, m_stop; cplx_trans_type m_global_trans; db::PropertiesTranslator m_property_translator; @@ -858,7 +886,8 @@ private: void new_cell (RecursiveShapeReceiver *receiver) const; void new_layer () const; void up (RecursiveShapeReceiver *receiver) const; - void down (RecursiveShapeReceiver *receiver) const; + bool down (RecursiveShapeReceiver *receiver) const; + void pop () const; bool is_outside_complex_region (const db::Box &box) const; diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index 488fbc460..c05f9d338 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -74,14 +74,42 @@ Region &Region::operator= (const Region &other) return *this; } -Region::Region (const RecursiveShapeIterator &si) +Region::Region (const RecursiveShapeIterator &si, bool merged_semantics, bool is_merged) { - mp_delegate = new OriginalLayerRegion (si); + mp_delegate = new OriginalLayerRegion (si, db::ICplxTrans (), merged_semantics, is_merged); } -Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics) +Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) { - mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics); + mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics, is_merged); +} + +Region::Region (const Shapes &shapes, bool merged_semantics, bool is_merged) +{ + db::FlatRegion *flat_region = new FlatRegion (is_merged); + flat_region->reserve (shapes.size (db::ShapeIterator::Regions)); + + // NOTE: we need to normalize the shapes to polygons because this is what the flat region expects + for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) { + flat_region->insert (*s); + } + + mp_delegate = flat_region; + mp_delegate->set_merged_semantics (merged_semantics); +} + +Region::Region (const Shapes &shapes, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) +{ + db::FlatRegion *flat_region = new FlatRegion (is_merged); + flat_region->reserve (shapes.size (db::ShapeIterator::Regions)); + + // NOTE: we need to normalize the shapes to polygons because this is what the flat region expects + for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) { + flat_region->insert (*s, trans); + } + + mp_delegate = flat_region; + mp_delegate->set_merged_semantics (merged_semantics); } Region::Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 39880b2ca..1329adcc8 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -199,7 +199,7 @@ public: * Creates a region from a recursive shape iterator. This allows feeding a region * from a hierarchy of cells. */ - explicit Region (const RecursiveShapeIterator &si); + explicit Region (const RecursiveShapeIterator &si, bool merged_semantics = true, bool is_merged = false); /** * @brief Constructor from a RecursiveShapeIterator with a transformation @@ -208,7 +208,23 @@ public: * from a hierarchy of cells. The transformation is useful to scale to a specific * DBU for example. */ - explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true); + explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false); + + /** + * @brief Constructor from a Shapes container + * + * Creates a region from a shapes container. + */ + explicit Region (const Shapes &si, bool merged_semantics = true, bool is_merged = false); + + /** + * @brief Constructor from a Shapes container with a transformation + * + * Creates a region from a recursive shape iterator. This allows feeding a region + * from a hierarchy of cells. The transformation is useful to scale to a specific + * DBU for example. + */ + explicit Region (const Shapes &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false); /** * @brief Constructor from a RecursiveShapeIterator providing a deep representation diff --git a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc index bc702af0f..50f840eee 100644 --- a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc @@ -476,13 +476,29 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "\n" "This method has been introduced in version 0.23.\n" ) + - gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("region"), + gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("flag"), "@brief Sets a flag indicating whether overlapping shapes are selected when a region is used\n" "\n" "If this flag is false, shapes touching the search region are returned.\n" "\n" "This method has been introduced in version 0.23.\n" ) + + gsi::method ("for_merged_input?", &db::RecursiveShapeIterator::for_merged_input, + "@brief Gets a flag indicating whether iterator optimizes for merged input\n" + "\n" + "see \\for_merged_input= for details of this attribute.\n" + "\n" + "This method has been introduced in version 0.29.\n" + ) + + gsi::method ("for_merged_input=", &db::RecursiveShapeIterator::set_for_merged_input, gsi::arg ("flag"), + "@brief Sets a flag indicating whether iterator optimizes for merged input\n" + "\n" + "If this flag is set to true, the iterator is allowed to skip shapes it deems irrelevant " + "because they are covered entirely by other shapes. This allows shortcutting hierarchy traversal in " + "some cases.\n" + "\n" + "This method has been introduced in version 0.29.\n" + ) + gsi::method ("unselect_all_cells", &db::RecursiveShapeIterator::unselect_all_cells, "@brief Unselects all cells.\n" "\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index f978a7c4f..ad941cc27 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -270,15 +270,6 @@ static db::Region *new_path (const db::Path &o) return new db::Region (o); } -static db::Region *new_shapes (const db::Shapes &s) -{ - db::Region *r = new db::Region (); - for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::All); !i.at_end (); ++i) { - r->insert (*i); - } - return r; -} - static db::Region *new_texts_as_boxes1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern, db::Coord enl) { return new db::Region (db::Region (si).texts_as_boxes (pat, pattern, enl)); @@ -329,16 +320,26 @@ static db::Region *new_si (const db::RecursiveShapeIterator &si) return new db::Region (si); } -static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) -{ - return new db::Region (si, dss, area_ratio, max_vertex_count); -} - static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) { return new db::Region (si, trans); } +static db::Region *new_sis (const db::Shapes &si) +{ + return new db::Region (si); +} + +static db::Region *new_sis2 (const db::Shapes &si, const db::ICplxTrans &trans) +{ + return new db::Region (si, trans); +} + +static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) +{ + return new db::Region (si, dss, area_ratio, max_vertex_count); +} + static db::Region *new_sid2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans, double area_ratio, size_t max_vertex_count) { return new db::Region (si, dss, trans, true, area_ratio, max_vertex_count); @@ -1088,13 +1089,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This constructor creates a region from a path.\n" ) + - constructor ("new", &new_shapes, gsi::arg ("shapes"), - "@brief Shapes constructor\n" - "\n" - "This constructor creates a region from a \\Shapes collection.\n" - "\n" - "This constructor has been introduced in version 0.25." - ) + constructor ("new", &new_si, gsi::arg ("shape_iterator"), "@brief Constructor from a hierarchical shape set\n" "\n" @@ -1126,6 +1120,24 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n" "@/code\n" ) + + constructor ("new", &new_sis, gsi::arg ("shapes"), + "@brief Constructor from a shapes container\n" + "\n" + "This constructor creates a region from the shapes container.\n" + "Text objects and edges are not inserted, because they cannot be converted to polygons.\n" + "This method allows feeding the shapes from a hierarchy of cells into the region.\n" + "\n" + "This constructor has been introduced in version 0.25 and extended in version 0.29." + ) + + constructor ("new", &new_sis2, gsi::arg ("shapes"), gsi::arg ("trans"), + "@brief Constructor from a shapes container with a transformation\n" + "\n" + "This constructor creates a region from the shapes container after applying the transformation.\n" + "Text objects and edges are not inserted, because they cannot be converted to polygons.\n" + "This method allows feeding the shapes from a hierarchy of cells into the region.\n" + "\n" + "This constructor variant has been introduced in version 0.29." + ) + constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("area_ratio", 0.0), gsi::arg ("max_vertex_count", size_t (0)), "@brief Constructor for a deep region from a hierarchical shape set\n" "\n" diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 554f25956..70ac453b2 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -2537,6 +2537,35 @@ TEST(55_PropertiesFilterFlat) EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); } +TEST(56_RegionsFromShapes) +{ + db::Shapes shapes; + + shapes.insert (db::Box (0, 0, 100, 200)); + shapes.insert (db::Box (50, 50, 150, 250)); + + EXPECT_EQ (db::Region (shapes).area (), 32500); + EXPECT_EQ (db::Region (shapes, false).area (), 40000); + EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5)).area (), 8125); + EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5), false).area (), 10000); + + // for cross-checking: same for RecursiveShapeIterator + + db::Layout layout; + unsigned int l1 = layout.insert_layer (); + db::Cell &top = layout.cell (layout.add_cell ("TOP")); + + top.shapes (l1).insert (db::Box (0, 0, 100, 200)); + top.shapes (l1).insert (db::Box (50, 50, 150, 250)); + + db::RecursiveShapeIterator si (layout, top, l1); + + EXPECT_EQ (db::Region (si).area (), 32500); + EXPECT_EQ (db::Region (si, false).area (), 40000); + EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5)).area (), 8125); + EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5), false).area (), 10000); +} + TEST(100_Processors) { db::Region r; diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 0d81b5efd..8c59d587c 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -1066,6 +1066,47 @@ class DBRegion_TestClass < TestBase end + # regions from Shapes + def test_regions_from_shapes + + shapes = RBA::Shapes::new; + + shapes.insert(RBA::Box::new(0, 0, 100, 200)) + shapes.insert(RBA::Box::new(50, 50, 150, 250)) + + assert_equal(RBA::Region::new(shapes).area, 32500) + region = RBA::Region::new(shapes) + region.merged_semantics = false + assert_equal(region.area, 40000) + + assert_equal(RBA::Region::new(shapes, RBA::ICplxTrans::new(0.5)).area, 8125) + region = RBA::Region::new(shapes, RBA::ICplxTrans::new(0.5)) + region.merged_semantics = false + assert_equal(region.area, 10000) + + # for cross-checking: same for RecursiveShapeIterator + + layout = RBA::Layout::new + l1 = layout.insert_layer(RBA::LayerInfo::new(1, 0)) + top = layout.create_cell("TOP") + + top.shapes(l1).insert (RBA::Box::new(0, 0, 100, 200)) + top.shapes(l1).insert (RBA::Box::new(50, 50, 150, 250)) + + si = RBA::RecursiveShapeIterator::new(layout, top, l1) + + assert_equal(RBA::Region::new(si).area, 32500) + region = RBA::Region::new(si) + region.merged_semantics = false + assert_equal(region.area, 40000) + + assert_equal(RBA::Region::new(si, RBA::ICplxTrans::new(0.5)).area, 8125) + region = RBA::Region::new(si, RBA::ICplxTrans::new(0.5)) + region.merged_semantics = false + assert_equal(region.area, 10000) + + end + # deep region tests def test_deep1