Global transformations for DRC and RecursiveShapeIterator

This commit is contained in:
Matthias Koefferlein 2021-03-21 23:09:09 +01:00
parent 536681f5e1
commit afdc50d05a
20 changed files with 608 additions and 48 deletions

View File

@ -953,7 +953,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
// collects the cell mappings we skip because they are variants (variant building or box variants) // collects the cell mappings we skip because they are variants (variant building or box variants)
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants; std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) { if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) {
// This is the case of mapping back to the original. In this case we can use the information // This is the case of mapping back to the original. In this case we can use the information
// provided inside the original hierarchy builders. They list the source cells and the target cells // provided inside the original hierarchy builders. They list the source cells and the target cells

View File

@ -40,10 +40,10 @@ int
compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2) compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
{ {
if ((iter1.layout () == 0) != (iter2.layout () == 0)) { if ((iter1.layout () == 0) != (iter2.layout () == 0)) {
return (iter1.layout () == 0) < (iter2.layout () == 0); return (iter1.layout () == 0) < (iter2.layout () == 0) ? -1 : 1;
} }
if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) { if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) {
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0); return (iter1.top_cell () == 0) < (iter2.top_cell () == 0) ? -1 : 1;
} }
// basic source (layout, top_cell) needs to be the same of course // basic source (layout, top_cell) needs to be the same of course
@ -70,6 +70,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
return iter1.enables () < iter2.enables () ? -1 : 1; return iter1.enables () < iter2.enables () ? -1 : 1;
} }
// compare global transformations
if (! iter1.global_trans ().equal (iter2.global_trans ())) {
return iter1.global_trans ().less (iter2.global_trans ()) ? -1 : 1;
}
// if a region is set, the hierarchical appearance is the same only if the layers and // if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are identical // complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) { if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
@ -338,7 +343,7 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
} }
HierarchyBuilder::new_inst_mode HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{ {
if (all) { if (all) {
@ -349,6 +354,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
if (m_cell_stack.back ().first) { if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (inst, &mp_target->array_repository ()); db::CellInstArray new_inst (inst, &mp_target->array_repository ());
new_inst.object () = db::CellInst (new_cell); new_inst.object () = db::CellInst (new_cell);
new_inst.transform (always_apply);
new_inst.transform_into (m_trans); new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) { for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst); (*c)->insert (new_inst);
@ -367,7 +373,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
} }
bool bool
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all) HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{ {
if (all) { if (all) {
@ -386,7 +392,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
// for a new cell, create this instance // for a new cell, create this instance
if (m_cell_stack.back ().first) { if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (db::CellInst (new_cell), trans); db::CellInstArray new_inst (db::CellInst (new_cell), always_apply * trans);
new_inst.transform_into (m_trans); new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) { for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst); (*c)->insert (new_inst);
@ -399,11 +405,11 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
} }
void void
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region) HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &apply_always, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region)
{ {
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) { for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
db::Shapes &shapes = (*c)->shapes (m_target_layer); db::Shapes &shapes = (*c)->shapes (m_target_layer);
mp_pipe->push (shape, m_trans, region, complex_region, &shapes); mp_pipe->push (shape, m_trans * apply_always, region, complex_region, &shapes);
} }
} }

View File

@ -273,9 +273,9 @@ public:
virtual void end (const RecursiveShapeIterator *iter); virtual void end (const RecursiveShapeIterator *iter);
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region); virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region);
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell); virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all); virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all); virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region); virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
/** /**
* @brief Sets the target layer - shapes will be put there * @brief Sets the target layer - shapes will be put there

View File

@ -72,6 +72,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
m_current_layer = d.m_current_layer; m_current_layer = d.m_current_layer;
m_shape = d.m_shape; m_shape = d.m_shape;
m_trans = d.m_trans; m_trans = d.m_trans;
m_global_trans = d.m_global_trans;
m_trans_stack = d.m_trans_stack; m_trans_stack = d.m_trans_stack;
m_inst_iterators = d.m_inst_iterators; m_inst_iterators = d.m_inst_iterators;
m_inst_array_iterators = d.m_inst_array_iterators; m_inst_array_iterators = d.m_inst_array_iterators;
@ -286,6 +287,7 @@ RecursiveShapeIterator::init ()
m_shape_quad_id = 0; m_shape_quad_id = 0;
mp_cell = 0; mp_cell = 0;
m_current_layer = 0; m_current_layer = 0;
m_global_trans = cplx_trans_type ();
} }
void void
@ -318,6 +320,26 @@ RecursiveShapeIterator::init_region (const RecursiveShapeIterator::region_type &
} }
} }
void
RecursiveShapeIterator::set_global_trans (const cplx_trans_type &tr)
{
if (m_global_trans != tr) {
m_global_trans = tr;
m_needs_reinit = true;
}
}
const db::RecursiveShapeIterator::cplx_trans_type &
RecursiveShapeIterator::always_apply () const
{
if (m_trans_stack.empty ()) {
return m_global_trans;
} else {
static cplx_trans_type unity;
return unity;
}
}
void void
RecursiveShapeIterator::set_region (const box_type &region) RecursiveShapeIterator::set_region (const box_type &region)
{ {
@ -420,13 +442,13 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
m_inst_quad_id_stack.clear (); m_inst_quad_id_stack.clear ();
m_inst_array_iterators.clear (); m_inst_array_iterators.clear ();
m_cells.clear (); m_cells.clear ();
m_trans = cplx_trans_type (); m_trans = m_global_trans;
m_current_layer = 0; m_current_layer = 0;
m_shape = shape_iterator (); m_shape = shape_iterator ();
m_shape_quad_id = 0; m_shape_quad_id = 0;
m_local_region_stack.clear (); m_local_region_stack.clear ();
m_local_region_stack.push_back (m_region); m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
m_local_complex_region_stack.clear (); m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) { if (mp_complex_region.get ()) {
@ -749,8 +771,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
box_type new_region = box_type::world (); box_type new_region = box_type::world ();
// compute the region inside the new cell // compute the region inside the new cell
if (new_region != m_local_region_stack.front ()) { if (new_region != m_region) {
new_region = m_trans.inverted () * m_local_region_stack.front (); new_region = m_trans.inverted () * m_region;
new_region &= cell ()->bbox (); new_region &= cell ()->bbox ();
} }
m_local_region_stack.push_back (new_region); m_local_region_stack.push_back (new_region);
@ -911,7 +933,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all; RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
if (receiver) { 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); ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
} }
if (ni == RecursiveShapeReceiver::NI_skip) { if (ni == RecursiveShapeReceiver::NI_skip) {
@ -956,7 +978,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
} }
while (! m_inst_array.at_end () && receiver) { 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 ())) { if (receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), 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; break;
} else { } else {
++m_inst_array; ++m_inst_array;
@ -999,7 +1021,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
validate (receiver); validate (receiver);
while (! at_end ()) { while (! at_end ()) {
receiver->shape (this, *m_shape, m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ()); receiver->shape (this, *m_shape, always_apply (), m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
next (receiver); next (receiver);
} }

View File

@ -391,6 +391,30 @@ public:
} }
} }
/**
* @brief Sets a global transformation
*
* The global transformation will be applied to all shapes delivered by biasing the "trans" attribute
*/
void set_global_trans (const cplx_trans_type &tr);
/**
* @brief Gets the global transformation
*/
cplx_trans_type global_trans () const
{
return m_global_trans;
}
/**
* @brief Gets the transformation which is to be applied always in push mode
*
* The reasoning behind this method is that in push mode and with the presence of a global transformation we need to
* somehow reflect the fact that the top-level is transformed. Instead of transforming every shape and instance we use
* this attribute. It is unity for all cells below top level and equal to the global transformation for the top cell.
*/
const cplx_trans_type &always_apply () const;
/** /**
* @brief Reset the iterator * @brief Reset the iterator
*/ */
@ -727,6 +751,7 @@ private:
bool m_shape_inv_prop_sel; bool m_shape_inv_prop_sel;
bool m_overlapping; bool m_overlapping;
std::set<db::cell_index_type> m_start, m_stop; std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans;
const layout_type *mp_layout; const layout_type *mp_layout;
const cell_type *mp_top_cell; const cell_type *mp_top_cell;
@ -881,7 +906,7 @@ public:
* - NI_single: iterate a single member (the first one) * - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated) * - NI_skip: skips the whole array (not a single instance is iterated)
*/ */
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; } virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
/** /**
* @brief Enters a new array member of the instance * @brief Enters a new array member of the instance
@ -894,14 +919,14 @@ public:
* *
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered. * 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 RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; } virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
/** /**
* @brief Delivers a shape * @brief Delivers a shape
* *
* @param trans The transformation which maps the shape to the top cell. * @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*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { } virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
}; };
} // namespace db } // namespace db

View File

@ -70,6 +70,27 @@ static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ()); return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ());
} }
static db::DCplxTrans si_global_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->global_trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static db::DCplxTrans si_always_apply_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->always_apply () * db::VCplxTrans (1.0 / ly->dbu ());
}
static void si_set_global_dtrans (db::RecursiveShapeIterator *r, const db::DCplxTrans &gt)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
r->set_global_trans (db::VCplxTrans (1.0 / ly->dbu ()) * gt * db::CplxTrans (ly->dbu ()));
}
static void select_cells1 (db::RecursiveShapeIterator *r, const std::vector<db::cell_index_type> &cells) static void select_cells1 (db::RecursiveShapeIterator *r, const std::vector<db::cell_index_type> &cells)
{ {
std::set<db::cell_index_type> cc; std::set<db::cell_index_type> cc;
@ -270,6 +291,46 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n" "\n"
"This method has been introduced in version 0.23.\n" "This method has been introduced in version 0.23.\n"
) + ) +
gsi::method ("global_trans=", &db::RecursiveShapeIterator::set_global_trans, gsi::arg ("t"),
"@brief Sets the global transformation to apply to all shapes delivered\n"
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
"The search regions apply to the coordinate space after global transformation.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("global_trans", &db::RecursiveShapeIterator::global_trans,
"@brief Gets the global transformation to apply to all shapes delivered\n"
"See also \\global_trans=.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("global_dtrans=", &si_set_global_dtrans,
"@brief Sets the global transformation to apply to all shapes delivered (transformation in micrometer units)\n"
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
"The search regions apply to the coordinate space after global transformation.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("global_dtrans", &si_global_dtrans,
"@brief Gets the global transformation to apply to all shapes delivered (in micrometer units)\n"
"See also \\global_dtrans=.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("always_apply_trans", &db::RecursiveShapeIterator::always_apply,
"@brief Gets the global transformation if at top level, unity otherwise\n"
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
"while considering the global transformation properly.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("always_apply_dtrans", &si_always_apply_dtrans,
"@brief Gets the global transformation if at top level, unity otherwise (micrometer-unit version)\n"
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
"while considering the global transformation properly.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("region", &db::RecursiveShapeIterator::region, gsi::method ("region", &db::RecursiveShapeIterator::region,
"@brief Gets the basic region that is iterator is using\n" "@brief Gets the basic region that is iterator is using\n"
"The basic region is the overall box the region iterator iterates over. " "The basic region is the overall box the region iterator iterates over. "

View File

@ -113,6 +113,19 @@ TEST(1)
x = collect_with_copy(i1, g); x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
i1.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
i1.set_region (db::Box (10, 20, 110, 120));
x = collect(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
i1.reset ();
x = collect(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
db::RecursiveShapeIterator i1_1inf (g, c0, 0, db::Box (0, 0, 100, 100)); db::RecursiveShapeIterator i1_1inf (g, c0, 0, db::Box (0, 0, 100, 100));
i1_1inf.min_depth(1); i1_1inf.min_depth(1);
x = collect(i1_1inf, g); x = collect(i1_1inf, g);
@ -731,7 +744,7 @@ namespace {
public: public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { } FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{ {
mp_boxes->insert (trans * shape.bbox ()); mp_boxes->insert (trans * shape.bbox ());
} }
@ -766,6 +779,8 @@ TEST(4)
} }
// ...
db::Box search_box (2500, 2500, 7500, 7500); db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes; std::set<db::Box> selected_boxes;
@ -794,6 +809,45 @@ TEST(4)
EXPECT_EQ (selected_boxes.size () > 100, true); 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); EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// with global trans
selected_boxes.clear ();
selected_boxes2.clear ();
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
{
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
for ( ; !iter.at_end (); ++iter) {
selected_boxes.insert (iter->bbox ().transformed (iter.trans ()));
}
}
{
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (b->transformed (ctr))) {
selected_boxes2.insert (b->transformed (ctr));
}
}
}
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 iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
iter.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); db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear (); selected_boxes.clear ();
@ -882,6 +936,40 @@ TEST(5)
EXPECT_EQ (selected_boxes.size () > 100, true); 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); EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
selected_boxes.clear ();
selected_boxes2.clear ();
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
{
db::RecursiveShapeIterator iter = db::RecursiveShapeIterator (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
for ( ; !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->bbox ());
}
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (b->transformed (ctr))) {
selected_boxes2.insert (b->transformed (ctr));
}
}
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 iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
iter.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); db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear (); selected_boxes.clear ();
@ -936,7 +1024,7 @@ public:
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
} }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, 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 ()); m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
if (all) { if (all) {
@ -946,9 +1034,9 @@ public:
return NI_all; return NI_all;
} }
virtual bool 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*/, bool all) virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{ {
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans); m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (always_apply * trans);
if (all) { if (all) {
m_text += ",all"; m_text += ",all";
} }
@ -956,7 +1044,7 @@ public:
return true; return true;
} }
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{ {
m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n"; m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
} }
@ -971,9 +1059,9 @@ class ReceiverRejectingACellInstanceArray
public: public:
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { } ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all) virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all)
{ {
LoggingReceiver::new_inst (iter, inst, region, complex_region, all); LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip; return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
} }
@ -987,9 +1075,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
public: public:
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { } ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all) virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all)
{ {
LoggingReceiver::new_inst (iter, inst, region, complex_region, all); LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_single; return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
} }
@ -1003,9 +1091,9 @@ class ReceiverRejectingACellInstance
public: public:
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { } ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { }
virtual bool 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, bool all) virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{ {
LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all); LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all);
return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected; return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
} }
@ -1127,6 +1215,100 @@ TEST(10)
"end\n" "end\n"
); );
LoggingReceiver lr1_gt;
db::RecursiveShapeIterator i1_gt (g, c0, 0);
i1_gt.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
i1_gt.push (&lr1_gt);
EXPECT_EQ (lr1_gt.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 10,20,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 10,20)\n"
"shape(box (-1000,0;0,1000),r0 *1 10,20)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,20)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,2020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,1020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,3020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 10,6020,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,6020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,8020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,7020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,9020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6010,20,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,20)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,2020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,1020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,3020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6010,6020,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,6020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,8020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,7020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,9020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ()); ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ());
db::RecursiveShapeIterator ir1 (g, c0, 0); db::RecursiveShapeIterator ir1 (g, c0, 0);
ir1.push (&rr1); ir1.push (&rr1);

View File

@ -64,6 +64,36 @@ module DRC
end end
def shift(x, y)
self._context("shift") do
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))
end
end
def magnify(m)
self._context("magnify") do
RBA::DCplxTrans::new(_make_numeric_value(m))
end
end
def rotate(a)
self._context("rotate") do
RBA::DCplxTrans::new(1.0, _make_numeric_value(a), false, RBA::DVector::new)
end
end
def mirror_x
self._context("mirror_x") do
RBA::DCplxTrans::new(1.0, 0.0, true, RBA::DVector::new)
end
end
def mirror_y
self._context("mirror_y") do
RBA::DCplxTrans::new(1.0, 180.0, true, RBA::DVector::new)
end
end
def joined def joined
DRCJoinFlag::new(true) DRCJoinFlag::new(true)
end end
@ -1494,6 +1524,22 @@ CODE
nil nil
end end
# %DRC%
# @name global_transform
# @brief Gets or sets a global transformation
# @synopsis global_transform
# @synopsis global_transform([ transformations ])
#
# Applies a global transformation to the default source layout.
# See \Source#global_transform for a description of this feature.
def global_transform(*args)
self._context("global_transform") do
@def_source = layout.global_transform(*args)
end
nil
end
# %DRC% # %DRC%
# @name cheat # @name cheat
# @brief Hierarchy cheats # @brief Hierarchy cheats
@ -1679,8 +1725,6 @@ CODE
pull_overlapping pull_overlapping
rectangles rectangles
rectilinear rectilinear
rotate
rotated
rounded_corners rounded_corners
scale scale
scaled scaled
@ -2440,7 +2484,7 @@ CODE
end end
end end
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, cls) def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, global_trans, cls)
if layers.empty? && ! @deep if layers.empty? && ! @deep
@ -2454,6 +2498,7 @@ CODE
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers) iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
end end
iter.shape_flags = shape_flags iter.shape_flags = shape_flags
iter.global_dtrans = global_trans
sel.each do |s| sel.each do |s|
if s == "-" if s == "-"

View File

@ -27,6 +27,7 @@ module DRC
@clip = false @clip = false
@overlapping = false @overlapping = false
@tmp_layers = [] @tmp_layers = []
@global_trans = RBA::DCplxTrans::new
end end
# Conceptual deep copy (not including the temp layers) # Conceptual deep copy (not including the temp layers)
@ -71,6 +72,24 @@ module DRC
@cell @cell
end end
def inplace_global_transform(*args)
gt = RBA::DCplxTrans::new
args.each do |a|
if a.is_a?(RBA::DVector) || a.is_a?(RBA::DTrans)
gt = RBA::DCplxTrans::new(a) * gt
elsif a.is_a?(RBA::DCplxTrans)
gt = a * gt
else
raise("Expected a transformation spec instead of #{a.inspect}")
end
end
@global_trans = gt
end
def global_transformation
@global_trans
end
def finish def finish
@tmp_layers.each do |li| @tmp_layers.each do |li|
@layout.delete_layer(li) @layout.delete_layer(li)
@ -245,8 +264,40 @@ module DRC
# \touching is a similar method which delivers shapes touching # \touching is a similar method which delivers shapes touching
# the search region with their bounding box (without the requirement to overlap) # the search region with their bounding box (without the requirement to overlap)
# %DRC%
# @name global_transform
# @brief Gets or sets a global transformation
# @synopsis global_transform
# @synopsis global_transform([ transformations ])
#
# This method returns a new source representing the transformed layout. It is provided in the spritit of
# \Source#clip and similar methods.
#
# The transformation
# is either given as a RBA::DTrans, RBA::DVector or RBA::DCplxTrans object or as one of the
# following specifications:
#
# @ul
# @li "shift(x, y)": shifts the input layout horizontally by x and vertically by y micrometers
# @li "rotate(a)": rotates the input layout by a degree counter-clockwise
# @li "magnify(m)": magnifies the input layout by the factor m (NOTE: using fractional scale factors may result in small gaps due to grid snapping)
# @li "mirror_x": mirrors the input layout at the x axis
# @li "mirror_y": mirrors the input layout at the y axis
# @/ul
#
# Multiple transformation specs can be given. In that case the transformations are applied right to left.
# Using "global_transform" will reset any global transformation present already.
# Without an argument, the global transformation is reset.
#
# The following example rotates the layout by 90 degree at the origin (0, 0) and then shifts it up by
# 100 micrometers:
#
# @code
# source.global_transform(shift(0, 100.um), rotate(90.0))
# @/code
# export inplace_* as * out-of-place # export inplace_* as * out-of-place
%w(select cell clip touching overlapping).each do |f| %w(select cell clip touching overlapping global_transform).each do |f|
eval <<"CODE" eval <<"CODE"
def #{f}(*args) def #{f}(*args)
@engine._context("#{f}") do @engine._context("#{f}") do
@ -274,7 +325,7 @@ CODE
if @box if @box
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu) layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
else else
layer.insert(RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu) layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
end end
layer layer
end end
@ -326,7 +377,7 @@ CODE
def input(*args) def input(*args)
@engine._context("input") do @engine._context("input") do
layers = parse_input_layers(*args) layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region)) DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
end end
end end
@ -350,7 +401,7 @@ CODE
def labels(*args) def labels(*args)
@engine._context("labels") do @engine._context("labels") do
layers = parse_input_layers(*args) layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, RBA::Texts)) DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, @global_trans, RBA::Texts))
end end
end end
@ -373,7 +424,7 @@ CODE
def polygons(*args) def polygons(*args)
@engine._context("polygons") do @engine._context("polygons") do
layers = parse_input_layers(*args) layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, RBA::Region)) DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, @global_trans, RBA::Region))
end end
end end
@ -399,7 +450,7 @@ CODE
def edges(*args) def edges(*args)
@engine._context("edges") do @engine._context("edges") do
layers = parse_input_layers(*args) layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, RBA::Edges)) DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, @global_trans, RBA::Edges))
end end
end end
@ -425,7 +476,7 @@ CODE
def edge_pairs(*args) def edge_pairs(*args)
@engine._context("edge_pairs") do @engine._context("edge_pairs") do
layers = parse_input_layers(*args) layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, RBA::EdgePairs)) DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, @global_trans, RBA::EdgePairs))
end end
end end
@ -437,7 +488,7 @@ CODE
def make_layer def make_layer
layers = [] layers = []
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region)) DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
end end
# %DRC% # %DRC%

View File

@ -1168,3 +1168,23 @@ TEST(30_density)
run_test (_this, "30", false); run_test (_this, "30", false);
} }
TEST(31_globaTransformation)
{
run_test (_this, "31", false);
}
TEST(31d_globalTransformation)
{
run_test (_this, "31", true);
}
TEST(32_globalTransformationWithClip)
{
run_test (_this, "32", false);
}
TEST(32d_globalTransformationWithClip)
{
run_test (_this, "32", true);
}

View File

@ -146,7 +146,7 @@ public:
m_cell_stack.pop_back (); m_cell_stack.pop_back ();
} }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
{ {
db::cell_index_type ci = inst.object ().cell_index (); db::cell_index_type ci = inst.object ().cell_index ();
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) { if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {
@ -156,7 +156,7 @@ public:
} }
} }
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{ {
tl_assert (! m_cell_stack.empty ()); tl_assert (! m_cell_stack.empty ());
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape); create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape);
@ -209,9 +209,9 @@ public:
} }
} }
virtual void shape (const db::RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{ {
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * iter->trans (), shape); create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape);
} }
public: public:

57
testdata/drc/drcSimpleTests_31.drc vendored Normal file
View File

@ -0,0 +1,57 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
def self_test(id, a, b)
a == b || raise(id + ": self-test failed (" + a.inspect + " != " + b.inspect + ")")
end
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *1 0,0")
global_transform(magnify(2.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 0,0")
global_transform(magnify(2.0), rotate(90.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r90 *2 0,0")
global_transform(mirror_x, mirror_y)
self_test("magnify(2.0)", source.global_transformation.to_s, "r180 *1 0,0")
global_transform(magnify(2.0), shift(10.um, 20.um))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 10,20")
# The actual DRC test
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
l1.merged.output(10, 0)
l1.sized(100.nm).output(11, 0)
l2.sized(100.nm).output(12, 0)
# reset
global_transform
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(101, 0)
l2.output(102, 0)
l1.merged.output(110, 0)
l1.sized(100.nm).output(111, 0)
l2.sized(100.nm).output(112, 0)

BIN
testdata/drc/drcSimpleTests_31.gds vendored Normal file

Binary file not shown.

59
testdata/drc/drcSimpleTests_32.drc vendored Normal file
View File

@ -0,0 +1,59 @@
source $drc_test_source
target $drc_test_target
clip(0.um, 0.um, 26.um, 45.um)
if $drc_test_deep
deep
end
def self_test(id, a, b)
a == b || raise(id + ": self-test failed (" + a.inspect + " != " + b.inspect + ")")
end
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *1 0,0")
global_transform(magnify(2.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 0,0")
global_transform(magnify(2.0), rotate(90.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r90 *2 0,0")
global_transform(mirror_x, mirror_y)
self_test("magnify(2.0)", source.global_transformation.to_s, "r180 *1 0,0")
global_transform(magnify(2.0), shift(10.um, 20.um))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 10,20")
# The actual DRC test
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
l1.merged.output(10, 0)
l1.sized(100.nm).output(11, 0)
l2.sized(100.nm).output(12, 0)
# reset
global_transform
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(101, 0)
l2.output(102, 0)
l1.merged.output(110, 0)
l1.sized(100.nm).output(111, 0)
l2.sized(100.nm).output(112, 0)

BIN
testdata/drc/drcSimpleTests_32.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au31.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au31d.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au32.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au32d.gds vendored Normal file

Binary file not shown.

View File

@ -63,6 +63,25 @@ class DBRecursiveShapeIterator_TestClass < TestBase
end end
def acollect(s, l)
res = []
while !s.at_end?
r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box?
box = s.shape.box
r += box.transformed(s.always_apply_trans).to_s
else
r += "X";
end
s.next
res.push(r)
end
return res.join("/")
end
def test_1 def test_1
# Recursive shape iterator tests # Recursive shape iterator tests
@ -197,6 +216,19 @@ class DBRecursiveShapeIterator_TestClass < TestBase
ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), false) ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), false)
assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)") assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)")
ii.reset
assert_equal(acollect(ii, l), "[c2](0,100;1000,1200)/[c3](0,100;1000,1200)/[c3](1,101;1001,1201)")
ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 20, 2000, 121), true)
ii.global_trans = RBA::ICplxTrans::new(RBA::Vector::new(10, 20))
assert_equal(ii.global_trans.to_s, "r0 *1 10,20")
assert_equal(collect(ii, l), "[c2](10,120;1010,1220)/[c3](1110,120;2110,1220)")
ii.global_dtrans = RBA::DCplxTrans::new(RBA::DVector::new(0.01, 0.02))
ii.reset
assert_equal(ii.global_dtrans.to_s, "r0 *1 0.01,0.02")
assert_equal(collect(ii, l), "[c2](10,120;1010,1220)/[c3](1110,120;2110,1220)")
ii.reset
assert_equal(acollect(ii, l), "[c2](10,120;1010,1220)/[c3](0,100;1000,1200)")
ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), true) ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), true)
assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)") assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)")