Recursive instance iterator, first draft.

This commit is contained in:
Matthias Koefferlein 2021-02-20 00:40:05 +01:00
parent 9d349239b5
commit 412056afed
6 changed files with 2644 additions and 0 deletions

View File

@ -61,6 +61,7 @@ SOURCES = \
dbPolygonGenerators.cc \
dbPropertiesRepository.cc \
dbReader.cc \
dbRecursiveInstanceIterator.cc \
dbRecursiveShapeIterator.cc \
dbRegion.cc \
dbRegionLocalOperations.cc \
@ -269,6 +270,7 @@ HEADERS = \
dbPolygonGenerators.h \
dbPropertiesRepository.h \
dbReader.h \
dbRecursiveInstanceIterator.h \
dbRecursiveShapeIterator.h \
dbRegion.h \
dbRegionLocalOperations.h \

View File

@ -0,0 +1,714 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbRecursiveInstanceIterator.h"
#include "dbRegion.h"
#include "dbEdgeProcessor.h"
#include "tlProgress.h"
namespace db
{
// ------------------------------------------------------------------------------------
// Recursive shape iterator implementation
RecursiveInstanceIterator::RecursiveInstanceIterator (const RecursiveInstanceIterator &d)
{
operator= (d);
}
RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const RecursiveInstanceIterator &d)
{
if (&d != this) {
m_max_depth = d.m_max_depth;
m_min_depth = d.m_min_depth;
m_shape_flags = d.m_shape_flags;
m_shape_inv_prop_sel = d.m_shape_inv_prop_sel;
m_overlapping = d.m_overlapping;
m_start = d.m_start;
m_stop = d.m_stop;
mp_layout = d.mp_layout;
mp_top_cell = d.mp_top_cell;
m_region = d.m_region;
if (d.mp_complex_region.get () != 0) {
mp_complex_region.reset (new region_type (*d.mp_complex_region.get ()));
} else {
mp_complex_region.reset (0);
}
m_box_convert = d.m_box_convert;
m_inst = d.m_inst;
m_inst_array = d.m_inst_array;
m_empty_cells_cache = d.m_empty_cells_cache;
mp_cell = d.mp_cell;
m_trans = d.m_trans;
m_trans_stack = d.m_trans_stack;
m_inst_iterators = d.m_inst_iterators;
m_inst_array_iterators = d.m_inst_array_iterators;
m_cells = d.m_cells;
m_local_complex_region_stack = d.m_local_complex_region_stack;
m_local_region_stack = d.m_local_region_stack;
m_needs_reinit = d.m_needs_reinit;
m_inst_quad_id = d.m_inst_quad_id;
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
}
return *this;
}
RecursiveInstanceIterator::RecursiveInstanceIterator ()
{
// anything. Not necessary reasonable.
mp_layout = 0;
mp_top_cell = 0;
mp_cell = 0;
m_overlapping = false;
m_max_depth = std::numeric_limits<int>::max (); // all
m_min_depth = 0;
m_shape_inv_prop_sel = false;
m_needs_reinit = false;
m_inst_quad_id = 0;
}
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type &region, bool overlapping)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_top_cell = &cell;
m_overlapping = overlapping;
init ();
init_region (region);
}
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type &region, bool overlapping)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_top_cell = &cell;
m_overlapping = overlapping;
init ();
init_region (region);
}
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_top_cell = &cell;
m_overlapping = false;
init ();
init_region (box_type::world ());
}
RecursiveInstanceIterator::~RecursiveInstanceIterator ()
{
// .. nothing yet ..
}
void
RecursiveInstanceIterator::init ()
{
m_needs_reinit = true;
m_max_depth = std::numeric_limits<int>::max (); // all
m_min_depth = 0; // from the beginning
m_shape_inv_prop_sel = false;
m_inst_quad_id = 0;
mp_cell = 0;
}
void
RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::box_type &region)
{
m_region = region;
mp_complex_region.reset (0);
}
void
RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::region_type &region)
{
if (region.empty ()) {
m_region = box_type ();
mp_complex_region.reset (0);
} else if (region.is_box ()) {
m_region = region.bbox ();
mp_complex_region.reset (0);
} else {
mp_complex_region.reset (new region_type (region));
m_region = region.bbox ();
// A small optimization. We can do this since we merge and translate to trapezoids anyway.
mp_complex_region->set_strict_handling (false);
}
}
void
RecursiveInstanceIterator::set_region (const box_type &region)
{
if (m_region != region || mp_complex_region.get () != 0) {
init_region (region);
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::set_region (const region_type &region)
{
init_region (region);
m_needs_reinit = true;
}
void
RecursiveInstanceIterator::confine_region (const box_type &region)
{
if (m_region.empty ()) {
// no more confinement
} else if (mp_complex_region.get ()) {
init_region (*mp_complex_region & region_type (region));
} else {
init_region (m_region & region);
}
m_needs_reinit = true;
}
void
RecursiveInstanceIterator::confine_region (const region_type &region)
{
if (m_region.empty ()) {
// no more confinement
} else if (mp_complex_region.get ()) {
init_region (*mp_complex_region & region);
} else {
init_region (region & region_type (m_region));
}
m_needs_reinit = true;
}
namespace {
struct BoxTreePusher
: public db::SimplePolygonSink
{
BoxTreePusher (RecursiveInstanceIterator::box_tree_type *bt)
: mp_bt (bt)
{
// .. nothing yet ..
}
void put (const db::SimplePolygon &sp)
{
mp_bt->insert (sp.box ());
}
private:
RecursiveInstanceIterator::box_tree_type *mp_bt;
};
}
void
RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const
{
if (! m_needs_reinit) {
return;
}
m_needs_reinit = false;
// re-initialize
mp_cell = mp_top_cell;
m_trans_stack.clear ();
m_inst_iterators.clear ();
m_inst_quad_id_stack.clear ();
m_inst_array_iterators.clear ();
m_cells.clear ();
m_trans = cplx_trans_type ();
m_local_region_stack.clear ();
m_local_region_stack.push_back (m_region);
m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) {
// prepare a local complex region
m_local_complex_region_stack.push_back (box_tree_type ());
// Use a merge and the trapezoid generator to produce a decomposition that goes into the complex region
db::EdgeProcessor ep;
size_t n = 0;
for (region_type::const_iterator p = mp_complex_region->begin (); !p.at_end (); ++p, ++n) {
ep.insert (*p, n);
}
BoxTreePusher btp (&m_local_complex_region_stack.back ());
db::TrapezoidGenerator tg (btp);
db::MergeOp op (0);
ep.process (tg, op);
m_local_complex_region_stack.back ().sort (db::box_convert <db::Box> ());
}
if (mp_top_cell) {
new_cell (receiver);
next_instance (receiver);
}
}
void
RecursiveInstanceIterator::reset_selection ()
{
if (mp_layout) {
m_start.clear ();
m_stop.clear ();
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::unselect_cells (const std::set<db::cell_index_type> &cells)
{
if (mp_layout) {
for (std::set<db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
m_stop.insert (*c);
m_start.erase (*c);
}
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::unselect_all_cells ()
{
if (mp_layout) {
m_start.clear ();
for (db::Layout::const_iterator c = mp_layout->begin (); c != mp_layout->end (); ++c) {
m_stop.insert (c->cell_index ());
}
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::select_cells (const std::set<db::cell_index_type> &cells)
{
if (mp_layout) {
for (std::set<db::cell_index_type>::const_iterator c = cells.begin (); c != cells.end (); ++c) {
m_start.insert (*c);
m_stop.erase (*c);
}
m_needs_reinit = true;
}
}
void
RecursiveInstanceIterator::select_all_cells ()
{
if (mp_layout) {
m_stop.clear ();
for (db::Layout::const_iterator c = mp_layout->begin (); c != mp_layout->end (); ++c) {
m_start.insert (c->cell_index ());
}
m_needs_reinit = true;
}
}
bool
RecursiveInstanceIterator::at_end () const
{
validate (0);
return m_inst.at_end ();
}
std::vector<db::InstElement>
RecursiveInstanceIterator::path () const
{
std::vector<db::InstElement> elements;
for (size_t i = 0; i < m_inst_array_iterators.size () && i < m_inst_iterators.size (); ++i) {
elements.push_back (db::InstElement (*m_inst_iterators [i], m_inst_array_iterators [i]));
}
return elements;
}
void
RecursiveInstanceIterator::skip_inst_iter_for_complex_region () const
{
while (! m_inst.at_end ()) {
// skip inst quad if possible
while (! m_inst.at_end ()) {
if (is_outside_complex_region (m_inst.quad_box ())) {
m_inst.skip_quad ();
} else {
m_inst_quad_id = m_inst.quad_id ();
break;
}
}
// skip insts outside the complex region
if (! m_inst.at_end ()) {
if (! is_outside_complex_region (m_inst->bbox ())) {
break;
} else {
++m_inst;
}
}
}
}
void
RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver)
{
if (! at_end ()) {
++m_inst;
new_inst (receiver);
next_instance (receiver);
}
}
void
RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) const
{
while (true) {
if (! m_inst.at_end ()) {
if (int (m_inst_iterators.size ()) < m_max_depth) {
down (receiver);
}
} else {
if (! m_inst_iterators.empty ()) {
// no more instances: up and next instance
up (receiver);
} else {
break;
}
if (! m_inst.at_end () && int (m_inst_iterators.size () + 1) >= m_min_depth && ! is_inactive ()) {
break;
}
}
if (! m_inst.at_end ()) {
if (int (m_inst_iterators.size () + 1) < m_min_depth || is_inactive ()) {
++m_inst;
new_inst (receiver);
} else {
break;
}
}
}
}
void
RecursiveInstanceIterator::down (RecursiveInstanceReceiver *receiver) const
{
m_trans_stack.push_back (m_trans);
m_cells.push_back (mp_cell);
m_inst_iterators.push_back (m_inst);
m_inst_array_iterators.push_back (m_inst_array);
m_inst_quad_id_stack.push_back (m_inst_quad_id);
bool ia = is_inactive ();
bool aoi = is_all_of_instance ();
mp_cell = &mp_layout->cell (m_inst->cell_index ());
set_inactive (ia);
set_all_of_instance (aoi);
m_trans = m_trans * m_inst->complex_trans (*m_inst_array);
// don't transform the world region, since transformation of that region might not work properly
box_type new_region = box_type::world ();
// compute the region inside the new cell
if (new_region != m_local_region_stack.front ()) {
new_region = m_trans.inverted () * m_local_region_stack.front ();
new_region &= cell ()->bbox ();
}
m_local_region_stack.push_back (new_region);
if (! m_local_complex_region_stack.empty ()) {
m_local_complex_region_stack.push_back (box_tree_type ());
const box_tree_type &pcl = m_local_complex_region_stack.end ()[-2];
if (! new_region.empty ()) {
// compute a new, reduced complex region for use inside the new cell
db::CellInstArray::complex_trans_type tinst = m_inst->complex_trans (*m_inst_array);
db::CellInstArray::complex_trans_type tinst_inv = tinst.inverted ();
db::Box bb;
for (box_tree_type::touching_iterator b = pcl.begin_touching (correct_box_overlapping (new_region.transformed (tinst)), db::box_convert<db::Box> ()); ! b.at_end (); ++b) {
db::Box lb = (b->transformed (tinst_inv) & new_region);
if (! lb.empty ()) {
m_local_complex_region_stack.back ().insert (lb);
bb += lb;
}
}
m_local_complex_region_stack.back ().sort (db::box_convert<db::Box> ());
// re-adjust the new local region, so we take into account additional clipping by the complex region.
// in the extreme case, this box is empty:
m_local_region_stack.back () = bb;
}
}
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);
}
void
RecursiveInstanceIterator::up (RecursiveInstanceReceiver *receiver) const
{
if (receiver) {
receiver->leave_cell (this, cell ());
}
m_inst = m_inst_iterators.back ();
m_inst_array = m_inst_array_iterators.back ();
m_inst_quad_id = m_inst_quad_id_stack.back ();
m_inst_iterators.pop_back ();
m_inst_array_iterators.pop_back ();
m_inst_quad_id_stack.pop_back ();
m_trans = m_trans_stack.back ();
m_trans_stack.pop_back ();
mp_cell = m_cells.back ();
m_cells.pop_back ();
m_local_region_stack.pop_back ();
if (! m_local_complex_region_stack.empty ()) {
m_local_complex_region_stack.pop_back ();
}
}
void
RecursiveInstanceIterator::new_cell (RecursiveInstanceReceiver *receiver) const
{
bool new_cell_inactive = is_child_inactive (cell_index ());
if (is_inactive () != new_cell_inactive) {
set_inactive (new_cell_inactive);
}
// @@@ drop?
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
skip_inst_iter_for_complex_region ();
}
// @@@
m_inst = cell ()->begin_touching (correct_box_overlapping (m_local_region_stack.back ()));
m_inst_quad_id = 0;
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
skip_inst_iter_for_complex_region ();
}
new_inst (receiver);
}
void
RecursiveInstanceIterator::new_inst (RecursiveInstanceReceiver *receiver) const
{
// look for the next instance with a non-empty array iterator. The array iterator can be empty because we
// use a lookup region.
while (! m_inst.at_end ()) {
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
skip_inst_iter_for_complex_region ();
if (m_inst.at_end ()) {
break;
}
}
bool all_of_instance = false;
bool with_region = false;
if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) {
with_region = true;
} else {
// TODO: optimization potential: only report all_of_instance == false, if not entirely within the complex region
all_of_instance = m_local_complex_region_stack.empty ();
}
RecursiveInstanceReceiver::new_inst_mode ni = RecursiveInstanceReceiver::NI_all;
if (receiver) {
ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
}
if (ni == RecursiveInstanceReceiver::NI_skip) {
m_inst_array = inst_array_iterator ();
} else if (ni == RecursiveInstanceReceiver::NI_single) {
// a singular iterator
m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false);
} else if (with_region) {
m_inst_array = m_inst->cell_inst ().begin_touching (correct_box_overlapping (m_local_region_stack.back ()), m_box_convert);
} else {
m_inst_array = m_inst->cell_inst ().begin ();
}
set_all_of_instance (all_of_instance);
new_inst_member (receiver);
if (! m_inst_array.at_end ()) {
break;
} else {
++m_inst;
}
}
}
void
RecursiveInstanceIterator::new_inst_member (RecursiveInstanceReceiver *receiver) const
{
if (! m_local_complex_region_stack.empty ()) {
// skip instance array members not part of the complex region
while (! m_inst_array.at_end ()) {
db::Box ia_box = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
if (! is_outside_complex_region (ia_box)) {
break;
} else {
++m_inst_array;
}
}
}
while (! m_inst_array.at_end () && receiver) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
break;
} else {
++m_inst_array;
}
}
}
RecursiveInstanceIterator::box_type
RecursiveInstanceIterator::correct_box_overlapping (const box_type &box) const
{
if (! m_overlapping) {
return box;
} else if (box.empty () || box == box_type::world ()) {
return box;
} else if (box.width () < 2 || box.height () < 2) {
return box;
} else {
return box.enlarged (box_type::vector_type (-1, -1));
}
}
bool
RecursiveInstanceIterator::is_outside_complex_region (const box_type &box) const
{
if (m_overlapping) {
return m_local_complex_region_stack.back ().begin_overlapping (box, db::box_convert<box_type> ()).at_end ();
} else {
return m_local_complex_region_stack.back ().begin_touching (box, db::box_convert<box_type> ()).at_end ();
}
}
bool
RecursiveInstanceIterator::is_child_inactive (db::cell_index_type new_child) const
{
bool inactive = is_inactive ();
if (! m_start.empty () && m_start.find (new_child) != m_start.end ()) {
inactive = false;
} else if (! m_stop.empty () && m_stop.find (new_child) != m_stop.end ()) {
inactive = true;
}
return inactive;
}
void
RecursiveInstanceIterator::push (RecursiveInstanceReceiver *receiver)
{
// force reset so we can validate with a receiver
reset ();
receiver->begin (this);
try {
validate (receiver);
while (! at_end ()) {
next (receiver);
}
receiver->end (this);
} catch (...) {
receiver->end (this);
throw;
}
}
}

View File

@ -0,0 +1,660 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_dbRecursiveInstanceIterator
#define HDR_dbRecursiveInstanceIterator
#include "dbCommon.h"
#include "dbLayout.h"
#include "dbInstElement.h"
#include "tlAssert.h"
#include <map>
#include <set>
#include <vector>
namespace db
{
class Region;
class RecursiveInstanceReceiver;
/**
* @brief An iterator delivering shapes that touch or overlap the given region recursively
*
* The iterator can be constructed from a layout, a cell and a region.
* It simplifies retrieval of instances from a geometrical region while considering
* subcells as well.
* Some options can be specified, i.e. the level to which to look into or which cells
* to select.
*
* The general iteration scheme is iterating is top-down and breadth-first.
*
* While the iterator delivers instances, it will first deliver the instances of cells
* and then the instances of cells inside cells whose instances have been delivered already.
* No differentiation is made for leaf or non-leaf cells.
*/
class DB_PUBLIC RecursiveInstanceIterator
{
public:
typedef db::Layout layout_type;
typedef db::Box box_type;
typedef db::Region region_type;
typedef db::Cell cell_type;
typedef db::Cell::touching_iterator inst_iterator;
typedef db::CellInstArray::iterator inst_array_iterator;
typedef db::Instances::overlapping_iterator overlapping_instance_iterator;
typedef db::Instances::touching_iterator touching_instance_iterator;
typedef db::Instance instance_type;
typedef db::ICplxTrans cplx_trans_type;
typedef db::box_tree<db::Box, db::Box, db::box_convert<db::Box>, 20, 20> box_tree_type;
/**
* @brief Default constructor
*/
RecursiveInstanceIterator ();
/**
* @brief Copy constructor
*/
RecursiveInstanceIterator (const RecursiveInstanceIterator &d);
/**
* @brief Assignment
*/
RecursiveInstanceIterator &operator= (const RecursiveInstanceIterator &d);
/**
* @brief Standard constructor
*
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param region The region from which to select the instances
* @param overlapping Specify overlapping mode
*
* By default the iterator operates in touching mode - i.e. instances that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers instances that
* overlap the given region by at least one database unit.
* The cell instances are selected according to their overall bounding box.
*/
RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type &region, bool overlapping = false);
/**
* @brief Standard constructor
*
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode
*
* By default the iterator operates in touching mode - i.e. instances that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers instances that
* overlap the given region by at least one database unit.
* The cell instances are selected according to their overall bounding box.
* This version offers a complex search region instead of a simple box.
*/
RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type &region, bool overlapping = false);
/**
* @brief Standard constructor for "overall" iteration
*
* This iterator delivers all instances recursively.
*
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
*/
RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell);
/**
* @brief Destructor
*/
~RecursiveInstanceIterator ();
/**
* @brief Specify the maximum hierarchy depth to look into
*
* A depth of 0 instructs the iterator to deliver only shapes from the initial cell.
* The depth must be specified before the shapes are being retrieved.
*/
void max_depth (int depth)
{
if (m_max_depth != depth) {
m_max_depth = depth;
m_needs_reinit = true;
}
}
/**
* @brief Gets the maximum hierarchy depth to search for
*/
int max_depth () const
{
return m_max_depth;
}
/**
* @brief Specify the minimum hierarchy depth to look into
*
* A depth of 0 instructs the iterator to deliver shapes from the top level.
* 1 instructs to deliver shapes from the first child level.
* The minimum depth must be specified before the shapes are being retrieved.
*/
void min_depth (int depth)
{
if (m_min_depth != depth) {
m_min_depth = depth;
m_needs_reinit = true;
}
}
/**
* @brief Gets the minimum hierarchy depth to search for
*/
int min_depth () const
{
return m_min_depth;
}
/**
* @brief Gets the layout
*/
const layout_type *layout () const
{
return mp_layout;
}
/**
* @brief Gets the top cell
*
* The top cell is the cell with which the iterator was started
*/
const cell_type *top_cell () const
{
return mp_top_cell;
}
/**
* @brief Gets the basic region the iterator is using (will be world if none is set)
* In addition to the basic region, a complex region may be defined that is further confining the
* search to a subregion of the basic region.
*/
const box_type &region () const
{
return m_region;
}
/**
* @brief Returns true if a complex region is given
*/
bool has_complex_region () const
{
return mp_complex_region.get () != 0;
}
/**
* @brief Gets the complex region the iterator is using
*/
const region_type &complex_region () const
{
tl_assert (mp_complex_region.get ());
return *mp_complex_region;
}
/**
* @brief Sets the region to a basic rectangle
* This will reset the iterator.
*/
void set_region (const box_type &region);
/**
* @brief Sets a complex search region
* This will reset the iterator to the beginning.
*/
void set_region (const region_type &region);
/**
* @brief Confines the search further to the given rectangle.
* This will reset the iterator and confine the search to the given rectangle
* in addition to any region or complex region already defined.
*/
void confine_region (const box_type &region);
/**
* @brief Confines the search further to the given complex region.
* This will reset the iterator and confine the search to the given region
* in addition to any simple region or complex region already defined.
*/
void confine_region (const region_type &region);
/**
* @brief Gets a flag indicating whether overlapping shapes are selected when a region is used
*/
bool overlapping () const
{
return m_overlapping;
}
/**
* @brief Sets a flag indicating whether overlapping shapes are selected when a region is used
*/
void set_overlapping (bool f)
{
if (m_overlapping != f) {
m_overlapping = f;
m_needs_reinit = true;
}
}
/**
* @brief Reset the iterator
*/
void reset ()
{
m_needs_reinit = true;
}
/**
* @brief Select cells
*
* If no specific cells have been selected before, this method will confine the selection
* to the given cells (plus their sub-hierarchy).
* If cells have been selected before, this will add the given cells to the selection.
*/
void select_cells (const std::set<db::cell_index_type> &cells);
/**
* @brief Select all cells
*
* Makes all cells selected. After doing so, all unselect_cells calls
* will unselect only that specific cell without children.
*/
void select_all_cells ();
/**
* @brief Unselect cells
*
* This method will remove the given cells (plus their sub-hierarchy) from the selection.
*/
void unselect_cells (const std::set<db::cell_index_type> &cells);
/**
* @brief Unselect all cells
*
* Makes all cells unselected. After doing so, select_cells calls
* will select only that specific cell without children.
*/
void unselect_all_cells ();
/**
* @brief Resets the selection
*
* This will reset all selections and unselections.
* After calling this methods, all select_cells will again select the cells
* including their children.
*/
void reset_selection ();
/**
* @brief Returns the cells in the "enable" selection
*
* Cells in this set make the iterator become active, while cells in the
* disable selection make the iterator inactive. Only when active, the
* iterator will deliver shapes.
*/
const std::set<db::cell_index_type> &enables () const
{
return m_start;
}
/**
* @brief Returns the cells in the "disable" selection
*/
const std::set<db::cell_index_type> &disables () const
{
return m_stop;
}
/**
* @brief Get the current transformation by which the instances must be transformed into the initial cell
*
* The instances delivered are not transformed. Instead, this transformation must be applied to
* get the instance in the coordinate system of the top cell.
*/
const cplx_trans_type &trans () const
{
validate (0);
return m_trans;
}
/**
* @brief Gets the current depth
*
* Returns the number of hierarchy levels we are below top level currently.
*/
unsigned int depth () const
{
validate (0);
return (unsigned int) m_trans_stack.size ();
}
/**
* @brief Gets the current instance
*
* Returns the instance currently referred to by the recursive iterator.
* This instance is not transformed yet and is located in the current cell.
*/
instance_type instance () const
{
return *operator-> ();
}
/**
* @brief Access operator
*
* The access operator is identical to the instance method.
*/
instance_type operator* () const
{
return *operator-> ();
}
/**
* @brief Access (arrow) operator
*
* The access operator is identical to the instance method.
*/
const instance_type *operator-> () const
{
validate (0);
return m_inst.operator-> ();
}
/**
* @brief End of iterator predicate
*
* Returns true, if the iterator is at the end of the sequence
*/
bool at_end () const;
/**
* @brief Gets the current cell's index
*/
db::cell_index_type cell_index () const
{
return cell ()->cell_index ();
}
/**
* @brief Gets the current cell's reference
*/
const cell_type *cell () const
{
validate (0);
size_t c = reinterpret_cast<size_t> (mp_cell);
return reinterpret_cast<const cell_type *> (c - (c & size_t (3)));
}
/**
* @brief Increments the iterator (operator version)
*/
RecursiveInstanceIterator &operator++()
{
next (0);
return *this;
}
/**
* @brief Increments the iterator
*/
void next ()
{
next (0);
}
/**
* @brief Comparison of iterators - equality
*/
bool operator==(const RecursiveInstanceIterator &d) const
{
if (at_end () != d.at_end ()) {
return false;
} else if (at_end ()) {
return true;
} else {
return (*m_inst == *d.m_inst);
}
}
/**
* @brief Comparison of iterators - inequality
*/
bool operator!=(const RecursiveInstanceIterator &d) const
{
return !operator==(d);
}
/**
* @brief The instance path
*/
std::vector<db::InstElement> path () const;
/**
* @brief Push-mode delivery
*
* This method will deliver all instances to the given receiver.
* In contrast to pull mode, this method allows tailoring the
* traversal of the hierarchy tree during iteration.
* For this purpose, the receiver has methods that receive
* events and to some extend may modify the traversal (e.g.
* return value of enter_cell).
*
* See RecursiveInstanceReceiver class for more details.
*/
void push (RecursiveInstanceReceiver *receiver);
/**
* @brief Returns a value indicating whether the current cell is inactive (disabled)
*/
bool is_inactive () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
}
/**
* @brief Returns a value indicating whether a new child cell of the current cell will be inactive
*/
bool is_child_inactive (db::cell_index_type new_child) const;
private:
int m_max_depth;
int m_min_depth;
unsigned int m_shape_flags;
bool m_shape_inv_prop_sel;
bool m_overlapping;
std::set<db::cell_index_type> m_start, m_stop;
const layout_type *mp_layout;
const cell_type *mp_top_cell;
box_type m_region;
std::unique_ptr<region_type> mp_complex_region;
db::box_convert<db::CellInst> m_box_convert;
mutable inst_iterator m_inst;
mutable inst_array_iterator m_inst_array;
mutable std::map<db::cell_index_type, bool> m_empty_cells_cache;
mutable const cell_type *mp_cell;
mutable cplx_trans_type m_trans;
mutable std::vector<cplx_trans_type> m_trans_stack;
mutable std::vector<inst_iterator> m_inst_iterators;
mutable std::vector<inst_array_iterator> m_inst_array_iterators;
mutable std::vector<const cell_type *> m_cells;
mutable std::vector<box_tree_type> m_local_complex_region_stack;
mutable std::vector<box_type> m_local_region_stack;
mutable bool m_needs_reinit;
mutable size_t m_inst_quad_id;
mutable std::vector<size_t> m_inst_quad_id_stack;
void init ();
void init_region (const region_type &region);
void init_region (const box_type &region);
void skip_inst_iter_for_complex_region () const;
void validate (RecursiveInstanceReceiver *receiver) const;
void next (RecursiveInstanceReceiver *receiver);
void next_instance (RecursiveInstanceReceiver *receiver) const;
void new_inst (RecursiveInstanceReceiver *receiver) const;
void new_inst_member (RecursiveInstanceReceiver *receiver) const;
void new_cell (RecursiveInstanceReceiver *receiver) const;
void up (RecursiveInstanceReceiver *receiver) const;
void down (RecursiveInstanceReceiver *receiver) const;
bool is_outside_complex_region (const box_type &box) const;
box_type correct_box_overlapping (const box_type &box) const;
void set_inactive (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);
c -= (c & size_t (1));
mp_cell = reinterpret_cast<const db::Cell *> (c + (a ? 1 : 0));
}
bool is_all_of_instance () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (2)) != 0;
}
void set_all_of_instance (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);
c -= (c & size_t (2));
mp_cell = reinterpret_cast<const db::Cell *> (c + (a ? 2 : 0));
}
};
/**
* @brief A receiver interface for "push" mode
*
* In push mode, the iterator will deliver the instances and hierarchy transitions
* to this interface. See "RecursiveInstanceIterator::push" for details about this
* mode.
*
* The receiver receives events for the start of the delivery, on each cell
* entry and on each instance (followed by a cell entry).
*/
class DB_PUBLIC RecursiveInstanceReceiver
{
public:
typedef RecursiveInstanceIterator::box_tree_type box_tree_type;
/**
* @brief See new_inst for details.
*/
enum new_inst_mode { NI_all = 0, NI_single = 1, NI_skip = 2 };
/**
* @brief Constructor
*/
RecursiveInstanceReceiver () { }
/**
* @brief Destructor
*/
virtual ~RecursiveInstanceReceiver () { }
/**
* @brief Called once when the iterator begins pushing
*/
virtual void begin (const RecursiveInstanceIterator * /*iter*/) { }
/**
* @brief Called once after the iterator pushed everything
*/
virtual void end (const RecursiveInstanceIterator * /*iter*/) { }
/**
* @brief Enters a cell
*
* This method is called when the recursive shape iterator
* enters a new cell. It is not called for the top cell. When it is called, "iter->trans()"
* will already be updated.
*
* @param iter The iterator
* @param cell The cell which is entered
* @param region The clip box as seen from "cell" or db::Box::world if there is no clip box
* @param complex_region A complex clip region if one is supplied together with "region"
*/
virtual void enter_cell (const RecursiveInstanceIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
/**
* @brief Leaves the current cell
*
* This method is the counterpart for "enter_cell". It is called when traversal of "cell" ended.
*/
virtual void leave_cell (const RecursiveInstanceIterator * /*iter*/, const db::Cell * /*cell*/) { }
/**
* @brief Enters a new instance
*
* This method is called before "enter_cell" and "new_inst_member" is called and will indicate the instance to follow.
* The sequence of events is
*
* new_inst(A)
* new_inst_member(A[0,0])
* enter_cell(A)
* ...
* leave_cell(A)
* new_inst_member(A[1,0])
* enter_cell(A)
* ...
* leave_cell(A)
* ...
* new_inst(B)
* ...
*
* The "all" parameter is true, if all instances of the array will be addressed.
*
* This method can return the following values:
* - NI_all: iterate all members through "new_inst_member"
* - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated)
*/
virtual new_inst_mode new_inst (const RecursiveInstanceIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
/**
* @brief Enters a new array member of the instance
*
* See "new_inst" for a description. This method adds the "trans" parameter
* which holds the complex transformation for this particular instance of
* the array.
*
* "all" is true, if an instance array is iterated in "all" mode (see new_inst).
*
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
*/
virtual bool new_inst_member (const RecursiveInstanceIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
};
} // namespace db
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1023,6 +1023,8 @@ TEST(10)
db::Box b (1000, -500, 2000, 500);
c2.shapes (0).insert (b);
c0.shapes (0).insert (b.moved (db::Vector (-1000, 500)));
c0.shapes (0).insert (b.moved (db::Vector (-2000, 500)));
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2));
@ -1036,6 +1038,9 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
// It's a bit weird to have shape events after new_inst_member, but remember, new_inst_member is a query callback, not an event.
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
@ -1126,6 +1131,8 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"leave_cell($2)\n"
@ -1152,6 +1159,8 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
@ -1194,6 +1203,8 @@ TEST(10)
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n" // -> skipped
@ -1271,6 +1282,8 @@ TEST(10)
EXPECT_EQ (rr2.text (),
"begin\n"
"new_inst($2,all)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"end\n"
);
@ -1282,6 +1295,8 @@ TEST(10)
"begin\n"
"new_inst($2)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"shape(box (0,0;1000,1000),r0 *1 0,0)\n"
"shape(box (-1000,0;0,1000),r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3)\n"
"new_inst_member($3,r0 *1 0,0)\n"

View File

@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
dbCompoundOperationTests.cc \
dbRecursiveInstanceIteratorTests.cc \
dbRegionUtilsTests.cc \
dbUtilsTests.cc \
dbWriterTools.cc \