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)
|
// 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
|
||||||
|
|
|
||||||
|
|
@ -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 ®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) {
|
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 ®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) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ®ion, const box_tree_type *complex_region);
|
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 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 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 db::ICplxTrans &trans, 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 &trans, const db::Box ®ion, 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 ®ion, 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
|
||||||
|
|
|
||||||
|
|
@ -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 ®ion)
|
RecursiveShapeIterator::set_region (const box_type ®ion)
|
||||||
{
|
{
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 >)
|
||||||
|
{
|
||||||
|
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,7 +291,47 @@ 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 ("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"
|
"@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. "
|
||||||
"There may be an additional complex region that confines the region iterator. "
|
"There may be an additional complex region that confines the region iterator. "
|
||||||
|
|
|
||||||
|
|
@ -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 ®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;
|
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 ®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;
|
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 ®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;
|
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);
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,36 @@ module DRC
|
||||||
@in_context = nil
|
@in_context = nil
|
||||||
|
|
||||||
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)
|
||||||
|
|
@ -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 == "-"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -70,6 +71,24 @@ module DRC
|
||||||
def cell_obj
|
def cell_obj
|
||||||
@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|
|
||||||
|
|
@ -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%
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
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)")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue