Preparations: recursive shape iterator shortcuts if hierarchy traversal, needs testing.

This commit is contained in:
Matthias Koefferlein 2024-03-24 19:01:36 +01:00
parent 1673c472f2
commit b9bdcf6fac
11 changed files with 307 additions and 62 deletions

View File

@ -219,6 +219,8 @@ AsIfFlatRegion::area (const db::Box &box) const
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (box.empty () || p->box ().inside (box)) { if (box.empty () || p->box ().inside (box)) {
a += p->area (); a += p->area ();
} else if (p->is_box ()) {
a += (p->box () & box).area ();
} else { } else {
std::vector<db::Polygon> clipped; std::vector<db::Polygon> clipped;
clip_poly (*p, box, clipped); clip_poly (*p, box, clipped);

View File

@ -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) : MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons), mp_properties_repository (other.mp_properties_repository)
{ {
init (); init ();
m_is_merged = other.m_is_merged; m_is_merged = other.m_is_merged;
m_merged_polygons_valid = other.m_merged_polygons_valid; 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 ()) : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
{ {
init (); init ();
m_is_merged = is_merged; 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) 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 ()) : MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
{ {
init (); init ();
m_is_merged = is_merged; m_is_merged = is_merged;
} }

View File

@ -52,7 +52,8 @@ public:
typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type; typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type;
FlatRegion (); 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 (bool is_merged);
FlatRegion (const FlatRegion &other); FlatRegion (const FlatRegion &other);

View File

@ -48,6 +48,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
mp_shape_prop_sel = d.mp_shape_prop_sel; mp_shape_prop_sel = d.mp_shape_prop_sel;
m_shape_inv_prop_sel = d.m_shape_inv_prop_sel; m_shape_inv_prop_sel = d.m_shape_inv_prop_sel;
m_overlapping = d.m_overlapping; m_overlapping = d.m_overlapping;
m_for_merged_input = d.m_for_merged_input;
m_start = d.m_start; m_start = d.m_start;
m_stop = d.m_stop; m_stop = d.m_stop;
@ -99,6 +101,7 @@ RecursiveShapeIterator::RecursiveShapeIterator ()
mp_cell = 0; mp_cell = 0;
m_current_layer = 0; m_current_layer = 0;
m_overlapping = false; m_overlapping = false;
m_for_merged_input = false;
m_max_depth = std::numeric_limits<int>::max (); // all m_max_depth = std::numeric_limits<int>::max (); // all
m_min_depth = 0; m_min_depth = 0;
m_shape_flags = shape_iterator::All; m_shape_flags = shape_iterator::All;
@ -116,6 +119,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes)
mp_shapes = &shapes; mp_shapes = &shapes;
mp_top_cell = 0; mp_top_cell = 0;
m_overlapping = false; m_overlapping = false;
m_for_merged_input = false;
init (); init ();
init_region (box_type::world ()); init_region (box_type::world ());
} }
@ -127,6 +131,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
mp_shapes = &shapes; mp_shapes = &shapes;
mp_top_cell = 0; mp_top_cell = 0;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = false;
init (); init ();
init_region (region); init_region (region);
} }
@ -138,11 +143,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
mp_shapes = &shapes; mp_shapes = &shapes;
mp_top_cell = 0; mp_top_cell = 0;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = false;
init (); init ();
init_region (region); init_region (region);
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout, layer) : m_box_convert (layout, layer)
{ {
m_layer = layer; m_layer = layer;
@ -151,11 +157,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (region); init_region (region);
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout, layer) : m_box_convert (layout, layer)
{ {
m_layer = layer; m_layer = layer;
@ -164,11 +171,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (region); 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_box_convert (layout, layer)
{ {
m_layer = layer; m_layer = layer;
@ -177,11 +185,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = false; m_overlapping = false;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (box_type::world ()); init_region (box_type::world ());
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout) : m_box_convert (layout)
{ {
m_layer = 0; m_layer = 0;
@ -191,11 +200,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (region); init_region (region);
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout) : m_box_convert (layout)
{ {
m_layer = 0; m_layer = 0;
@ -205,11 +215,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (region); init_region (region);
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input)
: m_box_convert (layout) : m_box_convert (layout)
{ {
m_layer = 0; m_layer = 0;
@ -219,11 +230,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = false; m_overlapping = false;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (box_type::world ()); init_region (box_type::world ());
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout) : m_box_convert (layout)
{ {
m_layer = 0; m_layer = 0;
@ -233,11 +245,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (region); init_region (region);
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout) : m_box_convert (layout)
{ {
m_layer = 0; m_layer = 0;
@ -247,11 +260,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = overlapping; m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (region); init_region (region);
} }
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers) RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input)
: m_box_convert (layout) : m_box_convert (layout)
{ {
m_layer = 0; m_layer = 0;
@ -261,6 +275,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0; mp_shapes = 0;
mp_top_cell = &cell; mp_top_cell = &cell;
m_overlapping = false; m_overlapping = false;
m_for_merged_input = for_merged_input;
init (); init ();
init_region (box_type::world ()); 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; ++m_inst;
new_inst (receiver); new_inst (receiver);
} else {
down (receiver);
} }
} else { } else {
@ -755,7 +766,7 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
} }
} }
void bool
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
{ {
tl_assert (mp_layout); tl_assert (mp_layout);
@ -783,6 +794,40 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
new_region = m_trans.inverted () * m_region; new_region = m_trans.inverted () * m_region;
new_region &= cell_bbox (cell_index ()); 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); m_local_region_stack.push_back (new_region);
if (! m_local_complex_region_stack.empty ()) { if (! m_local_complex_region_stack.empty ()) {
@ -817,11 +862,25 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
} }
if (receiver) { // do not descend if the box is empty
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); 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 void
@ -831,6 +890,12 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
receiver->leave_cell (this, cell ()); receiver->leave_cell (this, cell ());
} }
pop ();
}
void
RecursiveShapeIterator::pop () const
{
m_shape = shape_iterator (); m_shape = shape_iterator ();
m_shape_quad_id = 0; m_shape_quad_id = 0;

View File

@ -122,12 +122,13 @@ public:
* @param layer The layer from which to deliver the shapes * @param layer The layer from which to deliver the shapes
* @param region The region from which to select the shapes * @param region The region from which to select the shapes
* @param overlapping Specify overlapping mode * @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 * 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 * 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. * 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 &region, bool overlapping = false); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping = false, bool for_merged_input = false);
/** /**
* @brief Standard constructor * @brief Standard constructor
@ -137,13 +138,14 @@ public:
* @param layer The layer from which to deliver the shapes * @param layer The layer from which to deliver the shapes
* @param region The complex region from which to select the shapes * @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode * @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 * 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 * 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 * overlap the given region by at least one database unit. It allows specification of a complex
* search region. * search region.
*/ */
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping = false); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping = false, bool for_merged_input = false);
/** /**
* @brief Standard constructor for "world" iteration * @brief Standard constructor for "world" iteration
@ -153,8 +155,9 @@ public:
* @param layout The layout from which to get the cell hierarchy * @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell * @param cell The starting cell
* @param layer The layer from which to deliver the shapes * @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 * @brief Standard constructor with a layer selection
@ -164,12 +167,13 @@ public:
* @param layers The layers from which to deliver the shapes * @param layers The layers from which to deliver the shapes
* @param region The region from which to select the shapes * @param region The region from which to select the shapes
* @param overlapping Specify overlapping mode * @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 * 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 * 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. * overlap the given region by at least one database unit.
*/ */
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping = false); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping = false, bool for_merged_input = false);
/** /**
* @brief Standard constructor with a layer selection * @brief Standard constructor with a layer selection
@ -179,13 +183,14 @@ public:
* @param layers The layers from which to deliver the shapes * @param layers The layers from which to deliver the shapes
* @param region The complex region from which to select the shapes * @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode * @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 * 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 * 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 * overlap the given region by at least one database unit. It allows specification of a complex
* search region. * search region.
*/ */
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping = false); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping = false, bool for_merged_input = false);
/** /**
* @brief Standard constructor with a layer selection * @brief Standard constructor with a layer selection
@ -195,12 +200,13 @@ public:
* @param layers The layers from which to deliver the shapes * @param layers The layers from which to deliver the shapes
* @param region The region from which to select the shapes * @param region The region from which to select the shapes
* @param overlapping Specify overlapping mode * @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 * 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 * 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. * overlap the given region by at least one database unit.
*/ */
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping = false); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping = false, bool for_merged_input = false);
/** /**
* @brief Standard constructor with a layer selection * @brief Standard constructor with a layer selection
@ -210,13 +216,14 @@ public:
* @param layers The layers from which to deliver the shapes * @param layers The layers from which to deliver the shapes
* @param region The complex region from which to select the shapes * @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode * @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 * 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 * 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 * overlap the given region by at least one database unit. It allows specification of a complex
* search region. * search region.
*/ */
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping = false); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping = false, bool for_merged_input = false);
/** /**
* @brief Standard constructor for "world" iteration with a layer set * @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 layout The layout from which to get the cell hierarchy
* @param cell The starting cell * @param cell The starting cell
* @param layers The layers from which to deliver the shapes * @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<unsigned int> &layers); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input = false);
/** /**
* @brief Standard constructor for "world" iteration with a layer set * @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 layout The layout from which to get the cell hierarchy
* @param cell The starting cell * @param cell The starting cell
* @param layers The layers from which to deliver the shapes * @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<unsigned int> &layers); RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input = false);
/** /**
* @brief Destructor * @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 * @brief Sets a global transformation
* *
@ -812,7 +840,7 @@ private:
unsigned int m_shape_flags; unsigned int m_shape_flags;
const shape_iterator::property_selector *mp_shape_prop_sel; const shape_iterator::property_selector *mp_shape_prop_sel;
bool m_shape_inv_prop_sel; bool m_shape_inv_prop_sel;
bool m_overlapping; bool m_overlapping, m_for_merged_input;
std::set<db::cell_index_type> m_start, m_stop; std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans; cplx_trans_type m_global_trans;
db::PropertiesTranslator m_property_translator; db::PropertiesTranslator m_property_translator;
@ -858,7 +886,8 @@ private:
void new_cell (RecursiveShapeReceiver *receiver) const; void new_cell (RecursiveShapeReceiver *receiver) const;
void new_layer () const; void new_layer () const;
void up (RecursiveShapeReceiver *receiver) 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; bool is_outside_complex_region (const db::Box &box) const;

View File

@ -74,14 +74,42 @@ Region &Region::operator= (const Region &other)
return *this; 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) Region::Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)

View File

@ -199,7 +199,7 @@ public:
* Creates a region from a recursive shape iterator. This allows feeding a region * Creates a region from a recursive shape iterator. This allows feeding a region
* from a hierarchy of cells. * 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 * @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 * from a hierarchy of cells. The transformation is useful to scale to a specific
* DBU for example. * 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 * @brief Constructor from a RecursiveShapeIterator providing a deep representation

View File

@ -476,13 +476,29 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n" "\n"
"This method has been introduced in version 0.23.\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" "@brief Sets a flag indicating whether overlapping shapes are selected when a region is used\n"
"\n" "\n"
"If this flag is false, shapes touching the search region are returned.\n" "If this flag is false, shapes touching the search region are returned.\n"
"\n" "\n"
"This method has been introduced in version 0.23.\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, gsi::method ("unselect_all_cells", &db::RecursiveShapeIterator::unselect_all_cells,
"@brief Unselects all cells.\n" "@brief Unselects all cells.\n"
"\n" "\n"

View File

@ -270,15 +270,6 @@ static db::Region *new_path (const db::Path &o)
return new db::Region (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) 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)); 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); 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) static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
{ {
return new db::Region (si, 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) 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); return new db::Region (si, dss, trans, true, area_ratio, max_vertex_count);
@ -1088,13 +1089,6 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"This constructor creates a region from a path.\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"), constructor ("new", &new_si, gsi::arg ("shape_iterator"),
"@brief Constructor from a hierarchical shape set\n" "@brief Constructor from a hierarchical shape set\n"
"\n" "\n"
@ -1126,6 +1120,24 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n" "r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
"@/code\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)), 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" "@brief Constructor for a deep region from a hierarchical shape set\n"
"\n" "\n"

View File

@ -2537,6 +2537,35 @@ TEST(55_PropertiesFilterFlat)
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); 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) TEST(100_Processors)
{ {
db::Region r; db::Region r;

View File

@ -1066,6 +1066,47 @@ class DBRegion_TestClass < TestBase
end 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 # deep region tests
def test_deep1 def test_deep1