diff --git a/src/db/db/dbLayoutQuery.cc b/src/db/db/dbLayoutQuery.cc index 02ab78dd1..901e615ca 100644 --- a/src/db/db/dbLayoutQuery.cc +++ b/src/db/db/dbLayoutQuery.cc @@ -42,10 +42,69 @@ namespace db // -------------------------------------------------------------------------------- // Some utilities -bool check_trailing_reserved_word (const tl::Extractor &ex0) +static const char *s_select = "select"; +static const char *s_delete = "delete"; +static const char *s_or = "or"; +static const char *s_of = "of"; +static const char *s_on = "on"; +static const char *s_do = "do"; +static const char *s_from = "from"; +static const char *s_layer = "layer"; +static const char *s_layers = "layers"; +static const char *s_cell = "cell"; +static const char *s_cells = "cells"; +static const char *s_where = "where"; +static const char *s_shapes = "shapes"; +static const char *s_polygons = "polygons"; +static const char *s_boxes = "boxes"; +static const char *s_edges = "edges"; +static const char *s_paths = "paths"; +static const char *s_texts = "texts"; +static const char *s_instances = "instances"; +static const char *s_arrays = "arrays"; +static const char *s_sorted = "sorted"; +static const char *s_unique = "unique"; +static const char *s_by = "by"; +static const char *s_with = "with"; +static const char *s_pass = "pass"; + +const char *s_reserved_words[] = { + s_select, + s_delete, + s_or, + s_of, + s_on, + s_do, + s_from, + s_layer, + s_layers, + s_cell, + s_cells, + s_where, + s_shapes, + s_polygons, + s_boxes, + s_edges, + s_paths, + s_texts, + s_instances, + s_arrays, + s_sorted, + s_unique, + s_by, + s_with, + s_pass +}; + +bool check_trailing_reserved_word (const tl::Extractor &ex0) { tl::Extractor ex = ex0; - return (ex.test ("do") || ex.test ("sorted") || ex.test ("pass") || ex.test ("where")); + for (size_t i = 0; i < sizeof (s_reserved_words) / sizeof (s_reserved_words[0]); ++i) { + if (ex.test (s_reserved_words[i])) { + return true; + } + } + return false; } // -------------------------------------------------------------------------------- @@ -202,7 +261,9 @@ struct ShapeFilterPropertyIDs ShapeFilterPropertyIDs (LayoutQuery *q) { bbox = q->register_property ("bbox", LQ_box); + dbbox = q->register_property ("dbbox", LQ_dbox); shape_bbox = q->register_property ("shape_bbox", LQ_box); + shape_dbbox = q->register_property ("shape_dbbox", LQ_dbox); shape = q->register_property ("shape", LQ_shape); layer_info = q->register_property ("layer_info", LQ_layer); layer_index = q->register_property ("layer_index", LQ_variant); @@ -211,7 +272,9 @@ struct ShapeFilterPropertyIDs } unsigned int bbox; // bbox -> The shape's bounding box + unsigned int dbbox; // dbbox -> The shape's bounding box in micrometer units unsigned int shape_bbox; // shape_bbox -> == box + unsigned int shape_dbbox; // shape_dbbox -> == dbox unsigned int shape; // shape -> The shape object unsigned int layer_info; // layer_info -> The layer (a LayerInfo object) unsigned int layer_index; // layer_index -> The layer index @@ -309,6 +372,12 @@ public: v = tl::Variant::make_variant (m_shape->bbox ()); return true; + } else if (id == m_pids.dbbox || id == m_pids.shape_dbbox) { + + tl_assert (mp_parent->layout ()); + v = tl::Variant::make_variant (db::CplxTrans (mp_parent->layout ()->dbu ()) * m_shape->bbox ()); + return true; + } else if (id == m_pids.shape) { if (m_reading) { @@ -418,7 +487,9 @@ struct ChildCellFilterPropertyIDs parent_cell_name = q->register_property ("parent_cell_name", LQ_variant); hier_levels = q->register_property ("hier_levels", LQ_variant); bbox = q->register_property ("bbox", LQ_box); + dbbox = q->register_property ("dbbox", LQ_dbox); cell_bbox = q->register_property ("cell_bbox", LQ_box); + cell_dbbox = q->register_property ("cell_dbbox", LQ_dbox); // with instance_mode == NoInstances: if (instance_mode == NoInstances) { @@ -434,21 +505,31 @@ struct ChildCellFilterPropertyIDs // with instance_mode != NoInstances: if (instance_mode != NoInstances) { path_trans = q->register_property ("path_trans", LQ_trans); + path_dtrans = q->register_property ("path_dtrans", LQ_dtrans); trans = q->register_property ("trans", LQ_trans); + dtrans = q->register_property ("dtrans", LQ_dtrans); inst_bbox = q->register_property ("inst_bbox", LQ_box); + inst_dbbox = q->register_property ("inst_dbbox", LQ_box); inst = q->register_property ("inst", LQ_instance); array_a = q->register_property ("array_a", LQ_point); + array_da = q->register_property ("array_da", LQ_dpoint); array_na = q->register_property ("array_na", LQ_variant); array_b = q->register_property ("array_b", LQ_point); + array_db = q->register_property ("array_db", LQ_dpoint); array_nb = q->register_property ("array_nb", LQ_variant); } else { path_trans = std::numeric_limits::max (); + path_dtrans = std::numeric_limits::max (); trans = std::numeric_limits::max (); + dtrans = std::numeric_limits::max (); inst_bbox = std::numeric_limits::max (); + inst_dbbox = std::numeric_limits::max (); inst = std::numeric_limits::max (); array_a = std::numeric_limits::max (); + array_da = std::numeric_limits::max (); array_na = std::numeric_limits::max (); array_b = std::numeric_limits::max (); + array_db = std::numeric_limits::max (); array_nb = std::numeric_limits::max (); } @@ -475,7 +556,9 @@ struct ChildCellFilterPropertyIDs unsigned int parent_cell_name; // parent_cell_name -> Name of parent cell (next in path) or nil unsigned int hier_levels; // hier_levels -> Number of hierarchy levels in path (length of path - 1) unsigned int bbox; // bbox -> Cell bounding box + unsigned int dbbox; // dbbox -> Cell bounding box in micrometer units unsigned int cell_bbox; // cell_bbox -> == bbox + unsigned int cell_dbbox; // cell_dbbox -> == dbbox // with instance_mode == NoInstances: unsigned int references; // references -> The number of instances (arefs count as 1) of this cell in the parent cell @@ -484,17 +567,22 @@ struct ChildCellFilterPropertyIDs // with instance_mode != NoInstances: unsigned int path_trans; // path_trans -> The transformation of that instance into the top cell + unsigned int path_dtrans; // path_dtrans -> The transformation of that instance into the top cell in micrometer units unsigned int trans; // trans -> The transformation of that instance (first instance if an array) + unsigned int dtrans; // dtrans -> The transformation of that instance (first instance if an array) in micrometer units unsigned int inst_bbox; // inst_bbox -> The instance bounding box in the top cell + unsigned int inst_dbbox; // inst_dbbox -> The instance bounding box in the top cell in micrometer units unsigned int inst; // inst -> The instance object unsigned int array_a; // array_a -> The a vector for an array instance + unsigned int array_da; // array_da -> The a vector for an array instance in micrometer units unsigned int array_na; // array_na -> The a axis array dimension unsigned int array_b; // array_b -> The b vector for an array instance + unsigned int array_db; // array_db -> The b vector for an array instance in micrometer units unsigned int array_nb; // array_nb -> The b axis array dimension // with instance_mode == ExplodedInstances: unsigned int array_ia; // array_ia -> The a index when an array is iterated - unsigned int array_ib; // array_ib -> The b index when an array is iterated + unsigned int array_ib; // array_ib -> The b index when an array is iterated }; class DB_PUBLIC ChildCellFilterState @@ -764,6 +852,15 @@ public: } return true; + } else if (id == m_pids.dbbox || id == m_pids.cell_dbbox) { + + if (! layout ()->is_valid_cell_index (cell_index ())) { + v = tl::Variant (); + } else { + v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * layout ()->cell (cell_index ()).bbox ()); + } + return true; + } else if (id == m_pids.cell_name) { if (! layout ()->is_valid_cell_index (cell_index ())) { @@ -983,6 +1080,35 @@ public: return false; } + } else if (id == m_pids.inst_dbbox) { + + if (mp_parent) { + + if (m_instance_mode == ExplodedInstances) { + + db::ICplxTrans t = m_parent_trans; + t *= (*m_inst)->complex_trans (*m_array_iter); + db::DBox box (db::CplxTrans (layout ()->dbu ()) * t * layout ()->cell ((*m_inst)->object ().cell_index ()).bbox ()); + v = tl::Variant::make_variant (box); + return true; + + } else if (m_instance_mode == ArrayInstances) { + + db::ICplxTrans t = m_parent_trans; + t *= (*m_inst)->complex_trans (); + db::box_convert bc (*layout ()); + db::DBox box (db::CplxTrans (layout ()->dbu ()) * t * (*m_inst)->bbox (bc)); + v = tl::Variant::make_variant (box); + return true; + + } else { + return false; + } + + } else { + return false; + } + } else if (id == m_pids.path_trans) { if (mp_parent) { @@ -1011,6 +1137,36 @@ public: return true; } + } else if (id == m_pids.path_dtrans) { + + if (mp_parent) { + + if (m_instance_mode == ExplodedInstances) { + + db::ICplxTrans t = m_parent_trans; + t *= (*m_inst)->complex_trans (*m_array_iter); + db::CplxTrans tdbu (layout ()->dbu ()); + v = tl::Variant::make_variant (tdbu * t * tdbu.inverted ()); + return true; + + } else if (m_instance_mode == ArrayInstances) { + + db::ICplxTrans t = m_parent_trans; + t *= (*m_inst)->complex_trans (); + db::CplxTrans tdbu (layout ()->dbu ()); + v = tl::Variant::make_variant (tdbu * t * tdbu.inverted ()); + return true; + + } else { + v = tl::Variant::make_variant (db::ICplxTrans ()); + return true; + } + + } else { + v = tl::Variant::make_variant (db::ICplxTrans ()); + return true; + } + } else if (id == m_pids.trans) { if (mp_parent) { @@ -1033,6 +1189,30 @@ public: return false; } + } else if (id == m_pids.dtrans) { + + if (mp_parent) { + + if (m_instance_mode == ExplodedInstances) { + + db::CplxTrans tdbu (layout ()->dbu ()); + v = tl::Variant::make_variant (tdbu * (*m_inst)->complex_trans (*m_array_iter) * tdbu.inverted ()); + return true; + + } else if (m_instance_mode == ArrayInstances) { + + db::CplxTrans tdbu (layout ()->dbu ()); + v = tl::Variant::make_variant (tdbu * (*m_inst)->complex_trans () * tdbu.inverted ()); + return true; + + } else { + return false; + } + + } else { + return false; + } + } else if (id == m_pids.inst) { if (! mp_parent || m_instance_mode == NoInstances) { @@ -1064,7 +1244,7 @@ public: return true; } - } else if (id == m_pids.array_a || id == m_pids.array_b || id == m_pids.array_na || id == m_pids.array_nb) { + } else if (id == m_pids.array_a || id == m_pids.array_b || id == m_pids.array_da || id == m_pids.array_db || id == m_pids.array_na || id == m_pids.array_nb) { if (! mp_parent || m_instance_mode == NoInstances) { return false; @@ -1074,8 +1254,12 @@ public: if ((*m_inst)->is_regular_array (a, b, na, nb)) { if (id == m_pids.array_a) { v = tl::Variant::make_variant (a); + } else if (id == m_pids.array_da) { + v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * a); } else if (id == m_pids.array_b) { v = tl::Variant::make_variant (b); + } else if (id == m_pids.array_db) { + v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * b); } else if (id == m_pids.array_na) { v = na; } else if (id == m_pids.array_nb) { @@ -1178,8 +1362,11 @@ struct CellFilterPropertyIDs tot_weight = q->register_property ("tot_weight", LQ_variant); instances = q->register_property ("instances", LQ_variant); bbox = q->register_property ("bbox", LQ_box); + dbbox = q->register_property ("dbbox", LQ_dbox); cell_bbox = q->register_property ("cell_bbox", LQ_box); + cell_dbbox = q->register_property ("cell_dbbox", LQ_dbox); path_trans = q->register_property ("path_trans", LQ_trans); + path_dtrans = q->register_property ("path_dtrans", LQ_dtrans); } unsigned int path; // path -> Variant array with the indexes of the cells in that path @@ -1200,8 +1387,11 @@ struct CellFilterPropertyIDs unsigned int tot_weight; // tot_weight -> The number of instances of this cell in the initial cell along the given path unsigned int instances; // instances -> The number of instances of this cell in the previous cell (or over all if there is no previous cell) unsigned int bbox; // bbox -> Cell bounding box + unsigned int dbbox; // dbbox -> Cell bounding box in micrometer units unsigned int cell_bbox; // cell_bbox -> == bbox + unsigned int cell_dbbox; // cell_dbbox -> == dbbox unsigned int path_trans; // parent_trans -> transformation to initial cell + unsigned int path_dtrans; // parent_dtrans -> transformation to initial cell in micrometer units }; class DB_PUBLIC CellFilterState @@ -1283,6 +1473,15 @@ public: } return true; + } else if (id == m_pids.dbbox || id == m_pids.cell_dbbox) { + + if (! layout ()->is_valid_cell_index (*m_cell)) { + v = tl::Variant (); + } else { + v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * layout ()->cell (*m_cell).bbox ()); + } + return true; + } else if (id == m_pids.cell_name || id == m_pids.initial_cell_name) { if (! layout ()->is_valid_cell_index (*m_cell)) { @@ -1363,6 +1562,11 @@ public: v = tl::Variant::make_variant (db::ICplxTrans ()); return true; + } else if (id == m_pids.path_dtrans) { + + v = tl::Variant::make_variant (db::DCplxTrans ()); + return true; + } else { return FilterStateBase::get_property (id, v); } @@ -2225,7 +2429,7 @@ parse_cell_name_filter_element (tl::Extractor &ex, LayoutQuery *q, ChildCellFilt std::unique_ptr b (new FilterBracket (q)); do { parse_cell_name_filter_seq (ex, q, b.get (), instance_mode, reading); - } while (ex.test (",") || ex.test ("or")); + } while (ex.test (",") || ex.test (s_or)); // TODO: do this in the optimization if (b->children ().size () == 1 && dynamic_cast (b->children ()[0])) { @@ -2362,21 +2566,21 @@ parse_cell_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bo std::unique_ptr b (new FilterBracket (q)); - if (ex.test ("instances")) { - (ex.test ("of") || ex.test ("from")) && (ex.test ("cells") || ex.test ("cell")); + if (ex.test (s_instances)) { + (ex.test (s_of) || ex.test (s_from)) && (ex.test (s_cells) || ex.test (s_cell)); // Because an array member cannot be modified we use ArrayInstances in the modification case always parse_cell_name_filter_seq (ex, q, b.get (), reading ? ExplodedInstances : ArrayInstances, reading); - } else if (ex.test ("arrays")) { - (ex.test ("of") || ex.test ("from")) && (ex.test ("cells") || ex.test ("cell")); + } else if (ex.test (s_arrays)) { + (ex.test (s_of) || ex.test (s_from)) && (ex.test (s_cells) || ex.test (s_cell)); parse_cell_name_filter_seq (ex, q, b.get (), ArrayInstances, reading); } else { - ex.test ("cells") || ex.test ("cell"); + ex.test (s_cells) || ex.test (s_cell); parse_cell_name_filter_seq (ex, q, b.get (), NoInstances, reading); } FilterBase *fl = 0, *f = 0; - if (with_where_clause && ex.test ("where")) { + if (with_where_clause && ex.test (s_where)) { std::string expr = tl::Eval::parse_expr (ex, true); @@ -2407,22 +2611,22 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re { unsigned int sf = (unsigned int) db::ShapeIterator::Nothing; do { - if (ex.test ("shapes")) { + if (ex.test (s_shapes)) { sf |= (unsigned int) db::ShapeIterator::All; - } else if (ex.test ("polygons")) { + } else if (ex.test (s_polygons)) { sf |= (unsigned int) db::ShapeIterator::Polygons; - } else if (ex.test ("boxes")) { + } else if (ex.test (s_boxes)) { sf |= (unsigned int) db::ShapeIterator::Boxes; - } else if (ex.test ("edges")) { + } else if (ex.test (s_edges)) { sf |= (unsigned int) db::ShapeIterator::Edges; - } else if (ex.test ("paths")) { + } else if (ex.test (s_paths)) { sf |= (unsigned int) db::ShapeIterator::Paths; - } else if (ex.test ("texts")) { + } else if (ex.test (s_texts)) { sf |= (unsigned int) db::ShapeIterator::Texts; } else { break; } - } while (ex.test (",") || ex.test ("or")); + } while (ex.test (",") || ex.test (s_or)); db::ShapeIterator::flags_type shapes = (db::ShapeIterator::flags_type) sf; @@ -2430,12 +2634,12 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re db::LayerMap lm; - if (ex.test ("on")) { - ex.test ("layer") || ex.test ("layers"); + if (ex.test (s_on)) { + ex.test (s_layer) || ex.test (s_layers); lm.map_expr (ex, 0); } - ex.test ("of") || ex.test ("from"); + ex.test (s_of) || ex.test (s_from); std::unique_ptr b (new FilterBracket (q)); parse_cell_filter (ex, q, b.get (), false, reading); @@ -2451,7 +2655,7 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re bracket->add_child (f); fl->connect (f); - if (ex.test ("where")) { + if (ex.test (s_where)) { std::string expr = tl::Eval::parse_expr (ex, true); @@ -2472,7 +2676,7 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re void parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool reading) { - if (ex.test ("select")) { + if (ex.test (s_select)) { std::vector expressions; @@ -2480,7 +2684,7 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool expressions.push_back (tl::Eval::parse_expr (ex, true)); } while (ex.test (",")); - ex.expect ("from"); + ex.expect (s_from); std::unique_ptr b (new FilterBracket (q)); parse_filter (ex, q, b.get (), true); @@ -2488,10 +2692,10 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool bool unique = false; std::string sort_expression; - if (ex.test ("sorted")) { - ex.test ("by"); + if (ex.test (s_sorted)) { + ex.test (s_by); sort_expression = tl::Eval::parse_expr (ex, true); - unique = ex.test ("unique"); + unique = ex.test (s_unique); } FilterBase *f = b.release (); @@ -2504,16 +2708,16 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool bracket->connect_exit (ff); - } else if (! reading && ex.test ("with")) { + } else if (! reading && ex.test (s_with)) { std::unique_ptr b (new FilterBracket (q)); parse_filter (ex, q, b.get (), false); - ex.expect ("do"); + ex.expect (s_do); std::string expression = tl::Eval::parse_expr (ex, true); - bool transparent = ex.test ("pass"); + bool transparent = ex.test (s_pass); FilterBase *f = b.release (); bracket->add_child (f); @@ -2525,12 +2729,12 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool bracket->connect_exit (ff); - } else if (! reading && ex.test ("delete")) { + } else if (! reading && ex.test (s_delete)) { std::unique_ptr b (new FilterBracket (q)); parse_filter (ex, q, b.get (), false); - bool transparent = ex.test ("pass"); + bool transparent = ex.test (s_pass); FilterBase *f = b.release (); bracket->add_child (f); @@ -2554,7 +2758,10 @@ LayoutQuery::LayoutQuery (const std::string &query) tl::Extractor ex (query.c_str ()); parse_statement (ex, this, r.get (), false); - ex.expect_end (); + + if (! ex.at_end ()) { + ex.error (tl::to_string (tr ("Unexpected text"))); + } r->optimize (); mp_root = r.release (); diff --git a/src/db/db/dbLayoutQuery.h b/src/db/db/dbLayoutQuery.h index ac9a04d32..8fff4c492 100644 --- a/src/db/db/dbLayoutQuery.h +++ b/src/db/db/dbLayoutQuery.h @@ -51,11 +51,14 @@ enum LayoutQueryPropertyType LQ_variant, LQ_shape, LQ_trans, + LQ_dtrans, LQ_layer, LQ_instance, LQ_cell, LQ_point, + LQ_dpoint, LQ_box, + LQ_dbox, LQ_polygon, LQ_path, LQ_edge, diff --git a/src/db/db/dbRecursiveInstanceIterator.cc b/src/db/db/dbRecursiveInstanceIterator.cc index 257d49550..60577cf67 100644 --- a/src/db/db/dbRecursiveInstanceIterator.cc +++ b/src/db/db/dbRecursiveInstanceIterator.cc @@ -83,7 +83,6 @@ RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const Recursive RecursiveInstanceIterator::RecursiveInstanceIterator () { // anything. Not necessary reasonable. - mp_layout = 0; mp_top_cell = 0; mp_cell = 0; m_overlapping = false; @@ -97,7 +96,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator () RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type ®ion, bool overlapping) : m_box_convert (layout) { - mp_layout = &layout; + mp_layout = const_cast (&layout); mp_top_cell = &cell; m_overlapping = overlapping; init (); @@ -107,7 +106,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type ®ion, bool overlapping) : m_box_convert (layout) { - mp_layout = &layout; + mp_layout = const_cast (&layout); mp_top_cell = &cell; m_overlapping = overlapping; init (); @@ -117,7 +116,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell) : m_box_convert (layout) { - mp_layout = &layout; + mp_layout = const_cast (&layout); mp_top_cell = &cell; m_overlapping = false; init (); @@ -272,6 +271,7 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const m_inst_array_iterators.clear (); m_cells.clear (); m_trans = cplx_trans_type (); + m_target_tree.clear (); m_local_region_stack.clear (); m_local_region_stack.push_back (m_region); @@ -300,10 +300,9 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const } - if (mp_top_cell) { + if (mp_top_cell && mp_layout) { if (! m_all_targets) { - m_target_tree.clear (); mp_top_cell->collect_called_cells (m_target_tree); } @@ -501,6 +500,8 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c void RecursiveInstanceIterator::down (RecursiveInstanceReceiver *receiver) const { + tl_assert (mp_layout); + m_trans_stack.push_back (m_trans); m_cells.push_back (mp_cell); diff --git a/src/db/db/dbRecursiveInstanceIterator.h b/src/db/db/dbRecursiveInstanceIterator.h index 7f1f671b3..29fafcdda 100644 --- a/src/db/db/dbRecursiveInstanceIterator.h +++ b/src/db/db/dbRecursiveInstanceIterator.h @@ -29,6 +29,7 @@ #include "dbLayout.h" #include "dbInstElement.h" #include "tlAssert.h" +#include "tlObject.h" #include #include @@ -180,7 +181,7 @@ public: */ const layout_type *layout () const { - return mp_layout; + return mp_layout.get (); } /** @@ -544,7 +545,7 @@ private: std::set m_targets; bool m_all_targets; - const layout_type *mp_layout; + tl::weak_ptr mp_layout; const cell_type *mp_top_cell; box_type m_region; diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index 6b91ff9b2..ee23140ac 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -93,7 +93,6 @@ RecursiveShapeIterator::RecursiveShapeIterator () // anything. Not necessary reasonable. m_layer = 0; m_has_layers = false; - mp_layout = 0; mp_shapes = 0; mp_top_cell = 0; mp_cell = 0; @@ -113,7 +112,6 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes) { m_layer = 0; m_has_layers = false; - mp_layout = 0; mp_shapes = &shapes; mp_top_cell = 0; m_overlapping = false; @@ -125,7 +123,6 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const { m_layer = 0; m_has_layers = false; - mp_layout = 0; mp_shapes = &shapes; mp_top_cell = 0; m_overlapping = overlapping; @@ -137,7 +134,6 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const { m_layer = 0; m_has_layers = false; - mp_layout = 0; mp_shapes = &shapes; mp_top_cell = 0; m_overlapping = overlapping; @@ -150,7 +146,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const { m_layer = layer; m_has_layers = false; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; @@ -163,7 +159,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const { m_layer = layer; m_has_layers = false; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; @@ -176,7 +172,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const { m_layer = layer; m_has_layers = false; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = false; @@ -190,7 +186,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const m_layer = 0; m_layers = layers; m_has_layers = true; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; @@ -204,7 +200,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const m_layer = 0; m_layers = layers; m_has_layers = true; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; @@ -218,7 +214,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const m_layer = 0; m_layers = layers; m_has_layers = true; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = false; @@ -232,7 +228,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const m_layer = 0; m_layers.insert (m_layers.end (), layers.begin (), layers.end ()); m_has_layers = true; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; @@ -246,7 +242,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const m_layer = 0; m_layers.insert (m_layers.end (), layers.begin (), layers.end ()); m_has_layers = true; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = overlapping; @@ -260,7 +256,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const m_layer = 0; m_layers.insert (m_layers.end (), layers.begin (), layers.end ()); m_has_layers = true; - mp_layout = &layout; + mp_layout.reset (const_cast (&layout)); mp_shapes = 0; mp_top_cell = &cell; m_overlapping = false; @@ -691,6 +687,8 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const if (! m_inst.at_end () && int (m_inst_iterators.size ()) < m_max_depth) { + tl_assert (mp_layout); + // determine whether the cell is empty with respect to the layers specified bool is_empty = false; if (! m_has_layers) { @@ -754,6 +752,8 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const void RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const { + tl_assert (mp_layout); + m_trans_stack.push_back (m_trans); m_cells.push_back (mp_cell); diff --git a/src/db/db/dbRecursiveShapeIterator.h b/src/db/db/dbRecursiveShapeIterator.h index 2370f65a7..330563c20 100644 --- a/src/db/db/dbRecursiveShapeIterator.h +++ b/src/db/db/dbRecursiveShapeIterator.h @@ -29,6 +29,7 @@ #include "dbLayout.h" #include "dbInstElement.h" #include "tlAssert.h" +#include "tlObject.h" #include #include @@ -306,7 +307,7 @@ public: */ const layout_type *layout () const { - return mp_layout; + return mp_layout.get (); } /** @@ -765,7 +766,7 @@ private: std::set m_start, m_stop; cplx_trans_type m_global_trans; - const layout_type *mp_layout; + tl::weak_ptr mp_layout; const cell_type *mp_top_cell; const shapes_type *mp_shapes; diff --git a/src/db/db/gsiDeclDbBox.cc b/src/db/db/gsiDeclDbBox.cc index 14c5c7d42..42a6789a2 100644 --- a/src/db/db/gsiDeclDbBox.cc +++ b/src/db/db/gsiDeclDbBox.cc @@ -49,6 +49,11 @@ struct box_defs return c.release (); } + static C world () + { + return C::world (); + } + static C *new_v () { return new C (); @@ -132,6 +137,22 @@ struct box_defs "are not provided in the correct order (i.e. right < left), these are " "swapped." ) + + method ("world", &world, + "@brief Gets the 'world' box\n" + "The world box is the biggest box that can be represented. So it is basically 'all'. The " + "world box behaves neutral on intersections for example. In other operations such as displacement or transformations, " + "the world box may render unexpected results because of coordinate overflow.\n" + "\n" + "The world box can be used\n" + "@ul\n" + " @li for comparison ('==', '!=', '<') @/li\n" + " @li in union and intersection ('+' and '&') @/li\n" + " @li in relations (\\contains?, \\overlaps?, \\touches?) @/li\n" + " @li as 'all' argument in region queries @/li\n" + "@/ul\n" + "\n" + "This method has been introduced in version 0.28." + ) + method ("p1", &C::p1, "@brief Gets the lower left point of the box\n" ) + diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index cc6edee03..bd5bf1491 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -68,6 +68,12 @@ struct cell_inst_array_defs return new C (); } + static C * + new_cell_inst_vector (db::cell_index_type ci, const vector_type &v) + { + return new C (db::CellInst (ci), trans_type (v)); + } + static C * new_cell_inst (db::cell_index_type ci, const trans_type &t) { @@ -84,6 +90,13 @@ struct cell_inst_array_defs } } + static C * + new_cell_inst_array_vector (db::cell_index_type ci, const vector_type &v, + const vector_type &a, const vector_type &b, unsigned int na, unsigned int nb) + { + return new C (db::CellInst (ci), trans_type (v), a, b, na, nb); + } + static C * new_cell_inst_array (db::cell_index_type ci, const trans_type &t, const vector_type &a, const vector_type &b, unsigned int na, unsigned int nb) @@ -397,6 +410,12 @@ struct cell_inst_array_defs "@param cell_index The cell to instantiate\n" "@param trans The transformation by which to instantiate the cell\n" ) + + gsi::constructor ("new", &new_cell_inst_vector, gsi::arg ("cell_index"), gsi::arg ("disp"), + "@brief Creates a single cell instance\n" + "@param cell_index The cell to instantiate\n" + "@param disp The displacement\n" + "This convenience initializer has been introduced in version 0.28." + ) + gsi::constructor ("new", &new_cell_inst_cplx, gsi::arg ("cell_index"), gsi::arg ("trans"), "@brief Creates a single cell instance with a complex transformation\n" "@param cell_index The cell to instantiate\n" @@ -415,6 +434,17 @@ struct cell_inst_array_defs "Starting with version 0.25 the displacements are of vector type." ) ) + + gsi::constructor ("new", &new_cell_inst_array_vector, gsi::arg ("cell_index"), gsi::arg ("disp"), gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("na"), gsi::arg ("nb"), + "@brief Creates a single cell instance\n" + "@param cell_index The cell to instantiate\n" + "@param disp The basic displacement of the first instance\n" + "@param a The displacement vector of the array in the 'a' axis\n" + "@param b The displacement vector of the array in the 'b' axis\n" + "@param na The number of placements in the 'a' axis\n" + "@param nb The number of placements in the 'b' axis\n" + "\n" + "This convenience initializer has been introduced in version 0.28." + ) + gsi::constructor ("new", &new_cell_inst_array_cplx, gsi::arg ("cell_index"), gsi::arg ("trans"), gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("na"), gsi::arg ("nb"), "@brief Creates a single cell instance with a complex transformation\n" "@param cell_index The cell to instantiate\n" diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index f63f97e9c..e2e48e1eb 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -353,6 +353,33 @@ static db::cell_index_type clip (db::Layout *l, db::cell_index_type c, const db: return cc [0]; } +static db::cell_index_type clip_dbox (db::Layout *l, db::cell_index_type c, const db::DBox &box) +{ + std::vector boxes; + boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box); + std::vector cc = db::clip_layout(*l, *l, c, boxes, true); + tl_assert (! cc.empty ()); + return cc [0]; +} + +static db::Cell *clip_cell_dbox (db::Layout *l, const db::Cell &c, const db::DBox &box) +{ + std::vector boxes; + boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box); + std::vector cc = db::clip_layout(*l, *l, c.cell_index (), boxes, true); + tl_assert (! cc.empty ()); + return &l->cell (cc [0]); +} + +static db::Cell *clip_cell (db::Layout *l, const db::Cell &c, const db::Box &box) +{ + std::vector boxes; + boxes.push_back (box); + std::vector cc = db::clip_layout(*l, *l, c.cell_index (), boxes, true); + tl_assert (! cc.empty ()); + return &l->cell (cc [0]); +} + static db::cell_index_type clip_into (const db::Layout *l, db::cell_index_type c, db::Layout *t, const db::Box &box) { std::vector boxes; @@ -362,14 +389,92 @@ static db::cell_index_type clip_into (const db::Layout *l, db::cell_index_type c return cc [0]; } +static db::cell_index_type clip_into_dbox (const db::Layout *l, db::cell_index_type c, db::Layout *t, const db::DBox &box) +{ + std::vector boxes; + boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box); + std::vector cc = db::clip_layout(*l, *t, c, boxes, true); + tl_assert (! cc.empty ()); + return cc [0]; +} + +static db::Cell *clip_into_cell (const db::Layout *l, const db::Cell &c, db::Layout *t, const db::Box &box) +{ + std::vector boxes; + boxes.push_back (box); + std::vector cc = db::clip_layout(*l, *t, c.cell_index (), boxes, true); + tl_assert (! cc.empty ()); + return &t->cell (cc [0]); +} + +static db::Cell *clip_into_cell_dbox (const db::Layout *l, const db::Cell &c, db::Layout *t, const db::DBox &box) +{ + std::vector boxes; + boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box); + std::vector cc = db::clip_layout(*l, *t, c.cell_index (), boxes, true); + tl_assert (! cc.empty ()); + return &t->cell (cc [0]); +} + +static std::vector transform_boxes (const db::Layout *l, const std::vector &boxes) +{ + std::vector result; + result.reserve (boxes.size ()); + db::VCplxTrans t = db::CplxTrans (l->dbu ()).inverted (); + for (std::vector::const_iterator i = boxes.begin (); i != boxes.end (); ++i) { + result.push_back (t * *i); + } + return result; +} + +static std::vector to_cell_refs (db::Layout *l, const std::vector &cell_indexes) +{ + std::vector result; + result.reserve (cell_indexes.size ()); + for (std::vector::const_iterator i = cell_indexes.begin (); i != cell_indexes.end (); ++i) { + result.push_back (&l->cell (*i)); + } + return result; +} + static std::vector multi_clip (db::Layout *l, db::cell_index_type c, const std::vector &boxes) { - return db::clip_layout(*l, *l, c, boxes, true); + return db::clip_layout (*l, *l, c, boxes, true); +} + +static std::vector multi_clip_cells (db::Layout *l, const db::Cell &c, const std::vector &boxes) +{ + return to_cell_refs (l, db::clip_layout (*l, *l, c.cell_index (), boxes, true)); +} + +static std::vector multi_clip_dboxes (db::Layout *l, db::cell_index_type c, const std::vector &boxes) +{ + return db::clip_layout (*l, *l, c, transform_boxes (l, boxes), true); +} + +static std::vector multi_clip_cells_dboxes (db::Layout *l, const db::Cell &c, const std::vector &boxes) +{ + return to_cell_refs (l, db::clip_layout (*l, *l, c.cell_index (), transform_boxes (l, boxes), true)); } static std::vector multi_clip_into (db::Layout *l, db::cell_index_type c, db::Layout *t, const std::vector &boxes) { - return db::clip_layout(*l, *t, c, boxes, true); + return db::clip_layout (*l, *t, c, boxes, true); +} + +static std::vector multi_clip_into_cells (db::Layout *l, const db::Cell &c, db::Layout *t, const std::vector &boxes) +{ + return to_cell_refs (l, db::clip_layout (*l, *t, c.cell_index (), boxes, true)); +} + +static std::vector multi_clip_into_dboxes (db::Layout *l, db::cell_index_type c, db::Layout *t, const std::vector &boxes) +{ + return db::clip_layout (*l, *t, c, transform_boxes (l, boxes), true); +} + +static std::vector multi_clip_into_cells_dboxes (db::Layout *l, const db::Cell &c, db::Layout *t, const std::vector &boxes) +{ + return to_cell_refs (l, db::clip_layout (*l, *t, c.cell_index (), transform_boxes (l, boxes), true)); } static unsigned int get_layer0 (db::Layout *l) @@ -1104,7 +1209,18 @@ Class decl_Layout ("db", "Layout", "@param properties_id The properties ID to get the properties for\n" "@return The array of variants (see \\properties_id)\n" ) + - gsi::method_ext ("top_cell", &top_cell, + gsi::method ("unique_cell_name", &db::Layout::uniquify_cell_name, gsi::arg ("name"), + "@brief Creates a new unique cell name from the given name\n" + "@return A unique name derived from the argument\n" + "\n" + "If a cell with the given name exists, a suffix will be added to make the name unique. " + "Otherwise, the argument will be returned unchanged.\n" + "\n" + "The returned name can be used to rename cells without risk of creating name clashes.\n" + "\n" + "This method has been introduced in version 0.28." + ) + + gsi::method_ext ("top_cell", &top_cell, "@brief Returns the top cell object\n" "@return The \\Cell object of the top cell\n" "If the layout has a single top cell, this method returns the top cell's \\Cell object.\n" @@ -1146,14 +1262,21 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduce in version 0.23 and replaces \\add_cell.\n" ) + - gsi::method_ext ("create_cell", &create_cell2, gsi::arg ("name"), gsi::arg ("params"), - "@brief Creates a cell as a PCell variant with the given name\n" - "@param name The name of the PCell and the name of the cell to create\n" + gsi::method_ext ("create_cell", &create_cell2, gsi::arg ("pcell_name"), gsi::arg ("params"), + "@brief Creates a cell as a PCell variant for the PCell with the given name\n" + "@param pcell_name The name of the PCell and also the name of the cell to create\n" "@param params The PCell parameters (key/value dictionary)\n" - "@return The \\Cell object of the newly created cell.\n" + "@return The \\Cell object of the newly created cell or an existing cell if the PCell has already been used with these parameters.\n" "\n" - "This method will look up the PCell by the given name and create a new PCell variant " - "with the given parameters. The parameters are specified as a key/value dictionary with " + "PCells are instantiated by creating a PCell variant. A PCell variant is linked to the PCell and represents " + "this PCell with a particular parameter set.\n" + "\n" + "This method will look up the PCell by the PCell name and create a new PCell variant " + "for the given parameters. If the PCell has already been instantiated with the same parameters, the " + "original variant will be returned. Hence this method is not strictly creating a cell - only if the required variant has " + "not been created yet.\n" + "\n" + "The parameters are specified as a key/value dictionary with " "the names being the ones from the PCell declaration.\n" "\n" "If no PCell with the given name exists, nil is returned.\n" @@ -1164,25 +1287,34 @@ Class decl_Layout ("db", "Layout", "@brief Creates a cell with the given name\n" "@param name The name of the library cell and the name of the cell to create\n" "@param lib_name The name of the library where to take the cell from\n" - "@return The \\Cell object of the newly created cell.\n" + "@return The \\Cell object of the newly created cell or an existing cell if the library cell has already been used in this layout.\n" + "\n" + "Library cells are imported by creating a 'library proxy'. This is a cell which represents " + "the library cell in the framework of the current layout. The library proxy is linked to the " + "library and will be updated if the library cell is changed.\n" + "\n" + "This method will look up the cell by the given name in the specified library and create a new library proxy for this cell.\n" + "If the same library cell has already been used, the original library proxy is returned. Hence, strictly speaking this " + "method does not always create a new cell but may return a reference to an existing cell.\n" "\n" - "This method will look up the cell by the given name in the specified library and create a new library proxy to this cell.\n" "If the library name is not valid, nil is returned.\n" "\n" "This method has been introduce in version 0.24.\n" ) + - gsi::method_ext ("create_cell", &create_cell4, gsi::arg ("name"), gsi::arg ("lib_name"), gsi::arg ("params"), - "@brief Creates a cell with the given name\n" - "@param name The name of the PCell and the name of the cell to create\n" + gsi::method_ext ("create_cell", &create_cell4, gsi::arg ("pcell_name"), gsi::arg ("lib_name"), gsi::arg ("params"), + "@brief Creates a cell for a PCell with the given PCell name from the given library\n" + "@param pcell_name The name of the PCell and also the name of the cell to create\n" "@param lib_name The name of the library where to take the PCell from\n" "@param params The PCell parameters (key/value dictionary)\n" - "@return The \\Cell object of the newly created cell.\n" + "@return The \\Cell object of the newly created cell or an existing cell if this PCell has already been used with the given parameters\n" "\n" - "This method will look up the PCell by the given name in the specified library and create a new PCell variant " - "with the given parameters. The parameters are specified as a key/value dictionary with " + "This method will look up the PCell by the PCell name in the specified library and create a new PCell variant " + "for the given parameters plus the library proxy. The parameters must be specified as a key/value dictionary with " "the names being the ones from the PCell declaration.\n" "\n" - "If no PCell with the given name exists or the library name is not valid, nil is returned.\n" + "If no PCell with the given name exists or the library name is not valid, nil is returned. Note that " + "this function - despite the name - may not always create a new cell, but return an existing cell if the " + "PCell from the library has already been used with the given parameters.\n" "\n" "This method has been introduce in version 0.24.\n" ) + @@ -1194,7 +1326,10 @@ Class decl_Layout ("db", "Layout", "is returns a \\Cell object (\\create_cell).\n" ) + gsi::method ("rename_cell", &db::Layout::rename_cell, gsi::arg ("index"), gsi::arg ("name"), - "@brief name\n" + "@brief Renames the cell with given index\n" + "The cell with the given index is renamed to the given name. NOTE: it is not ensured that the name is unique. " + "This method allows assigning identical names to different cells which usually breaks things.\n" + "Consider using \\unique_cell_name to generate truely unique names.\n" ) + gsi::method ("delete_cell", &db::Layout::delete_cell, gsi::arg ("cell_index"), "@brief Deletes a cell \n" @@ -1916,6 +2051,30 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been added in version 0.21.\n" ) + + gsi::method_ext ("clip", &clip_dbox, gsi::arg ("cell"), gsi::arg ("box"), + "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" + "@param cell The cell index of the cell to clip\n" + "@param box The clip box in micrometer units\n" + "@return The index of the new cell\n" + "\n" + "This variant which takes a micrometer-unit box has been added in version 0.28." + ) + + gsi::method_ext ("clip", &clip_cell, gsi::arg ("cell"), gsi::arg ("box"), + "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" + "@param cell The cell reference of the cell to clip\n" + "@param box The clip box in database units\n" + "@return The reference to the new cell\n" + "\n" + "This variant which takes cell references instead of cell indexes has been added in version 0.28." + ) + + gsi::method_ext ("clip", &clip_cell_dbox, gsi::arg ("cell"), gsi::arg ("box"), + "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" + "@param cell The cell reference of the cell to clip\n" + "@param box The clip box in micrometer units\n" + "@return The reference to the new cell\n" + "\n" + "This variant which takes a micrometer-unit box and cell references has been added in version 0.28." + ) + gsi::method_ext ("clip_into", &clip_into, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"), "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" "@param cell The cell index of the cell to clip\n" @@ -1935,8 +2094,35 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been added in version 0.21.\n" ) + + gsi::method_ext ("clip_into", &clip_into_dbox, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"), + "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" + "@param cell The cell index of the cell to clip\n" + "@param box The clip box in micrometer units\n" + "@param target The target layout\n" + "@return The index of the new cell in the target layout\n" + "\n" + "This variant which takes a micrometer-unit box has been added in version 0.28." + ) + + gsi::method_ext ("clip_into", &clip_into_cell, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"), + "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" + "@param cell The reference to the cell to clip\n" + "@param box The clip box in database units\n" + "@param target The target layout\n" + "@return The reference to the new cell in the target layout\n" + "\n" + "This variant which takes cell references instead of cell indexes has been added in version 0.28." + ) + + gsi::method_ext ("clip_into", &clip_into_cell_dbox, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"), + "@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n" + "@param cell The reference to the cell to clip\n" + "@param box The clip box in micrometer units\n" + "@param target The target layout\n" + "@return The reference to the new cell in the target layout\n" + "\n" + "This variant which takes a micrometer-unit box and cell references has been added in version 0.28." + ) + gsi::method_ext ("multi_clip", &multi_clip, gsi::arg ("cell"), gsi::arg ("boxes"), - "@brief Clips the given cell by the given rectangles and produce new cells with the clips, one for each rectangle.\n" + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" "@param cell The cell index of the cell to clip\n" "@param boxes The clip boxes in database units\n" "@return The indexes of the new cells\n" @@ -1949,8 +2135,32 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been added in version 0.21.\n" ) + + gsi::method_ext ("multi_clip", &multi_clip_dboxes, gsi::arg ("cell"), gsi::arg ("boxes"), + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" + "@param cell The cell index of the cell to clip\n" + "@param boxes The clip boxes in micrometer units\n" + "@return The indexes of the new cells\n" + "\n" + "This variant which takes micrometer-unit boxes has been added in version 0.28." + ) + + gsi::method_ext ("multi_clip", &multi_clip_cells, gsi::arg ("cell"), gsi::arg ("boxes"), + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" + "@param cell The reference to the cell to clip\n" + "@param boxes The clip boxes in database units\n" + "@return The references to the new cells\n" + "\n" + "This variant which takes cell references has been added in version 0.28." + ) + + gsi::method_ext ("multi_clip", &multi_clip_cells_dboxes, gsi::arg ("cell"), gsi::arg ("boxes"), + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" + "@param cell The reference to the cell to clip\n" + "@param boxes The clip boxes in micrometer units\n" + "@return The references to the new cells\n" + "\n" + "This variant which takes cell references and micrometer-unit boxes has been added in version 0.28." + ) + gsi::method_ext ("multi_clip_into", &multi_clip_into, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"), - "@brief Clips the given cell by the given rectangles and produce new cells with the clips, one for each rectangle.\n" + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" "@param cell The cell index of the cell to clip\n" "@param boxes The clip boxes in database units\n" "@param target The target layout\n" @@ -1969,6 +2179,33 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been added in version 0.21.\n" ) + + gsi::method_ext ("multi_clip_into", &multi_clip_into_dboxes, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"), + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" + "@param cell The cell index of the cell to clip\n" + "@param boxes The clip boxes in database units\n" + "@param target The target layout\n" + "@return The indexes of the new cells\n" + "\n" + "This variant which takes micrometer-unit boxes has been added in version 0.28." + ) + + gsi::method_ext ("multi_clip_into", &multi_clip_into_cells, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"), + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" + "@param cell The reference the cell to clip\n" + "@param boxes The clip boxes in database units\n" + "@param target The target layout\n" + "@return The references to the new cells\n" + "\n" + "This variant which takes cell references boxes has been added in version 0.28." + ) + + gsi::method_ext ("multi_clip_into", &multi_clip_into_cells_dboxes, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"), + "@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n" + "@param cell The reference the cell to clip\n" + "@param boxes The clip boxes in micrometer units\n" + "@param target The target layout\n" + "@return The references to the new cells\n" + "\n" + "This variant which takes cell references and micrometer-unit boxes has been added in version 0.28." + ) + gsi::method ("convert_cell_to_static", &db::Layout::convert_cell_to_static, gsi::arg ("cell_index"), "@brief Converts a PCell or library cell to a usual (static) cell\n" "@return The index of the new cell\n" diff --git a/src/db/db/gsiDeclDbLayoutQuery.cc b/src/db/db/gsiDeclDbLayoutQuery.cc index f1a05b0d8..e10beb554 100644 --- a/src/db/db/gsiDeclDbLayoutQuery.cc +++ b/src/db/db/gsiDeclDbLayoutQuery.cc @@ -111,7 +111,9 @@ char shape_query_property_name[] = "shape"; char layer_index_query_property_name[] = "layer_index"; char inst_query_property_name[] = "inst"; char path_trans_query_property_name[] = "path_trans"; +char path_dtrans_query_property_name[] = "path_dtrans"; char trans_query_property_name[] = "trans"; +char dtrans_query_property_name[] = "dtrans"; char cell_index_query_property_name[] = "cell_index"; char cell_query_property_name[] = "cell"; char parent_cell_index_query_property_name[] = "parent_cell_index"; @@ -138,7 +140,9 @@ Class decl_LayoutQueryIterator ("db", "LayoutQueryItera make_shortcut_method() + make_shortcut_method() + make_shortcut_method() + + make_shortcut_method() + make_shortcut_method() + + make_shortcut_method() + make_shortcut_method() + make_shortcut_method() + make_shortcut_method() + diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index b1573b595..4f84f11cf 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -965,9 +965,9 @@ struct polygon_defs poly->size (d, d, mode); } - static void size_d (C *poly, coord_type d) + static void size_dvm (C *poly, const db::Vector &dv, unsigned int mode) { - poly->size (d, d, 2); + poly->size (dv.x (), dv.y (), mode); } static C sized_xy (const C *poly, coord_type dx, coord_type dy, unsigned int mode) @@ -980,9 +980,9 @@ struct polygon_defs return poly->sized (d, d, mode); } - static C sized_d (const C *poly, coord_type d) + static C sized_dvm (const C *poly, const db::Vector &dv, unsigned int mode) { - return poly->sized (d, d, 2); + return poly->sized (dv.x (), dv.y (), mode); } static bool inside (const C *poly, point_type pt) @@ -1272,7 +1272,19 @@ struct polygon_defs "result = ep.simple_merge_p2p([ poly ], false, false, 1)\n" "@/code\n" ) + - method_ext ("size", &size_dm, gsi::arg ("d"), gsi::arg ("mode"), + method_ext ("size", &size_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2), + "@brief Sizes the polygon (biasing)\n" + "\n" + "This method is equivalent to\n" + "@code\n" + "size(dv.x, dv.y, mode)\n" + "@/code\n" + "\n" + "See \\size for a detailed description.\n" + "\n" + "This version has been introduced in version 0.28.\n" + ) + + method_ext ("size", &size_dm, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2), "@brief Sizes the polygon (biasing)\n" "\n" "Shifts the contour outwards (d>0) or inwards (d<0).\n" @@ -1294,7 +1306,19 @@ struct polygon_defs "\n" "This method has been introduced in version 0.23.\n" ) + - method_ext ("sized", &sized_dm, gsi::arg ("d"), gsi::arg ("mode"), + method_ext ("sized", &sized_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2), + "@brief Sizes the polygon (biasing) without modifying self\n" + "\n" + "This method is equivalent to\n" + "@code\n" + "sized(dv.x, dv.y, mode)\n" + "@/code\n" + "\n" + "See \\size and \\sized for a detailed description.\n" + "\n" + "This version has been introduced in version 0.28.\n" + ) + + method_ext ("sized", &sized_dm, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2), "@brief Sizes the polygon (biasing) without modifying self\n" "\n" "Shifts the contour outwards (d>0) or inwards (d<0).\n" @@ -1305,28 +1329,6 @@ struct polygon_defs "\n" "See \\size and \\sized for a detailed description.\n" ) + - method_ext ("sized", &sized_d, gsi::arg ("d"), - "@brief Sizes the polygon (biasing)\n" - "\n" - "@brief Sizing (biasing) without modifying self\n" - "This method is equivalent to\n" - "@code\n" - "sized(d, d, 2)\n" - "@/code\n" - "\n" - "See \\size and \\sized for a detailed description.\n" - ) + - method_ext ("size", &size_d, gsi::arg ("d"), - "@brief Sizes the polygon (biasing)\n" - "\n" - "Shifts the contour outwards (d>0) or inwards (d<0).\n" - "This method is equivalent to\n" - "@code\n" - "size(d, d, 2)\n" - "@/code\n" - "\n" - "See \\size for a detailed description.\n" - ) + method ("holes", &C::holes, "@brief Returns the number of holes" ) + diff --git a/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc b/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc index e2d9f93eb..dcce3a0dd 100644 --- a/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc @@ -30,6 +30,31 @@ namespace gsi { +namespace { + +/** + * @brief A wrapper that allows using "each" on the iterator + */ +class IteratorIterator +{ +public: + typedef db::RecursiveInstanceIterator value_type; + typedef db::RecursiveInstanceIterator &reference; + typedef db::RecursiveInstanceIterator *pointer; + typedef std::forward_iterator_tag iterator_category; + typedef void difference_type; + + IteratorIterator (db::RecursiveInstanceIterator *iter) : mp_iter (iter) { } + bool at_end () const { return mp_iter->at_end (); } + reference operator* () const { return *mp_iter; } + void operator++ () { ++*mp_iter; } + +private: + db::RecursiveInstanceIterator *mp_iter; +}; + +} + // --------------------------------------------------------------- // db::RecursiveInstanceIterator binding @@ -48,6 +73,11 @@ static db::RecursiveInstanceIterator *new_si2a (const db::Layout &layout, const return new db::RecursiveInstanceIterator (layout, cell, region, overlapping); } +static IteratorIterator each (db::RecursiveInstanceIterator *r) +{ + return IteratorIterator (r); +} + static db::DCplxTrans si_dtrans (const db::RecursiveInstanceIterator *r) { const db::Layout *ly = r->layout (); @@ -184,6 +214,21 @@ Class decl_RecursiveInstanceIterator ("db", "Recu "bounding box touches the search region are reported. The bounding box of instances is measured taking all layers " "of the target cell into account.\n" ) + + gsi::iterator_ext ("each", &each, + "@brief Native iteration\n" + "This method enables native iteration, e.g.\n" + "\n" + "@code\n" + " iter = ... # RecursiveInstanceIterator\n" + " iter.each do |i|\n" + " ... i is the iterator itself\n" + " end\n" + "@/code\n" + "\n" + "This is slightly more convenient than the 'at_end' .. 'next' loop.\n" + "\n" + "This feature has been introduced in version 0.28.\n" + ) + gsi::method ("max_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::max_depth, gsi::arg ("depth"), "@brief Specifies the maximum hierarchy depth to look into\n" "\n" @@ -466,6 +511,11 @@ Class decl_RecursiveInstanceIterator ("db", "Recu " puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n" " iter.next\n" "end\n" + "\n" + "# or shorter:\n" + "cell.begin_instances_rec.each do |iter|\n" + " puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n" + "end\n" "@/code\n" "\n" "Here, a target cell is specified which confines the search to instances of this particular cell.\n" diff --git a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc index 34e5a6650..c70423544 100644 --- a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc @@ -1,4 +1,4 @@ - +# /* KLayout Layout Viewer @@ -27,12 +27,39 @@ #include "tlGlobPattern.h" +#include + namespace gsi { // --------------------------------------------------------------- // db::RecursiveShapeIterator binding +namespace { + +/** + * @brief A wrapper that allows using "each" on the iterator + */ +class IteratorIterator +{ +public: + typedef db::RecursiveShapeIterator value_type; + typedef db::RecursiveShapeIterator &reference; + typedef db::RecursiveShapeIterator *pointer; + typedef std::forward_iterator_tag iterator_category; + typedef void difference_type; + + IteratorIterator (db::RecursiveShapeIterator *iter) : mp_iter (iter) { } + bool at_end () const { return mp_iter->at_end (); } + reference operator* () const { return *mp_iter; } + void operator++ () { ++*mp_iter; } + +private: + db::RecursiveShapeIterator *mp_iter; +}; + +} + static db::RecursiveShapeIterator *new_si1 (const db::Layout &layout, const db::Cell &cell, unsigned int layer) { return new db::RecursiveShapeIterator (layout, cell, layer); @@ -63,6 +90,11 @@ static db::RecursiveShapeIterator *new_si4a (const db::Layout &layout, const db: return new db::RecursiveShapeIterator (layout, cell, layers, region, overlapping); } +static IteratorIterator each (db::RecursiveShapeIterator *r) +{ + return IteratorIterator (r); +} + static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r) { const db::Layout *ly = r->layout (); @@ -236,6 +268,21 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS "\n" "This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n" ) + + gsi::iterator_ext ("each", &each, + "@brief Native iteration\n" + "This method enables native iteration, e.g.\n" + "\n" + "@code\n" + " iter = ... # RecursiveShapeIterator\n" + " iter.each do |i|\n" + " ... i is the iterator itself\n" + " end\n" + "@/code\n" + "\n" + "This is slightly more convenient than the 'at_end' .. 'next' loop.\n" + "\n" + "This feature has been introduced in version 0.28.\n" + ) + gsi::method ("max_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::max_depth, gsi::arg ("depth"), "@brief Specifies the maximum hierarchy depth to look into\n" "\n" @@ -560,6 +607,14 @@ Class decl_RecursiveShapeIterator ("db", "RecursiveS " end\n" " iter.next\n" "end\n" + "\n" + "# or shorter:\n" + "cell.begin_shapes_rec(layer).each do |iter|\n" + " if iter.shape.renders_polygon?\n" + " polygon = iter.shape.polygon.transformed(iter.itrans)\n" + " puts \"In cell #{iter.cell.name}: \" + polygon.to_s\n" + " end\n" + "end\n" "@/code\n" "\n" "\\Cell offers three methods to get these iterators: begin_shapes_rec, begin_shapes_rec_touching and begin_shapes_rec_overlapping.\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 2c78f30f4..0cc777b8b 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -471,17 +471,6 @@ static void break_polygons (db::Region *r, size_t max_vertex_count, double max_a r->process (db::PolygonBreaker (max_vertex_count, max_area_ratio)); } -static db::Region &size_ext (db::Region *r, db::Coord d) -{ - r->size (d); - return *r; -} - -static db::Region sized_ext (db::Region *r, db::Coord d) -{ - return r->sized (d); -} - static db::Region &merge_ext1 (db::Region *r, int min_wc) { r->merge (false, std::max (0, min_wc - 1)); @@ -740,6 +729,19 @@ fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fil db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box); } +static db::Region +sized_dvm (const db::Region *region, const db::Vector &dv, unsigned int mode) +{ + return region->sized (dv.x (), dv.y (), mode); +} + +static db::Region & +size_dvm (db::Region *region, const db::Vector &dv, unsigned int mode) +{ + region->size (dv.x (), dv.y (), mode); + return *region; +} + static db::Point default_origin; // provided by gsiDeclDbPolygon.cc: @@ -1537,7 +1539,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "# r now is (50,-50;50,100;100,100;100,-50)\n" "@/code\n" ) + - method ("size", (db::Region & (db::Region::*) (db::Coord, unsigned int)) &db::Region::size, gsi::arg ("d"), gsi::arg ("mode"), + method_ext ("size", &size_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2), + "@brief Anisotropic sizing (biasing)\n" + "\n" + "@return The region after the sizing has applied (self)\n" + "\n" + "This method is equivalent to \"size(dv.x, dv.y, mode)\".\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" + "\n" + "This variant has been introduced in version 0.28." + ) + + method ("size", (db::Region & (db::Region::*) (db::Coord, unsigned int)) &db::Region::size, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2), "@brief Isotropic sizing (biasing)\n" "\n" "@return The region after the sizing has applied (self)\n" @@ -1546,39 +1559,34 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + - method_ext ("size", size_ext, gsi::arg ("d"), - "@brief Isotropic sizing (biasing)\n" - "\n" - "@return The region after the sizing has applied (self)\n" - "\n" - "This method is equivalent to \"size(d, d, 2)\".\n" - "\n" - "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" - ) + method ("sized", (db::Region (db::Region::*) (db::Coord, db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"), "@brief Returns the anisotropically sized region\n" "\n" "@return The sized region\n" "\n" - "This method is returns the sized region (see \\size), but does not modify self.\n" + "This method returns the sized region (see \\size), but does not modify self.\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + - method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode"), + method_ext ("sized", &sized_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2), + "@brief Returns the (an)isotropically sized region\n" + "\n" + "@return The sized region\n" + "\n" + "This method is equivalent to \"sized(dv.x, dv.y, mode)\".\n" + "This method returns the sized region (see \\size), but does not modify self.\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" + "\n" + "This variant has been introduced in version 0.28." + ) + + method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2), "@brief Returns the isotropically sized region\n" "\n" "@return The sized region\n" "\n" - "This method is returns the sized region (see \\size), but does not modify self.\n" - "\n" - "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" - ) + - method_ext ("sized", sized_ext, gsi::arg ("d"), - "@brief Isotropic sizing (biasing)\n" - "\n" - "@return The region after the sizing has applied (self)\n" - "\n" - "This method is equivalent to \"sized(d, d, 2)\".\n" + "This method is equivalent to \"sized(d, d, mode)\".\n" + "This method returns the sized region (see \\size), but does not modify self.\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + diff --git a/src/db/db/gsiDeclDbText.cc b/src/db/db/gsiDeclDbText.cc index 9b6cbe08f..4bf0e354b 100644 --- a/src/db/db/gsiDeclDbText.cc +++ b/src/db/db/gsiDeclDbText.cc @@ -22,6 +22,7 @@ #include "gsiDecl.h" +#include "gsiEnums.h" #include "dbPoint.h" #include "dbText.h" #include "dbHash.h" @@ -36,6 +37,7 @@ template struct text_defs { typedef typename C::coord_type coord_type; + typedef typename C::box_type box_type; typedef typename C::point_type point_type; typedef typename C::vector_type vector_type; typedef db::simple_trans simple_trans_type; @@ -101,22 +103,43 @@ struct text_defs return t->font (); } - static void set_halign (C *t, int f) + static point_type get_pos (C *t) + { + return t->trans () * point_type (); + } + + static box_type get_bbox (C *t) + { + point_type p = get_pos (t); + return box_type (p, p); + } + + static void set_halign (C *t, db::HAlign f) + { + t->halign (f); + } + + static void set_halign_int (C *t, int f) { t->halign (db::HAlign (f)); } - static int get_halign (C *t) + static db::HAlign get_halign (C *t) { return t->halign (); } - static void set_valign (C *t, int f) + static void set_valign (C *t, db::VAlign f) + { + t->valign (f); + } + + static void set_valign_int (C *t, int f) { t->valign (db::VAlign (f)); } - static int get_valign (C *t) + static db::VAlign get_valign (C *t) { return t->valign (); } @@ -186,6 +209,18 @@ struct text_defs method ("string", (const char *(C::*) () const) &C::string, "@brief Get the text string\n" ) + + method_ext ("position", get_pos, + "@brief Gets the position of the text\n" + "\n" + "This convenience method has been added in version 0.28." + ) + + method_ext ("bbox", get_bbox, + "@brief Gets the bounding box of the text\n" + "The bounding box of the text is a single point - the location of the text. " + "Both points of the box are identical.\n" + "\n" + "This method has been added in version 0.28." + ) + method_ext ("x=", set_x, gsi::arg ("x"), "@brief Sets the x location of the text\n" "\n" @@ -210,43 +245,54 @@ struct text_defs "@brief Assign a transformation (text position and orientation) to this object\n" ) + method ("trans", (const simple_trans_type & (C::*) () const) &C::trans, - "@brief Get the transformation\n" + "@brief Gets the transformation\n" ) + method ("size=", (void (C::*) (coord_type)) &C::size, gsi::arg ("s"), - "@brief Set the text height of this object\n" + "@brief Sets the text height of this object\n" ) + method ("size", (coord_type (C::*) () const) &C::size, - "@brief Get the text height\n" + "@brief Gets the text height\n" ) + method_ext ("font=", &set_font, gsi::arg ("f"), - "@brief Set the font number\n" + "@brief Sets the font number\n" + "The font number does not play a role for KLayout. This property is provided " + "for compatibility with other systems which allow using different fonts for the text objects." ) + method_ext ("font", &get_font, - "@brief Get the font number\n" + "@brief Gets the font number\n" + "See \\font= for a description of this property." + ) + + method_ext ("#halign=", &set_halign_int, gsi::arg ("a"), + "@brief Sets the horizontal alignment\n" + "\n" + "This is the version accepting integer values. It's provided for backward compatibility.\n" ) + method_ext ("halign=", &set_halign, gsi::arg ("a"), - "@brief Set the horizontal alignment\n" + "@brief Sets the horizontal alignment\n" "\n" "This property specifies how the text is aligned relative to the anchor point. " - "Allowed values for this property are 0 (left), 1 (center) and 2 (right)." "\n" - "This property has been introduced in version 0.22.\n" + "This property has been introduced in version 0.22 and extended to enums in 0.28.\n" ) + method_ext ("halign", &get_halign, - "@brief Get the horizontal alignment\n" + "@brief Gets the horizontal alignment\n" "\n" "See \\halign= for a description of this property.\n" ) + + method_ext ("#valign=", &set_valign_int, gsi::arg ("a"), + "@brief Sets the vertical alignment\n" + "\n" + "This is the version accepting integer values. It's provided for backward compatibility.\n" + ) + method_ext ("valign=", &set_valign, gsi::arg ("a"), - "@brief Set the vertical alignment\n" + "@brief Sets the vertical alignment\n" "\n" "This property specifies how the text is aligned relative to the anchor point. " - "Allowed values for this property are 0 (top), 1 (center) and 2 (bottom)." "\n" - "This property has been introduced in version 0.22.\n" + "This property has been introduced in version 0.22 and extended to enums in 0.28.\n" ) + method_ext ("valign", &get_valign, - "@brief Get the vertical alignment\n" + "@brief Gets the vertical alignment\n" "\n" "See \\valign= for a description of this property.\n" ) + @@ -303,14 +349,14 @@ struct text_defs "This method was introduced in version 0.23." ) + method ("transformed", &C::template transformed, gsi::arg ("t"), - "@brief Transform the text with the given simple transformation\n" + "@brief Transforms the text with the given simple transformation\n" "\n" "\n" "@param t The transformation to apply\n" "@return The transformed text\n" ) + method ("transformed", &C::template transformed, gsi::arg ("t"), - "@brief Transform the text with the given complex transformation\n" + "@brief Transforms the text with the given complex transformation\n" "\n" "\n" "@param t The magnifying transformation to apply\n" @@ -346,7 +392,7 @@ struct text_defs "This method has been added in version 0.23.\n" ) + method ("to_s", &C::to_string, gsi::arg ("dbu", 0.0), - "@brief Convert to a string.\n" + "@brief Converts the object to a string.\n" "If a DBU is given, the output units will be micrometers.\n" "\n" "The DBU argument has been added in version 0.27.6.\n" @@ -451,4 +497,44 @@ Class decl_DText ("db", "DText", "database objects." ); +gsi::Enum decl_HAlign ("db", "HAlign", + gsi::enum_const ("HAlignLeft", db::HAlignLeft, + "@brief Left horizontal alignment\n" + ) + + gsi::enum_const ("HAlignCenter", db::HAlignCenter, + "@brief Centered horizontal alignment\n" + ) + + gsi::enum_const ("HAlignRight", db::HAlignRight, + "@brief Right horizontal alignment\n" + ) + + gsi::enum_const ("NoHAlign", db::NoHAlign, + "@brief Undefined horizontal alignment\n" + ), + "@brief This class represents the horizontal alignment modes.\n" + "This enum has been introduced in version 0.28." +); + +gsi::Enum decl_VAlign ("db", "VAlign", + gsi::enum_const ("VAlignBottom", db::VAlignBottom, + "@brief Bottom vertical alignment\n" + ) + + gsi::enum_const ("VAlignCenter", db::VAlignCenter, + "@brief Centered vertical alignment\n" + ) + + gsi::enum_const ("VAlignTop", db::VAlignTop, + "@brief Top vertical alignment\n" + ) + + gsi::enum_const ("NoVAlign", db::NoVAlign, + "@brief Undefined vertical alignment\n" + ), + "@brief This class represents the vertical alignment modes.\n" + "This enum has been introduced in version 0.28." +); + +// Inject the alignment enums +gsi::ClassExt inject_Text_HAlign_in_parent (decl_HAlign.defs ()); +gsi::ClassExt inject_DText_HAlign_in_parent (decl_HAlign.defs ()); +gsi::ClassExt inject_Text_VAlign_in_parent (decl_VAlign.defs ()); +gsi::ClassExt inject_DText_VAlign_in_parent (decl_VAlign.defs ()); + } diff --git a/src/db/db/gsiDeclDbTrans.cc b/src/db/db/gsiDeclDbTrans.cc index cc00b33f6..ed6296625 100644 --- a/src/db/db/gsiDeclDbTrans.cc +++ b/src/db/db/gsiDeclDbTrans.cc @@ -742,7 +742,7 @@ struct cplx_trans_defs "\n" "@return The inverted transformation\n" ) + - method ("ctrans", &C::ctrans, arg ("d"), + method ("ctrans|*", &C::ctrans, arg ("d"), "@brief Transforms a distance\n" "\n" "The \"ctrans\" method transforms the given distance.\n" diff --git a/src/db/unit_tests/dbLayoutQueryTests.cc b/src/db/unit_tests/dbLayoutQueryTests.cc index 2bd77bacf..87e0cd37d 100644 --- a/src/db/unit_tests/dbLayoutQueryTests.cc +++ b/src/db/unit_tests/dbLayoutQueryTests.cc @@ -232,6 +232,8 @@ TEST(1) EXPECT_EQ (s, "1,8"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3),()"); + s = q2s_var (iq, "dbbox"); + EXPECT_EQ (s, "(0,0.001;0.002,0.003),()"); } { @@ -568,16 +570,26 @@ TEST(2) EXPECT_EQ (s, "c1,c1"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20"); + s = q2s_var (iq, "dtrans"); + EXPECT_EQ (s, "r0 *1 0.01,-0.02,m45 *1 -0.01,0.02"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20"); + s = q2s_var (iq, "path_dtrans"); + EXPECT_EQ (s, "r0 *1 0.01,-0.02,m45 *1 -0.01,0.02"); s = q2s_var (iq, "inst_bbox"); EXPECT_EQ (s, "(10,-10;20,10),(0,20;20,30)"); + s = q2s_var (iq, "inst_dbbox"); + EXPECT_EQ (s, "(0.01,-0.01;0.02,0.01),(0,0.02;0.02,0.03)"); s = q2s_var (iq, "inst"); EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20"); s = q2s_var (iq, "array_a"); EXPECT_EQ (s, "nil,nil"); + s = q2s_var (iq, "array_da"); + EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_b"); EXPECT_EQ (s, "nil,nil"); + s = q2s_var (iq, "array_db"); + EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_na"); EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_nb"); @@ -603,8 +615,12 @@ TEST(2) EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3)"); s = q2s_var (iq, "array_a"); EXPECT_EQ (s, "nil,1,1,1,1,1,1,1,1,1,1,1,1"); + s = q2s_var (iq, "array_da"); + EXPECT_EQ (s, "nil,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001"); s = q2s_var (iq, "array_b"); EXPECT_EQ (s, "nil,0,2,0,2,0,2,0,2,0,2,0,2"); + s = q2s_var (iq, "array_db"); + EXPECT_EQ (s, "nil,0,0.002,0,0.002,0,0.002,0,0.002,0,0.002,0,0.002"); s = q2s_var (iq, "array_na"); EXPECT_EQ (s, "nil,2,2,2,2,2,2"); s = q2s_var (iq, "array_nb"); @@ -788,6 +804,12 @@ TEST(3) EXPECT_EQ (s, "0,1,1,2"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3),(0,1;2,3),(0,1;2,3),(10,11;10,11)"); + s = q2s_var (iq, "dbbox"); + EXPECT_EQ (s, "(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0.01,0.011;0.01,0.011)"); + s = q2s_var (iq, "shape_bbox"); + EXPECT_EQ (s, "(0,1;2,3),(0,1;2,3),(0,1;2,3),(10,11;10,11)"); + s = q2s_var (iq, "shape_dbbox"); + EXPECT_EQ (s, "(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0.01,0.011;0.01,0.011)"); } { diff --git a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc index e8ba49cea..6656613c7 100644 --- a/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveInstanceIteratorTests.cc @@ -619,3 +619,44 @@ TEST(4) EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true); } +TEST(5) +{ + std::unique_ptr g (new db::Layout ()); + g->insert_layer (0); + g->insert_layer (1); + g->insert_layer (2); + + db::Cell &c0 (g->cell (g->add_cell ())); + db::Cell &c1 (g->cell (g->add_cell ())); + db::Cell &c2 (g->cell (g->add_cell ())); + db::Cell &c3 (g->cell (g->add_cell ())); + + db::Box b (0, 100, 1000, 1200); + c0.shapes (0).insert (b); + c1.shapes (0).insert (b); + c2.shapes (0).insert (b); + c3.shapes (0).insert (b); + + c0.shapes (2).insert (b); + c0.shapes (2).insert (b.moved (db::Vector (50, 50))); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100)))); + c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1))); + c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0)))); + + std::string x; + + db::RecursiveInstanceIterator i1 (*g, c0, db::Box (0, 0, 100, 100)); + x = collect(i1, *g); + EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100"); + + g.reset (new db::Layout ()); + + // now the layout is gone and the iterator stays silent (weak pointer to layout) + // NOTE: this only works on reset or re-initialization. Not during iteration. + i1.reset (); + x = collect(i1, *g); + EXPECT_EQ (x, ""); +} diff --git a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc index 077f47793..c4dc63ae2 100644 --- a/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc +++ b/src/db/unit_tests/dbRecursiveShapeIteratorTests.cc @@ -1515,3 +1515,42 @@ TEST(10) "end\n" ); } + +TEST(11_LayoutIsWeakPointer) +{ + std::unique_ptr g (new db::Layout ()); + g->insert_layer (0); + g->insert_layer (1); + db::Cell &c0 (g->cell (g->add_cell ())); + db::Cell &c1 (g->cell (g->add_cell ())); + db::Cell &c2 (g->cell (g->add_cell ())); + db::Cell &c3 (g->cell (g->add_cell ())); + + db::Box b (0, 100, 1000, 1200); + c1.shapes (0).insert (b); + c2.shapes (0).insert (b); + c3.shapes (0).insert (b); + + db::Box bb (1, 101, 1001, 1201); + c2.shapes (1).insert (bb); + + db::Trans tt; + c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt)); + c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100)))); + c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1))); + c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0)))); + + std::string x; + + db::RecursiveShapeIterator i1 (*g, c0, 0, db::Box (0, 0, 100, 100)); + x = collect(i1, *g); + EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); + + g.reset (new db::Layout ()); + + // now the layout is gone and the iterator stays silent (weak pointer to layout) + // NOTE: this only works on reset or re-initialization. Not during iteration. + i1.reset (); + x = collect(i1, *g); + EXPECT_EQ (x, ""); +} diff --git a/src/lay/lay/doc/about/custom_queries.xml b/src/lay/lay/doc/about/custom_queries.xml index 02c70381b..406456754 100644 --- a/src/lay/lay/doc/about/custom_queries.xml +++ b/src/lay/lay/doc/about/custom_queries.xml @@ -388,7 +388,7 @@ shapes on layer METAL, POLY from cell TOP Any kind of cell query can be used inside the shape query. If a cell query renders multiple cells, the shape query will be applied to each of the cells returned. If instances are selected by the cell query, the shapes will be reported for each instance. Since the cumulated transformation - of a specific instance into the top cell is available through the "path_trans" variable, + of a specific instance into the top cell is available through the "path_trans" (database units) or "path_dtrans" (micrometer units) variable, it is possible to transform each shape into the top cell in the instance case. The following expression combines a "with .. do" action with a shape query to flatten all shapes below "TOP":

@@ -603,10 +603,20 @@ delete shapes on layer 6 of cell TOP The cell's bounding box. + + dbbox + + The cell's bounding box in micrometer units. + cell_bbox - Same as "bbox" (disambiguator for shape and instance bounding boxes). + Same as "bbox" (disambiguator from shape and instance bounding boxes). + + + cell_dbbox + + Same as "dbbox" (disambiguator from shape and instance bounding boxes). @@ -631,16 +641,32 @@ delete shapes on layer 6 of cell TOP The transformation of that instance into the top cell. For a plain cell that is a unit transformation. + + path_dtrans + + The transformation of that instance into the top cell in micrometer units. + For a plain cell that is a unit transformation. + trans The transformation of that instance (first instance if an array). + + dtrans + + The transformation of that instance (first instance if an array) in micrometer units. + inst_bbox The instance bounding box in the initial cell. + + inst_dbbox + + The instance bounding box in the initial cell in micrometer units. + inst @@ -648,9 +674,14 @@ delete shapes on layer 6 of cell TOP array_a - + The a vector for an array instance or nil if the instance is not an array. + + array_da + + The a vector for an array instance in micrometer units or nil if the instance is not an array. + array_na Integer @@ -658,9 +689,14 @@ delete shapes on layer 6 of cell TOP array_b - + The b vector for an array instance or nil if the instance is not an array. + + array_db + + The b vector for an array instance in micrometer units or nil if the instance is not an array. + array_nb Integer @@ -689,14 +725,24 @@ delete shapes on layer 6 of cell TOP NameValue typeDescription bbox - + The shape's bounding box + + dbbox + + The shape's bounding box in micrometer units + shape_bbox Same as "bbox" (disambiguator for cell or instance bounding boxes) + + shape_dbbox + + Same as "dbbox" (disambiguator for cell or instance bounding boxes) + shape diff --git a/src/lay/lay/laySearchReplaceDialog.cc b/src/lay/lay/laySearchReplaceDialog.cc index 701c9094e..f2f46bdb2 100644 --- a/src/lay/lay/laySearchReplaceDialog.cc +++ b/src/lay/lay/laySearchReplaceDialog.cc @@ -1699,6 +1699,55 @@ SearchReplaceDialog::result_selection_changed () } + } else if (index < int (m_model.data ().size ())) { + + db::DCplxTrans as_dbu = db::DCplxTrans (layout.dbu ()).inverted (); + + const tl::Variant &dr = m_model.data () [index]; + for (tl::Variant::const_iterator v = dr.begin (); v != dr.end (); ++v) { + + lay::Marker *marker = new lay::Marker (view (), cv_index); + + if (v->is_user ()) { + marker->set (v->to_user (), as_dbu, global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), db::ICplxTrans (), global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), as_dbu, global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), db::ICplxTrans (), global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), as_dbu, global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), db::ICplxTrans (), global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), as_dbu, global_trans); + } else if (v->is_user ()) { + marker->set (v->to_user (), db::ICplxTrans (), global_trans); + } else if (v->is_user ()) { + db::DPoint p = v->to_user (); + marker->set (db::DBox (p, p), as_dbu, global_trans); + } else if (v->is_user ()) { + db::Point p = v->to_user (); + marker->set (db::Box (p, p), db::ICplxTrans (), global_trans); + } else if (v->is_user ()) { + db::DPoint p = db::DPoint () + v->to_user (); + marker->set (db::DBox (p, p), as_dbu, global_trans); + } else if (v->is_user ()) { + db::Point p = db::Point () + v->to_user (); + marker->set (db::Box (p, p), db::ICplxTrans (), global_trans); + } else { + delete marker; + marker = 0; + } + + if (marker) { + mp_markers.push_back (marker); + dbox += marker->bbox (); + } + + } + } } diff --git a/testdata/ruby/dbBoxTest.rb b/testdata/ruby/dbBoxTest.rb index 92e56dab9..4f6c1de10 100644 --- a/testdata/ruby/dbBoxTest.rb +++ b/testdata/ruby/dbBoxTest.rb @@ -106,6 +106,13 @@ class DBBox_TestClass < TestBase a = RBA::DBox.new assert_equal( a.empty?, true ) + a = RBA::DBox::world + b = RBA::DBox::new(1, 2, 3, 4) + assert_equal( a.empty?, false ) + assert_equal( a == RBA::DBox::world, true ) + assert_equal( (a + b) == RBA::DBox::world, true ) + assert_equal( (a & b) == b, true ) + end # DBox basics @@ -303,6 +310,13 @@ class DBBox_TestClass < TestBase a = RBA::Box.new assert_equal( a.empty?, true ) + a = RBA::Box::world + b = RBA::Box::new(1, 2, 3, 4) + assert_equal( a.empty?, false ) + assert_equal( a == RBA::Box::world, true ) + assert_equal( (a + b) == RBA::Box::world, true ) + assert_equal( (a & b) == b, true ) + end # Box basics diff --git a/testdata/ruby/dbCellInstArrayTest.rb b/testdata/ruby/dbCellInstArrayTest.rb index c57252a0d..c8beacd24 100644 --- a/testdata/ruby/dbCellInstArrayTest.rb +++ b/testdata/ruby/dbCellInstArrayTest.rb @@ -49,6 +49,11 @@ class DBCellInst_TestClass < TestBase assert_equal(a.trans.to_s, "r90 0,0") assert_equal(a.cplx_trans.to_s, "r90 *1 0,0") + a = RBA::CellInstArray::new(0, RBA::Vector::new(42, -17)) + assert_equal(a.is_complex?, false) + assert_equal(a.trans.to_s, "r0 42,-17") + assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17") + a = RBA::CellInstArray::new(0, RBA::ICplxTrans::new(1.5)) assert_equal(a.is_complex?, true) assert_equal(a.trans.to_s, "r0 0,0") @@ -106,6 +111,12 @@ class DBCellInst_TestClass < TestBase assert_equal(a.cplx_trans.to_s, "r90 *1 0,0") assert_equal(a.to_s, "#0 r90 0,0 [10,20*3;30,40*5]") + a = RBA::CellInstArray::new(0, RBA::Vector::new(42, -17), RBA::Vector::new(10, 20), RBA::Vector::new(30, 40), 3, 5) + assert_equal(a.is_complex?, false) + assert_equal(a.trans.to_s, "r0 42,-17") + assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17") + assert_equal(a.to_s, "#0 r0 42,-17 [10,20*3;30,40*5]") + a = RBA::CellInstArray::new(0, RBA::ICplxTrans::new(1.5), RBA::Vector::new(10, 20), RBA::Vector::new(30, 40), 3, 5) assert_equal(a.is_complex?, true) assert_equal(a.trans.to_s, "r0 0,0") @@ -178,6 +189,11 @@ class DBCellInst_TestClass < TestBase assert_equal(a.trans.to_s, "r90 0,0") assert_equal(a.cplx_trans.to_s, "r90 *1 0,0") + a = RBA::DCellInstArray::new(0, RBA::DVector::new(42, -17)) + assert_equal(a.is_complex?, false) + assert_equal(a.trans.to_s, "r0 42,-17") + assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17") + a = RBA::DCellInstArray::new(0, RBA::DCplxTrans::new(1.5)) assert_equal(a.is_complex?, true) assert_equal(a.trans.to_s, "r0 0,0") @@ -235,6 +251,12 @@ class DBCellInst_TestClass < TestBase assert_equal(a.cplx_trans.to_s, "r90 *1 0,0") assert_equal(a.to_s, "#0 r90 0,0 [10,20*3;30,40*5]") + a = RBA::DCellInstArray::new(0, RBA::DVector::new(42, -17), RBA::DVector::new(10, 20), RBA::DVector::new(30, 40), 3, 5) + assert_equal(a.is_complex?, false) + assert_equal(a.trans.to_s, "r0 42,-17") + assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17") + assert_equal(a.to_s, "#0 r0 42,-17 [10,20*3;30,40*5]") + a = RBA::DCellInstArray::new(0, RBA::DCplxTrans::new(1.5), RBA::DVector::new(10, 20), RBA::DVector::new(30, 40), 3, 5) assert_equal(a.is_complex?, true) assert_equal(a.trans.to_s, "r0 0,0") diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index 968515c32..92ca43de9 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -1043,10 +1043,31 @@ class DBLayout_TestClass < TestBase ci = l.clip(c0.cell_index, RBA::Box.new(0, 0, 200, 200)) assert_equal(dump_layer_i(l, 0, ci), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + cic = l.clip(c0, RBA::Box.new(0, 0, 200, 200)) + assert_equal(dump_layer_i(l, 0, cic.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + + cid = l.clip(c0.cell_index, RBA::DBox.new(0, 0, 0.2, 0.2)) + assert_equal(dump_layer_i(l, 0, cid), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + + cicd = l.clip(c0, RBA::DBox.new(0, 0, 0.2, 0.2)) + assert_equal(dump_layer_i(l, 0, cicd.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + ci = l.multi_clip(c0.cell_index, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)]) assert_equal(dump_layer_i(l, 0, ci[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") assert_equal(dump_layer_i(l, 0, ci[1]), "(1000,0;1100,200); (1200,0;1300,200)") + cic = l.multi_clip(c0, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)]) + assert_equal(dump_layer_i(l, 0, cic[0].cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + assert_equal(dump_layer_i(l, 0, cic[1].cell_index), "(1000,0;1100,200); (1200,0;1300,200)") + + cid = l.multi_clip(c0.cell_index, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)]) + assert_equal(dump_layer_i(l, 0, cid[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + assert_equal(dump_layer_i(l, 0, cid[1]), "(1000,0;1100,200); (1200,0;1300,200)") + + cidc = l.multi_clip(c0, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)]) + assert_equal(dump_layer_i(l, 0, cidc[0].cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + assert_equal(dump_layer_i(l, 0, cidc[1].cell_index), "(1000,0;1100,200); (1200,0;1300,200)") + ll = RBA::Layout.new ll.dbu = l.dbu ll.insert_layer_at(0, RBA::LayerInfo.new(2, 0)) @@ -1054,10 +1075,31 @@ class DBLayout_TestClass < TestBase ci = l.clip_into(c0.cell_index, ll, RBA::Box.new(0, 0, 200, 200)) assert_equal(dump_layer_i(ll, 0, ci), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + cic = l.clip_into(c0, ll, RBA::Box.new(0, 0, 200, 200)) + assert_equal(dump_layer_i(ll, 0, cic.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + + cid = l.clip_into(c0.cell_index, ll, RBA::DBox.new(0, 0, 0.2, 0.2)) + assert_equal(dump_layer_i(ll, 0, cid), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + + cicd = l.clip_into(c0, ll, RBA::DBox.new(0, 0, 0.2, 0.2)) + assert_equal(dump_layer_i(ll, 0, cicd.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + ci = l.multi_clip_into(c0.cell_index, ll, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)]) assert_equal(dump_layer_i(ll, 0, ci[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") assert_equal(dump_layer_i(ll, 0, ci[1]), "(1000,0;1100,200); (1200,0;1300,200)") + cic = l.multi_clip_into(c0, ll, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)]) + assert_equal(dump_layer_i(ll, 0, cic[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + assert_equal(dump_layer_i(ll, 0, cic[1]), "(1000,0;1100,200); (1200,0;1300,200)") + + cid = l.multi_clip_into(c0.cell_index, ll, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)]) + assert_equal(dump_layer_i(ll, 0, cid[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + assert_equal(dump_layer_i(ll, 0, cid[1]), "(1000,0;1100,200); (1200,0;1300,200)") + + cicd = l.multi_clip_into(c0, ll, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)]) + assert_equal(dump_layer_i(ll, 0, cicd[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)") + assert_equal(dump_layer_i(ll, 0, cicd[1]), "(1000,0;1100,200); (1200,0;1300,200)") + end def test_8 diff --git a/testdata/ruby/dbLayoutTest.rb b/testdata/ruby/dbLayoutTest.rb index dd6fa5735..29a7f3dc2 100644 --- a/testdata/ruby/dbLayoutTest.rb +++ b/testdata/ruby/dbLayoutTest.rb @@ -23,10 +23,10 @@ end load("test_prologue.rb") -class DBLayout_TestClass < TestBase +class DBLayoutTest_TestClass < TestBase # LayerInfo - def _test_1_Layout + def test_1_Layout lp = RBA::LayerInfo::new @@ -62,7 +62,7 @@ class DBLayout_TestClass < TestBase end # Basics: cells and instances - def _test_2_Layout + def test_2_Layout ly = RBA::Layout::new @@ -182,7 +182,7 @@ class DBLayout_TestClass < TestBase end # Instances and bboxes - def _test_5_Layout + def test_5_Layout ly = RBA::Layout::new @@ -223,10 +223,13 @@ class DBLayout_TestClass < TestBase assert_equal( c1.bbox_per_layer( lindex ).to_s, "()" ) assert_equal( c1.bbox_per_layer( ldummy ).to_s, "()" ) + assert_equal( ly.unique_cell_name("c3"), "c3" ) + assert_equal( ly.unique_cell_name("c1"), "c1$1" ) + end # Instances and bboxes - def _test_6_Layout + def test_6_Layout ly = RBA::Layout::new @@ -398,7 +401,7 @@ class DBLayout_TestClass < TestBase end # Instances and editable mode - def _test_6_EditableLayout + def test_6_EditableLayout ly = RBA::Layout::new( true ) assert_equal( ly.is_editable?, true ) @@ -470,7 +473,7 @@ class DBLayout_TestClass < TestBase end # Instances and bboxes - def _test_6_Layout_props + def test_6_Layout_props ly = RBA::Layout::new pid = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a ) @@ -648,7 +651,7 @@ class DBLayout_TestClass < TestBase end # Properties - def _test_6_Layout_props2 + def test_6_Layout_props2 ly = RBA::Layout::new(true) pid = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a ) @@ -697,7 +700,7 @@ class DBLayout_TestClass < TestBase end # Instances and bboxes (editable mode) - def _test_6_Layout_new + def test_6_Layout_new if( RBA::Application::instance.is_editable? ) @@ -805,7 +808,7 @@ class DBLayout_TestClass < TestBase end # Copy/move between cells - def _test_7_cells_copy_move + def test_7_cells_copy_move # because of set_property ... if !RBA::Application::instance.is_editable? @@ -879,7 +882,7 @@ class DBLayout_TestClass < TestBase end # top cells - def _test_8 + def test_8 l = RBA::Layout.new tc = [] @@ -916,7 +919,7 @@ class DBLayout_TestClass < TestBase end # under construction and update - def _test_9 + def test_9 ly = RBA::Layout::new l1 = ly.insert_layer(RBA::LayerInfo::new(1, 0)) @@ -946,7 +949,7 @@ class DBLayout_TestClass < TestBase end # Instance editing - def _test_10 + def test_10 ly = RBA::Layout::new @@ -1025,7 +1028,7 @@ class DBLayout_TestClass < TestBase end # User properties - def _test_11 + def test_11 ly = RBA::Layout::new @@ -1049,7 +1052,7 @@ class DBLayout_TestClass < TestBase end # Meta information - def _test_12 + def test_12 mi = RBA::LayoutMetaInfo::new("myinfo", "a") diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index ac2d7c037..3f30f0cf4 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -277,8 +277,19 @@ class DBPolygon_TestClass < TestBase a = RBA::Polygon::new( [ RBA::Point::new( 0, 1 ), RBA::Point::new( 1, 5 ), RBA::Point::new( 5, 5 ) ] ) assert_equal( a.to_s, "(0,1;1,5;5,5)" ) assert_equal( a.sized(2, 0, 2).to_s, "(-2,1;-1,5;7,5;2,1)" ) + assert_equal( a.sized(RBA::Vector::new(2, 0), 2).to_s, "(-2,1;-1,5;7,5;2,1)" ) + assert_equal( a.sized(RBA::Vector::new(2, 0)).to_s, "(-2,1;-1,5;7,5;2,1)" ) + aa = a.dup a.size(2, 0, 2); assert_equal( a.to_s, "(-2,1;-1,5;7,5;2,1)" ) + a = aa + aa = a.dup + a.size(RBA::Vector::new(2, 0), 2); + assert_equal( a.to_s, "(-2,1;-1,5;7,5;2,1)" ) + a = aa + aa = a.dup + a.size(RBA::Vector::new(2, 0)); + assert_equal( a.to_s, "(-2,1;-1,5;7,5;2,1)" ) a = RBA::Polygon::new assert_equal( a.to_s, "()" ) diff --git a/testdata/ruby/dbRecursiveInstanceIterator.rb b/testdata/ruby/dbRecursiveInstanceIterator.rb index 9448d147d..4d9aefa2b 100644 --- a/testdata/ruby/dbRecursiveInstanceIterator.rb +++ b/testdata/ruby/dbRecursiveInstanceIterator.rb @@ -27,7 +27,16 @@ class DBLayout_TestClass < TestBase def collect(s, l) + # check native iteration here too .. + res2 = [] + s.each do |s| + r = "[#{s.inst_cell.name}]" + r += (s.trans * s.inst_trans).to_s + res2.push(r) + end + res = [] + s.reset while !s.at_end? r = "[#{s.inst_cell.name}]" r += (s.trans * s.inst_trans).to_s @@ -35,6 +44,8 @@ class DBLayout_TestClass < TestBase s.next end + assert_equal(res, res2) + return res.join("/") end diff --git a/testdata/ruby/dbRecursiveShapeIterator.rb b/testdata/ruby/dbRecursiveShapeIterator.rb index 2f46a306b..82d4b47b6 100644 --- a/testdata/ruby/dbRecursiveShapeIterator.rb +++ b/testdata/ruby/dbRecursiveShapeIterator.rb @@ -27,7 +27,21 @@ class DBRecursiveShapeIterator_TestClass < TestBase def collect(s, l) + # check native iteration here too .. + res2 = [] + s.each do |s| + r = "[#{l.cell_name(s.cell_index)}]" + if s.shape.is_box? + box = s.shape.box + r += box.transformed(s.trans).to_s + else + r += "X"; + end + res2.push(r) + end + res = [] + s.reset while !s.at_end? r = "[#{l.cell_name(s.cell_index)}]" if s.shape.is_box? @@ -40,6 +54,8 @@ class DBRecursiveShapeIterator_TestClass < TestBase res.push(r) end + assert_equal(res, res2) + return res.join("/") end diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 47b5808eb..be086fd1c 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -318,6 +318,16 @@ class DBRegion_TestClass < TestBase rr.size(10, 20, 2) assert_equal(rr.to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)") + assert_equal((r1 | r2).sized(RBA::Vector::new(10, 20)).to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)") + rr = (r1 | r2).dup + rr.size(10, 20, 2) + assert_equal(rr.to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)") + + assert_equal((r1 | r2).sized(RBA::Vector::new(10, 20), 2).to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)") + rr = (r1 | r2).dup + rr.size(10, 20, 2) + assert_equal(rr.to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)") + r1.merged_semantics = false assert_equal((r1 | r2).sized(10, 2).to_s, "(-20,-30;-20,170;0,170;0,210;110,210;110,10;90,10;90,-30)") diff --git a/testdata/ruby/dbTextTest.rb b/testdata/ruby/dbTextTest.rb index 75eedbf76..fff844660 100644 --- a/testdata/ruby/dbTextTest.rb +++ b/testdata/ruby/dbTextTest.rb @@ -69,12 +69,34 @@ class DBText_TestClass < TestBase a = RBA::DText::new( "hallo", a.trans, 22.0, 7 ) assert_equal( a.string, "hallo" ) assert_equal( a.trans.to_s, "m45 5,7" ) + assert_equal( a.position.to_s, "5,7" ) + assert_equal( a.bbox.to_s, "(5,7;5,7)" ) assert_equal( a.font, 7 ) assert_equal( a.size, 22.0 ) a.font = 8 assert_equal( a.font, 8 ) + a.halign = 1 + assert_equal( a.halign.to_i, 1 ) + assert_equal( a.halign, RBA::DText::HAlignCenter ) + assert_equal( a.halign.to_s, "HAlignCenter" ) + + a.halign = RBA::DText::HAlignRight + assert_equal( a.halign.to_i, 2 ) + assert_equal( a.halign, RBA::DText::HAlignRight ) + assert_equal( a.halign.to_s, "HAlignRight" ) + + a.valign = 1 + assert_equal( a.valign.to_i, 1 ) + assert_equal( a.valign, RBA::DText::VAlignCenter ) + assert_equal( a.valign.to_s, "VAlignCenter" ) + + a.valign = RBA::DText::VAlignBottom + assert_equal( a.valign.to_i, 2 ) + assert_equal( a.valign, RBA::DText::VAlignBottom ) + assert_equal( a.valign.to_s, "VAlignBottom" ) + a.size = 23.0 assert_equal( a.size, 23.0 ) @@ -141,12 +163,34 @@ class DBText_TestClass < TestBase a = RBA::Text::new( "hallo", a.trans, 22, 7 ) assert_equal( a.string, "hallo" ) assert_equal( a.trans.to_s, "m45 5,7" ) + assert_equal( a.position.to_s, "5,7" ) + assert_equal( a.bbox.to_s, "(5,7;5,7)" ) assert_equal( a.font, 7 ) assert_equal( a.size, 22.0 ) a.font = 8 assert_equal( a.font, 8 ) + a.halign = 1 + assert_equal( a.halign.to_i, 1 ) + assert_equal( a.halign, RBA::Text::HAlignCenter ) + assert_equal( a.halign.to_s, "HAlignCenter" ) + + a.halign = RBA::Text::HAlignLeft + assert_equal( a.halign.to_i, 0 ) + assert_equal( a.halign, RBA::Text::HAlignLeft ) + assert_equal( a.halign.to_s, "HAlignLeft" ) + + a.valign = 1 + assert_equal( a.valign.to_i, 1 ) + assert_equal( a.valign, RBA::Text::VAlignCenter ) + assert_equal( a.valign.to_s, "VAlignCenter" ) + + a.valign = RBA::Text::VAlignTop + assert_equal( a.valign.to_i, 0 ) + assert_equal( a.valign, RBA::Text::VAlignTop ) + assert_equal( a.valign.to_s, "VAlignTop" ) + a.size = 23 assert_equal( a.size, 23 ) diff --git a/testdata/ruby/dbTransTest.rb b/testdata/ruby/dbTransTest.rb index 7fca57d7a..df24c8716 100644 --- a/testdata/ruby/dbTransTest.rb +++ b/testdata/ruby/dbTransTest.rb @@ -80,6 +80,8 @@ class DBTrans_TestClass < TestBase assert_equal( RBA::Trans::new(RBA::Trans::R180, RBA::DVector::new(5,-7)).to_s, "r180 5,-7" ) assert_equal( RBA::Trans::new(RBA::Trans::R180).to_s, "r180 0,0" ) + assert_equal( e.trans( 2.0 ).to_s, "2" ) + assert_equal( (e * 2.0).to_s, "2" ) assert_equal( e.trans( RBA::Edge::new(0, 1, 2, 3) ).to_s, "(-3,-2;-1,0)" ) assert_equal( ( e * RBA::Edge::new(0, 1, 2, 3) ).to_s, "(-3,-2;-1,0)" ) assert_equal( e.trans( RBA::Box::new(0, 1, 2, 3) ).to_s, "(-3,-2;-1,0)" ) @@ -140,7 +142,9 @@ class DBTrans_TestClass < TestBase assert_equal( mb.trans( RBA::DPoint::new( 1, 0 )).to_s, "17,3" ) assert_equal( mb.ctrans(2).to_s, "4.0" ) + assert_equal( (mb * 2).to_s, "4.0" ) assert_equal( i.ctrans(2).to_s, "1.0" ) + assert_equal( (i * 2).to_s, "1.0" ) end @@ -199,6 +203,7 @@ class DBTrans_TestClass < TestBase assert_equal( (c.angle - 45).abs < 1e-10, true ) assert_equal( c.ctrans( 5 ).to_s, "3.75" ) + assert_equal( (c * 5).to_s, "3.75" ) assert_equal( c.trans( RBA::DPoint::new( 12, 16 ) ).to_s, "17.3492424049,-14.6213203436" ) assert_equal( RBA::DCplxTrans::new.to_s, "r0 *1 0,0" ) @@ -306,7 +311,9 @@ class DBTrans_TestClass < TestBase assert_equal( mb.trans( RBA::Point::new( 1, 0 )).to_s, "17,3" ) assert_equal( mb.ctrans(2).to_s, "4.0" ) + assert_equal( (mb * 2).to_s, "4.0" ) assert_equal( i.ctrans(2).to_s, "1.0" ) + assert_equal( (i * 2).to_s, "1.0" ) end @@ -353,6 +360,7 @@ class DBTrans_TestClass < TestBase assert_equal( (c.angle - 45).abs < 1e-10, true ) assert_equal( c.ctrans( 5 ).to_s, "3.75" ) + assert_equal( (c * 5).to_s, "3.75" ) assert_equal( c.trans( RBA::Point::new( 12, 16 ) ).to_s, "17.3492424049,-14.6213203436" ) assert_equal( RBA::CplxTrans::new.to_s, "r0 *1 0,0" )