diff --git a/src/db/db/dbLayoutQuery.cc b/src/db/db/dbLayoutQuery.cc index 02ab78dd1..6024c7a28 100644 --- a/src/db/db/dbLayoutQuery.cc +++ b/src/db/db/dbLayoutQuery.cc @@ -202,7 +202,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 +213,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 +313,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 +428,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 +446,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 +497,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 +508,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 +793,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 +1021,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 +1078,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 +1130,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 +1185,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 +1195,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 +1303,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 +1328,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 +1414,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 +1503,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); } 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/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/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/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