mirror of https://github.com/KLayout/klayout.git
Recursive instance iterator, first draft.
This commit is contained in:
parent
9d349239b5
commit
412056afed
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion)
|
||||
{
|
||||
m_region = region;
|
||||
mp_complex_region.reset (0);
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveInstanceIterator::init_region (const RecursiveInstanceIterator::region_type ®ion)
|
||||
{
|
||||
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 ®ion)
|
||||
{
|
||||
if (m_region != region || mp_complex_region.get () != 0) {
|
||||
init_region (region);
|
||||
m_needs_reinit = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveInstanceIterator::set_region (const region_type ®ion)
|
||||
{
|
||||
init_region (region);
|
||||
m_needs_reinit = true;
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveInstanceIterator::confine_region (const box_type ®ion)
|
||||
{
|
||||
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 ®ion)
|
||||
{
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion () 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 ®ion);
|
||||
|
||||
/**
|
||||
* @brief Sets a complex search region
|
||||
* This will reset the iterator to the beginning.
|
||||
*/
|
||||
void set_region (const region_type ®ion);
|
||||
|
||||
/**
|
||||
* @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 ®ion);
|
||||
|
||||
/**
|
||||
* @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 ®ion);
|
||||
|
||||
/**
|
||||
* @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 ®ion);
|
||||
void init_region (const box_type ®ion);
|
||||
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
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
|
|||
|
||||
SOURCES = \
|
||||
dbCompoundOperationTests.cc \
|
||||
dbRecursiveInstanceIteratorTests.cc \
|
||||
dbRegionUtilsTests.cc \
|
||||
dbUtilsTests.cc \
|
||||
dbWriterTools.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue