mirror of https://github.com/KLayout/klayout.git
Global transformations for DRC and RecursiveShapeIterator
This commit is contained in:
parent
536681f5e1
commit
afdc50d05a
|
|
@ -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)
|
||||
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
|
||||
// provided inside the original hierarchy builders. They list the source cells and the target cells
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ int
|
|||
compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
|
||||
{
|
||||
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)) {
|
||||
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
|
||||
|
|
@ -70,6 +70,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
|
|||
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
|
||||
// complex region are identical
|
||||
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 (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) {
|
||||
|
||||
|
|
@ -349,6 +354,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
if (m_cell_stack.back ().first) {
|
||||
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
|
||||
new_inst.object () = db::CellInst (new_cell);
|
||||
new_inst.transform (always_apply);
|
||||
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) {
|
||||
(*c)->insert (new_inst);
|
||||
|
|
@ -367,7 +373,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
}
|
||||
|
||||
bool
|
||||
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all)
|
||||
{
|
||||
if (all) {
|
||||
|
||||
|
|
@ -386,7 +392,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
|
||||
// for a new cell, create this instance
|
||||
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);
|
||||
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);
|
||||
|
|
@ -399,11 +405,11 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box ®ion, 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 ®ion, 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -273,9 +273,9 @@ public:
|
|||
virtual void end (const RecursiveShapeIterator *iter);
|
||||
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
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 ®ion, 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 ®ion, 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 ®ion, const box_tree_type *complex_region);
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all);
|
||||
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
|
||||
/**
|
||||
* @brief Sets the target layer - shapes will be put there
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_current_layer = d.m_current_layer;
|
||||
m_shape = d.m_shape;
|
||||
m_trans = d.m_trans;
|
||||
m_global_trans = d.m_global_trans;
|
||||
m_trans_stack = d.m_trans_stack;
|
||||
m_inst_iterators = d.m_inst_iterators;
|
||||
m_inst_array_iterators = d.m_inst_array_iterators;
|
||||
|
|
@ -286,6 +287,7 @@ RecursiveShapeIterator::init ()
|
|||
m_shape_quad_id = 0;
|
||||
mp_cell = 0;
|
||||
m_current_layer = 0;
|
||||
m_global_trans = cplx_trans_type ();
|
||||
}
|
||||
|
||||
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
|
||||
RecursiveShapeIterator::set_region (const box_type ®ion)
|
||||
{
|
||||
|
|
@ -420,13 +442,13 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
m_inst_quad_id_stack.clear ();
|
||||
m_inst_array_iterators.clear ();
|
||||
m_cells.clear ();
|
||||
m_trans = cplx_trans_type ();
|
||||
m_trans = m_global_trans;
|
||||
m_current_layer = 0;
|
||||
m_shape = shape_iterator ();
|
||||
m_shape_quad_id = 0;
|
||||
|
||||
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 ();
|
||||
if (mp_complex_region.get ()) {
|
||||
|
|
@ -749,8 +771,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
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 ();
|
||||
if (new_region != m_region) {
|
||||
new_region = m_trans.inverted () * m_region;
|
||||
new_region &= cell ()->bbox ();
|
||||
}
|
||||
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;
|
||||
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) {
|
||||
|
|
@ -956,7 +978,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
++m_inst_array;
|
||||
|
|
@ -999,7 +1021,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
|
|||
validate (receiver);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -727,6 +751,7 @@ private:
|
|||
bool m_shape_inv_prop_sel;
|
||||
bool m_overlapping;
|
||||
std::set<db::cell_index_type> m_start, m_stop;
|
||||
cplx_trans_type m_global_trans;
|
||||
|
||||
const layout_type *mp_layout;
|
||||
const cell_type *mp_top_cell;
|
||||
|
|
@ -881,7 +906,7 @@ public:
|
|||
* - 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 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
|
||||
|
|
@ -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.
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @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
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
}
|
||||
|
||||
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 >)
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::set<db::cell_index_type> cc;
|
||||
|
|
@ -270,7 +291,47 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("region", &db::RecursiveShapeIterator::region,
|
||||
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,
|
||||
"@brief Gets the basic region that is iterator is using\n"
|
||||
"The basic region is the overall box the region iterator iterates over. "
|
||||
"There may be an additional complex region that confines the region iterator. "
|
||||
|
|
|
|||
|
|
@ -113,6 +113,19 @@ TEST(1)
|
|||
x = collect_with_copy(i1, g);
|
||||
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));
|
||||
i1_1inf.min_depth(1);
|
||||
x = collect(i1_1inf, g);
|
||||
|
|
@ -731,7 +744,7 @@ namespace {
|
|||
public:
|
||||
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 ());
|
||||
}
|
||||
|
|
@ -766,6 +779,8 @@ TEST(4)
|
|||
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
db::Box search_box (2500, 2500, 7500, 7500);
|
||||
|
||||
std::set<db::Box> selected_boxes;
|
||||
|
|
@ -794,6 +809,45 @@ 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);
|
||||
|
||||
// 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);
|
||||
|
||||
selected_boxes.clear ();
|
||||
|
|
@ -882,6 +936,40 @@ 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);
|
||||
|
||||
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);
|
||||
|
||||
selected_boxes.clear ();
|
||||
|
|
@ -936,7 +1024,7 @@ public:
|
|||
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 ());
|
||||
if (all) {
|
||||
|
|
@ -946,9 +1034,9 @@ public:
|
|||
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) {
|
||||
m_text += ",all";
|
||||
}
|
||||
|
|
@ -956,7 +1044,7 @@ public:
|
|||
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";
|
||||
}
|
||||
|
|
@ -971,9 +1059,9 @@ class ReceiverRejectingACellInstanceArray
|
|||
public:
|
||||
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 ®ion, 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 ®ion, 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;
|
||||
}
|
||||
|
||||
|
|
@ -987,9 +1075,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
|
|||
public:
|
||||
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 ®ion, 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 ®ion, 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;
|
||||
}
|
||||
|
||||
|
|
@ -1003,9 +1091,9 @@ class ReceiverRejectingACellInstance
|
|||
public:
|
||||
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 ®ion, 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 ®ion, 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;
|
||||
}
|
||||
|
||||
|
|
@ -1127,6 +1215,100 @@ TEST(10)
|
|||
"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 ());
|
||||
db::RecursiveShapeIterator ir1 (g, c0, 0);
|
||||
ir1.push (&rr1);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,36 @@ module DRC
|
|||
@in_context = nil
|
||||
|
||||
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
|
||||
DRCJoinFlag::new(true)
|
||||
|
|
@ -1494,6 +1524,22 @@ CODE
|
|||
nil
|
||||
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%
|
||||
# @name cheat
|
||||
# @brief Hierarchy cheats
|
||||
|
|
@ -1679,8 +1725,6 @@ CODE
|
|||
pull_overlapping
|
||||
rectangles
|
||||
rectilinear
|
||||
rotate
|
||||
rotated
|
||||
rounded_corners
|
||||
scale
|
||||
scaled
|
||||
|
|
@ -2440,7 +2484,7 @@ CODE
|
|||
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
|
||||
|
||||
|
|
@ -2454,6 +2498,7 @@ CODE
|
|||
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
|
||||
end
|
||||
iter.shape_flags = shape_flags
|
||||
iter.global_dtrans = global_trans
|
||||
|
||||
sel.each do |s|
|
||||
if s == "-"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ module DRC
|
|||
@clip = false
|
||||
@overlapping = false
|
||||
@tmp_layers = []
|
||||
@global_trans = RBA::DCplxTrans::new
|
||||
end
|
||||
|
||||
# Conceptual deep copy (not including the temp layers)
|
||||
|
|
@ -70,6 +71,24 @@ module DRC
|
|||
def cell_obj
|
||||
@cell
|
||||
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
|
||||
@tmp_layers.each do |li|
|
||||
|
|
@ -245,8 +264,40 @@ module DRC
|
|||
# \touching is a similar method which delivers shapes touching
|
||||
# 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
|
||||
%w(select cell clip touching overlapping).each do |f|
|
||||
%w(select cell clip touching overlapping global_transform).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
@engine._context("#{f}") do
|
||||
|
|
@ -274,7 +325,7 @@ CODE
|
|||
if @box
|
||||
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
|
||||
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
|
||||
layer
|
||||
end
|
||||
|
|
@ -326,7 +377,7 @@ CODE
|
|||
def input(*args)
|
||||
@engine._context("input") do
|
||||
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
|
||||
|
||||
|
|
@ -350,7 +401,7 @@ CODE
|
|||
def labels(*args)
|
||||
@engine._context("labels") do
|
||||
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
|
||||
|
||||
|
|
@ -373,7 +424,7 @@ CODE
|
|||
def polygons(*args)
|
||||
@engine._context("polygons") do
|
||||
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
|
||||
|
||||
|
|
@ -399,7 +450,7 @@ CODE
|
|||
def edges(*args)
|
||||
@engine._context("edges") do
|
||||
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
|
||||
|
||||
|
|
@ -425,7 +476,7 @@ CODE
|
|||
def edge_pairs(*args)
|
||||
@engine._context("edge_pairs") do
|
||||
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
|
||||
|
||||
|
|
@ -437,7 +488,7 @@ CODE
|
|||
|
||||
def make_layer
|
||||
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
|
||||
|
||||
# %DRC%
|
||||
|
|
|
|||
|
|
@ -1168,3 +1168,23 @@ TEST(30_density)
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public:
|
|||
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 ();
|
||||
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 ());
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -63,6 +63,25 @@ class DBRecursiveShapeIterator_TestClass < TestBase
|
|||
|
||||
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
|
||||
|
||||
# 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)
|
||||
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)
|
||||
assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)")
|
||||
|
|
|
|||
Loading…
Reference in New Issue