RecursiveShapeIterator now features a push mode

This will eventually enable catching a hierarchy
skeleton (with shapes) from a RecursiveShapeIterator.
This commit is contained in:
Matthias Koefferlein 2018-11-12 23:44:26 +01:00
parent b192417809
commit f346e70746
4 changed files with 564 additions and 39 deletions

View File

@ -383,7 +383,7 @@ private:
}
void
RecursiveShapeIterator::validate () const
RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
{
if (! m_needs_reinit) {
return;
@ -438,8 +438,8 @@ RecursiveShapeIterator::validate () const
} else if (mp_layout && (! m_has_layers || m_current_layer < m_layers.size ())) {
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
mp_layout->update ();
new_cell ();
next_shape ();
new_cell (receiver);
next_shape (receiver);
}
}
@ -519,7 +519,7 @@ RecursiveShapeIterator::select_all_cells ()
bool
RecursiveShapeIterator::at_end () const
{
validate ();
validate (0);
return m_shape.at_end () || is_inactive ();
}
@ -611,7 +611,7 @@ RecursiveShapeIterator::skip_inst_iter_for_complex_region () const
}
void
RecursiveShapeIterator::next ()
RecursiveShapeIterator::next (RecursiveShapeReceiver *receiver)
{
if (! at_end ()) {
@ -622,14 +622,14 @@ RecursiveShapeIterator::next ()
}
if (! mp_shapes && m_shape.at_end ()) {
next_shape ();
next_shape (receiver);
}
}
}
void
RecursiveShapeIterator::next_shape () const
RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
{
while (at_end ()) {
@ -674,10 +674,10 @@ RecursiveShapeIterator::next_shape () const
if (is_empty) {
++m_inst;
new_inst ();
new_inst (receiver);
} else {
down ();
down (receiver);
}
} else {
@ -688,12 +688,14 @@ RecursiveShapeIterator::next_shape () const
}
// no more instances: up and next instance
up ();
up (receiver);
++m_inst_array;
new_inst_member (receiver);
if (m_inst_array.at_end ()) {
++m_inst;
new_inst ();
new_inst (receiver);
}
}
@ -704,7 +706,7 @@ RecursiveShapeIterator::next_shape () const
}
void
RecursiveShapeIterator::down () const
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
{
m_trans_stack.push_back (m_trans);
m_cells.push_back (mp_cell);
@ -761,12 +763,24 @@ RecursiveShapeIterator::down () const
}
new_cell ();
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 ())) {
if (m_has_layers) {
m_current_layer = m_layers.size ();
}
m_shape = shape_iterator ();
m_inst = inst_iterator ();
} else {
new_cell (receiver);
}
}
void
RecursiveShapeIterator::up () const
RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
{
if (receiver) {
receiver->leave_cell (this, cell ());
}
m_shape = shape_iterator ();
m_shape_quad_id = 0;
@ -823,7 +837,7 @@ RecursiveShapeIterator::new_layer () const
}
void
RecursiveShapeIterator::new_cell () const
RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
{
if (m_has_layers) {
m_current_layer = 0;
@ -847,11 +861,11 @@ RecursiveShapeIterator::new_cell () const
skip_inst_iter_for_complex_region ();
}
new_inst ();
new_inst (receiver);
}
void
RecursiveShapeIterator::new_inst () const
RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
{
// look for the next instance with a non-empty array iterator. The latter can be
// empty because we use a per-layer box converter for that case what we don't for the
@ -866,12 +880,21 @@ RecursiveShapeIterator::new_inst () const
}
}
if (m_local_region_stack.back () != box_type::world ()) {
bool all_of_instance = true;
if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) {
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
all_of_instance = false;
} else {
m_inst_array = m_inst->cell_inst ().begin ();
m_inst_array = m_inst->cell_inst ().begin ();
// 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 ();
}
if (receiver) {
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);
}
new_inst_member (receiver);
if (! m_inst_array.at_end ()) {
break;
} else {
@ -881,6 +904,28 @@ RecursiveShapeIterator::new_inst () const
}
}
void
RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *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;
}
}
}
if (! m_inst_array.at_end () && receiver) {
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 ());
}
}
bool
RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
{
@ -891,5 +936,23 @@ RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
}
}
void
RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
{
// force reset so we can validate with a receiver
reset ();
receiver->begin (this);
validate (receiver);
while (! at_end ()) {
receiver->shape (this, *m_shape, m_trans);
next (receiver);
}
receiver->end (this);
}
}

View File

@ -38,6 +38,7 @@ namespace db
{
class Region;
class RecursiveShapeReceiver;
/**
* @brief An iterator delivering shapes that touch or overlap the given region recursively
@ -479,7 +480,7 @@ public:
*/
unsigned int layer () const
{
validate ();
validate (0);
return m_layer;
}
@ -514,7 +515,7 @@ public:
*/
const cplx_trans_type &trans () const
{
validate ();
validate (0);
return m_trans;
}
@ -525,7 +526,7 @@ public:
*/
unsigned int depth () const
{
validate ();
validate (0);
return (unsigned int) m_trans_stack.size ();
}
@ -537,7 +538,7 @@ public:
*/
shape_type shape () const
{
validate ();
validate (0);
return *m_shape;
}
@ -548,7 +549,7 @@ public:
*/
shape_type operator* () const
{
validate ();
validate (0);
return *m_shape;
}
@ -559,7 +560,7 @@ public:
*/
const shape_type *operator-> () const
{
validate ();
validate (0);
return m_shape.operator-> ();
}
@ -575,7 +576,7 @@ public:
*/
db::cell_index_type cell_index () const
{
validate ();
validate (0);
size_t c = reinterpret_cast<size_t> (mp_cell);
return reinterpret_cast<const cell_type *> (c - (c & size_t (1)))->cell_index ();
}
@ -585,7 +586,7 @@ public:
*/
const cell_type *cell () const
{
validate ();
validate (0);
size_t c = reinterpret_cast<size_t> (mp_cell);
return reinterpret_cast<const cell_type *> (c - (c & size_t (1)));
}
@ -595,14 +596,17 @@ public:
*/
RecursiveShapeIterator &operator++()
{
next ();
next (0);
return *this;
}
/**
* @brief Increment the iterator
* @brief Increments the iterator
*/
void next ();
void next ()
{
next (0);
}
/**
* @brief Comparison of iterators - equality
@ -638,6 +642,20 @@ public:
*/
std::vector<db::InstElement> path () const;
/**
* @brief Push-mode delivery
*
* This method will deliver all shapes 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 RecursiveShapeReceiver class for more details.
*/
void push (RecursiveShapeReceiver *receiver);
private:
std::vector<unsigned int> m_layers;
bool m_has_layers;
@ -681,14 +699,16 @@ private:
void init_region (const box_type &region);
void skip_shape_iter_for_complex_region () const;
void skip_inst_iter_for_complex_region () const;
void validate () const;
void validate (RecursiveShapeReceiver *receiver) const;
void start_shapes () const;
void next_shape () const;
void new_inst () const;
void new_cell () const;
void next (RecursiveShapeReceiver *receiver);
void next_shape (RecursiveShapeReceiver *receiver) const;
void new_inst (RecursiveShapeReceiver *receiver) const;
void new_inst_member (RecursiveShapeReceiver *receiver) const;
void new_cell (RecursiveShapeReceiver *receiver) const;
void new_layer () const;
void up () const;
void down () const;
void up (RecursiveShapeReceiver *receiver) const;
void down (RecursiveShapeReceiver *receiver) const;
bool is_outside_complex_region (const db::Box &box) const;
@ -705,8 +725,99 @@ private:
}
};
/**
* @brief A receiver interface for "push" mode
*
* In push mode, the iterator will deliver the shapes and hierarchy transitions
* to this interface. See "RecursiveShapeIterator::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). It also receives
* the shapes.
*/
class DB_PUBLIC RecursiveShapeReceiver
{
public:
typedef RecursiveShapeIterator::box_tree_type box_tree_type;
RecursiveShapeReceiver () { }
virtual ~RecursiveShapeReceiver () { }
/**
* @brief Called once when the iterator begins pushing
*/
virtual void begin (const RecursiveShapeIterator * /*iter*/) { }
/**
* @brief Called once after the iterator pushed everything
*/
virtual void end (const RecursiveShapeIterator * /*iter*/) { }
/**
* @brief Enters a cell
*
* This method is called when the recursive shape iterator
* enters a new cell. This method can return false. In this
* case, the cell is skipped together with it's subcells.
*
* This method 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 bool enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { return true; }
/**
* @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 RecursiveShapeIterator * /*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.
*/
virtual void new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*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.
*/
virtual void new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
/**
* @brief Delivers a shape
*
* @param trans The transformation which maps the shape to the top cell.
*/
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/) { }
};
} // namespace db
#endif

View File

@ -453,7 +453,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
gsi::method ("cell_index", &db::RecursiveShapeIterator::cell_index,
"@brief Gets the current cell's index \n"
) +
gsi::method ("next", &db::RecursiveShapeIterator::next,
gsi::method ("next", (void (db::RecursiveShapeIterator::*) ()) &db::RecursiveShapeIterator::next,
"@brief Increment the iterator\n"
"This moves the iterator to the next shape inside the search scope."
) +

View File

@ -709,6 +709,21 @@ static db::Layout boxes2layout (const std::set<db::Box> &boxes)
return l;
}
class FlatPusher
: public db::RecursiveShapeReceiver
{
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans)
{
mp_boxes->insert (trans * shape.bbox ());
}
private:
std::set<db::Box> *mp_boxes;
};
TEST(4)
{
// Big fun
@ -751,6 +766,16 @@ TEST(4)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator (g, c0, 0, search_box, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
@ -772,6 +797,16 @@ TEST(4)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator (g, c0, 0, reg, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
}
TEST(5)
@ -819,6 +854,16 @@ TEST(5)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator (g, c0, 0, search_box, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
@ -840,4 +885,310 @@ TEST(5)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator (g, c0, 0, reg, true).push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
}
class LoggingReceiver
: public db::RecursiveShapeReceiver
{
public:
LoggingReceiver () { }
const std::string &text () const { return m_text; }
virtual void begin (const db::RecursiveShapeIterator * /*iter*/) { m_text += "begin\n"; }
virtual void end (const db::RecursiveShapeIterator * /*iter*/) { m_text += "end\n"; }
virtual bool enter_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
m_text += std::string ("enter_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
return true;
}
virtual void leave_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell)
{
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
}
virtual void new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
if (all) {
m_text += ",all";
}
m_text += ")\n";
}
virtual void new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans) + ")\n";
}
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans)
{
m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
}
private:
std::string m_text;
};
class ReceiverRejectingACell
: public LoggingReceiver
{
public:
ReceiverRejectingACell (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual bool enter_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region)
{
LoggingReceiver::enter_cell (iter, cell, region, complex_region);
return cell->cell_index () != m_rejected;
}
private:
db::cell_index_type m_rejected;
};
// Push mode with cells
TEST(10)
{
db::Manager m;
db::Layout g (&m);
g.insert_layer(0);
db::Cell &c0 (g.cell (g.add_cell ()));
db::Cell &c1 (g.cell (g.add_cell ()));
db::Cell &c2 (g.cell (g.add_cell ()));
db::Box b (1000, -500, 2000, 500);
c2.shapes (0).insert (b);
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2));
c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2));
LoggingReceiver lr1;
db::RecursiveShapeIterator i1 (g, c0, 0);
i1.push (&lr1);
EXPECT_EQ (lr1.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,0)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,6000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,8000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,0)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACell rr1 (c2.cell_index ());
db::RecursiveShapeIterator ir1 (g, c0, 0);
ir1.push (&rr1);
EXPECT_EQ (rr1.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACell rr2 (c1.cell_index ());
db::RecursiveShapeIterator ir2 (g, c0, 0);
ir2.push (&rr2);
EXPECT_EQ (rr2.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"enter_cell($2)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000)\n"
"enter_cell($2)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0)\n"
"enter_cell($2)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000)\n"
"enter_cell($2)\n"
"leave_cell($2)\n"
"end\n"
);
LoggingReceiver lr2;
db::RecursiveShapeIterator i2 (g, c0, 0, db::Box (0, 0, 5000, 5000));
i2.push (&lr2);
EXPECT_EQ (lr2.text (),
"begin\n"
"new_inst($2)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"enter_cell($2)\n"
"new_inst($3)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,0)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
}