diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 32b7988a6..d57c364e4 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -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 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 diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 5a6751f87..66fbc8a41 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -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::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::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::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); } } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index 2bb1eca0a..27601e8ae 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -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 diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index a72fc5e1e..7cb884550 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -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); } diff --git a/src/db/db/dbRecursiveShapeIterator.h b/src/db/db/dbRecursiveShapeIterator.h index 0afdd5423..95c2b0e99 100644 --- a/src/db/db/dbRecursiveShapeIterator.h +++ b/src/db/db/dbRecursiveShapeIterator.h @@ -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 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 diff --git a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc index 72070d1e7..091f3ba83 100644 --- a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc @@ -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 &cells) { std::set cc; @@ -270,7 +291,47 @@ Class 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. " diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index cf559bb1f..2f5577c58 100644 --- a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc @@ -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 *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 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::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::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); diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 65c76b590..5b60a23e5 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -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 == "-" diff --git a/src/drc/drc/built-in-macros/_drc_source.rb b/src/drc/drc/built-in-macros/_drc_source.rb index 4750c0b1f..d36fd2675 100644 --- a/src/drc/drc/built-in-macros/_drc_source.rb +++ b/src/drc/drc/built-in-macros/_drc_source.rb @@ -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% diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index b1508b821..b1923f9cc 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -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); +} + diff --git a/src/rdb/rdb/rdbUtils.cc b/src/rdb/rdb/rdbUtils.cc index 931da36c0..336ed963e 100644 --- a/src/rdb/rdb/rdbUtils.cc +++ b/src/rdb/rdb/rdbUtils.cc @@ -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: diff --git a/testdata/drc/drcSimpleTests_31.drc b/testdata/drc/drcSimpleTests_31.drc new file mode 100644 index 000000000..6f3480b6a --- /dev/null +++ b/testdata/drc/drcSimpleTests_31.drc @@ -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) + diff --git a/testdata/drc/drcSimpleTests_31.gds b/testdata/drc/drcSimpleTests_31.gds new file mode 100644 index 000000000..735cbfe7c Binary files /dev/null and b/testdata/drc/drcSimpleTests_31.gds differ diff --git a/testdata/drc/drcSimpleTests_32.drc b/testdata/drc/drcSimpleTests_32.drc new file mode 100644 index 000000000..a6660946c --- /dev/null +++ b/testdata/drc/drcSimpleTests_32.drc @@ -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) + diff --git a/testdata/drc/drcSimpleTests_32.gds b/testdata/drc/drcSimpleTests_32.gds new file mode 100644 index 000000000..735cbfe7c Binary files /dev/null and b/testdata/drc/drcSimpleTests_32.gds differ diff --git a/testdata/drc/drcSimpleTests_au31.gds b/testdata/drc/drcSimpleTests_au31.gds new file mode 100644 index 000000000..9a33e4995 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au31.gds differ diff --git a/testdata/drc/drcSimpleTests_au31d.gds b/testdata/drc/drcSimpleTests_au31d.gds new file mode 100644 index 000000000..38514972a Binary files /dev/null and b/testdata/drc/drcSimpleTests_au31d.gds differ diff --git a/testdata/drc/drcSimpleTests_au32.gds b/testdata/drc/drcSimpleTests_au32.gds new file mode 100644 index 000000000..6b9829294 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au32.gds differ diff --git a/testdata/drc/drcSimpleTests_au32d.gds b/testdata/drc/drcSimpleTests_au32d.gds new file mode 100644 index 000000000..414bb2ff4 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au32d.gds differ diff --git a/testdata/ruby/dbRecursiveShapeIterator.rb b/testdata/ruby/dbRecursiveShapeIterator.rb index cbec7ee84..58f33c023 100644 --- a/testdata/ruby/dbRecursiveShapeIterator.rb +++ b/testdata/ruby/dbRecursiveShapeIterator.rb @@ -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)")