From f538885fb3874506aae1e055649fde2f8a5f00ed Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 28 Apr 2018 09:46:42 +0200 Subject: [PATCH] Added some convenience methods for building RDB entries from shapes. --- Changelog | 4 + .../laybasic/rdbMarkerBrowserDialog.cc | 65 ++--------- src/rdb/rdb/gsiDeclRdb.cc | 104 +++++++++++++++++- src/rdb/rdb/rdb.cc | 33 ++++++ src/rdb/rdb/rdb.h | 7 ++ testdata/ruby/rdbTest.rb | 67 ++++++++++- 6 files changed, 217 insertions(+), 63 deletions(-) diff --git a/Changelog b/Changelog index 651ca1108..7341ced1a 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,10 @@ Shapes can now insert from another Shapes container and from a RecursiveShapeIterator. Possible applications are fast flattening and fast region selection. +* Enhancement: New method to generate RDB items from shapes + RdbItem#add_value from a shape, RdbDatabase#create_items + from a shapes container or recursive shape iterator and + RdbDatabase#create_item from a shape. * Enhancement: DXF and CIF "keep layer names" If this option is set in the reader options, layer names are not translated into GDS layer/datatype pairs. diff --git a/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc b/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc index 0157b9ca5..401ff756a 100644 --- a/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc +++ b/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc @@ -788,36 +788,12 @@ MarkerBrowserDialog::scan_layer () for (db::ShapeIterator shape = cell.shapes ((*l)->layer_index ()).begin (db::ShapeIterator::All); ! shape.at_end (); ++shape) { - std::auto_ptr value; - - if (shape->is_polygon () || shape->is_box ()) { - - db::Polygon poly; - shape->polygon (poly); - value.reset (new rdb::Value (poly.transformed (db::CplxTrans (layout.dbu ())))); - - } else if (shape->is_path ()) { - - db::Path path; - shape->path (path); - value.reset (new rdb::Value (path.transformed (db::CplxTrans (layout.dbu ())))); - - } else if (shape->is_text ()) { - - db::Text text; - shape->text (text); - value.reset (new rdb::Value (text.transformed (db::CplxTrans (layout.dbu ())))); - - } else if (shape->is_edge ()) { - - db::Edge edge; - shape->edge (edge); - value.reset (new rdb::Value (edge.transformed (db::CplxTrans (layout.dbu ())))); - + std::auto_ptr value (rdb::ValueBase::create_from_shape (*shape, db::CplxTrans (layout.dbu ()))); + if (value.get ()) { + rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ()); + item->values ().add (value.release ()); } - rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ()); - item->values ().add (value.release ()); ++progress; } @@ -891,37 +867,12 @@ MarkerBrowserDialog::scan_layer_flat () db::RecursiveShapeIterator shape (layout, *cv.cell (), (*l)->layer_index ()); while (! shape.at_end ()) { - std::auto_ptr value; - - if (shape->is_polygon () || shape->is_box ()) { - - db::Polygon poly; - shape->polygon (poly); - value.reset (new rdb::Value (poly.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); - - } else if (shape->is_path ()) { - - db::Path path; - shape->path (path); - value.reset (new rdb::Value (path.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); - - } else if (shape->is_text ()) { - - db::Text text; - shape->text (text); - value.reset (new rdb::Value (text.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); - - } else if (shape->is_edge ()) { - - db::Edge edge; - shape->edge (edge); - value.reset (new rdb::Value (edge.transformed (db::CplxTrans (layout.dbu ()) * shape.trans ()))); - + std::auto_ptr value (rdb::ValueBase::create_from_shape (*shape, db::CplxTrans (layout.dbu ()) * shape.trans ())); + if (value.get ()) { + rdb::Item *item = rdb->create_item (rdb_top_cell->id (), cat->id ()); + item->values ().add (value.release ()); } - rdb::Item *item = rdb->create_item (rdb_top_cell->id (), cat->id ()); - item->values ().add (value.release ()); - ++progress; ++shape; diff --git a/src/rdb/rdb/gsiDeclRdb.cc b/src/rdb/rdb/gsiDeclRdb.cc index 90c9cf9fc..5b0e2b1f0 100644 --- a/src/rdb/rdb/gsiDeclRdb.cc +++ b/src/rdb/rdb/gsiDeclRdb.cc @@ -36,6 +36,7 @@ #include "dbBox.h" #include "dbPath.h" #include "dbText.h" +#include "dbRecursiveShapeIterator.h" #include "dbTilingProcessor.h" namespace gsi @@ -289,16 +290,17 @@ Class decl_RdbCategory ("RdbCategory", "This method has been introduced in version 0.23." ) + gsi::method_ext ("scan_shapes", &scan_shapes, - "@brief Scans the shapes from the shape iterator into the category\n" + "@brief Scans the polygon or edge shapes from the shape iterator into the category\n" "@args iter\n" - "Creates RDB items for each shape read from the iterator and puts them into this category.\n" + "Creates RDB items for each polygon or edge shape read from the iterator and puts them into this category.\n" + "A similar, but lower-level method is \\ReportDatabase#create_items with a \\RecursiveShapeIterator argument.\n" "\n" "This method has been introduced in version 0.23.\n" ) + gsi::method_ext ("scan_layer", &scan_layer1, "@brief Scans a layer from a layout into this category\n" "@args layout, layer\n" - "Creates RDB items for each shape read from the each cell in the layout on the given layer and puts them into this category.\n" + "Creates RDB items for each polygon or edge shape read from the each cell in the layout on the given layer and puts them into this category.\n" "New cells will be generated for every cell encountered in the layout.\n" "Other settings like database unit, description, top cell etc. are not made in the RDB.\n" "\n" @@ -307,7 +309,7 @@ Class decl_RdbCategory ("RdbCategory", gsi::method_ext ("scan_layer", &scan_layer2, "@brief Scans a layer from a layout into this category, starting with a given cell\n" "@args layout, layer, cell\n" - "Creates RDB items for each shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n" + "Creates RDB items for each polygon or edge shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n" "New cells will be generated when required.\n" "Other settings like database unit, description, top cell etc. are not made in the RDB.\n" "\n" @@ -316,7 +318,7 @@ Class decl_RdbCategory ("RdbCategory", gsi::method_ext ("scan_layer", &scan_layer3, "@brief Scans a layer from a layout into this category, starting with a given cell and a depth specification\n" "@args layout, layer, cell, levels\n" - "Creates RDB items for each shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n" + "Creates RDB items for each polygon or edge shape read from the cell and it's children in the layout on the given layer and puts them into this category.\n" "New cells will be generated when required.\n" "\"levels\" is the number of hierarchy levels to take the child cells from. 0 means to use only \"cell\" and don't descend, -1 means \"all levels\".\n" "Other settings like database unit, description, top cell etc. are not made in the RDB.\n" @@ -713,6 +715,14 @@ static rdb::Values::const_iterator end_values (const rdb::Item *item) return item->values ().end (); } +static void add_value_from_shape (rdb::Item *item, const db::Shape &shape, const db::CplxTrans &trans) +{ + rdb::ValueBase *value = rdb::ValueBase::create_from_shape (shape, trans); + if (value) { + item->values ().add (value); + } +} + static void add_value (rdb::Item *item, const rdb::ValueWrapper &value) { item->values ().add (value); @@ -837,6 +847,15 @@ Class decl_RdbItem ("RdbItem", "@param value The value to add.\n" "This method has been introduced in version 0.25 as a convenience method." ) + + gsi::method_ext ("add_value", &add_value_from_shape, gsi::arg ("shape"), gsi::arg ("trans"), + "@brief Adds a geometrical value object from a shape\n" + "@param value The shape object from which to take the geometrical object.\n" + "@param trans The transformation to apply.\n" + "\n" + "The transformation can be used to convert database units to micron units.\n" + "\n" + "This method has been introduced in version 0.25.3." + ) + gsi::method_ext ("clear_values", &clear_values, "@brief Removes all values from this item\n" ) + @@ -945,6 +964,40 @@ void database_set_tag_description (rdb::Database *db, rdb::id_type tag, const st db->set_tag_description (tag, d); } +void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter) +{ + tl_assert (iter.layout ()); + double dbu = iter.layout ()->dbu (); + + for (db::RecursiveShapeIterator i = iter; !i.at_end (); ++i) { + std::auto_ptr value (rdb::ValueBase::create_from_shape (*i, db::CplxTrans (dbu) * i.trans ())); + if (value.get ()) { + rdb::Item *item = db->create_item (cell_id, cat_id); + item->values ().add (value.release ()); + } + } +} + +void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::Shapes &shapes, const db::CplxTrans &trans) +{ + for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); !s.at_end (); ++s) { + std::auto_ptr value (rdb::ValueBase::create_from_shape (*s, trans)); + if (value.get ()) { + rdb::Item *item = db->create_item (cell_id, cat_id); + item->values ().add (value.release ()); + } + } +} + +void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::Shape &shape, const db::CplxTrans &trans) +{ + std::auto_ptr value (rdb::ValueBase::create_from_shape (shape, trans)); + if (value.get ()) { + rdb::Item *item = db->create_item (cell_id, cat_id); + item->values ().add (value.release ()); + } +} + void create_items_from_region (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Region &collection) { typedef db::Region::const_iterator iter; @@ -1226,6 +1279,47 @@ Class decl_ReportDatabase ("ReportDatabase", "\n" "This convenience method has been added in version 0.25.\n" ) + + gsi::method_ext ("create_items", &create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"), + "@brief Creates new items from a shape iterator\n" + "This method takes the shapes from the given iterator and produces items from them.\n" + "It accepts various kind of shapes, such as texts, polygons, boxes and paths and " + "converts them to corresponding items. " + "A similar method, which is intended for production of polygon or edge error layers is \\RdbCategory#scan_shapes.\n" + "\n" + "This method has been introduced in version 0.25.3.\n" + "\n" + "@param cell_id The ID of the cell to which the item is associated\n" + "@param category_id The ID of the category to which the item is associated\n" + "@param iter The iterator (a \\RecursiveShapeIterator object) from which to take the items\n" + ) + + gsi::method_ext ("create_item", &create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("shape"), gsi::arg ("trans"), + "@brief Creates a new item from a single shape\n" + "This method produces an item from the given shape.\n" + "It accepts various kind of shapes, such as texts, polygons, boxes and paths and " + "converts them to a corresponding item. The transformation argument can be used to " + "supply the transformation that applies the database unit for example.\n" + "\n" + "This method has been introduced in version 0.25.3.\n" + "\n" + "@param cell_id The ID of the cell to which the item is associated\n" + "@param category_id The ID of the category to which the item is associated\n" + "@param shape The shape to take the geometrical object from\n" + "@param trans The transformation to apply\n" + ) + + gsi::method_ext ("create_items", &create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("shapes"), gsi::arg ("trans"), + "@brief Creates new items from a shape container\n" + "This method takes the shapes from the given container and produces items from them.\n" + "It accepts various kind of shapes, such as texts, polygons, boxes and paths and " + "converts them to corresponding items. The transformation argument can be used to " + "supply the transformation that applies the database unit for example.\n" + "\n" + "This method has been introduced in version 0.25.3.\n" + "\n" + "@param cell_id The ID of the cell to which the item is associated\n" + "@param category_id The ID of the category to which the item is associated\n" + "@param shapes The shape container from which to take the items\n" + "@param trans The transformation to apply\n" + ) + gsi::method_ext ("create_items", &create_items_from_region, "@brief Creates new polygon items for the given cell/category combination\n" "For each polygon in the region a single item will be created. The value of the item will be this " diff --git a/src/rdb/rdb/rdb.cc b/src/rdb/rdb/rdb.cc index dfcb41f69..b62b16292 100644 --- a/src/rdb/rdb/rdb.cc +++ b/src/rdb/rdb/rdb.cc @@ -33,6 +33,7 @@ #include "dbEdgePair.h" #include "dbPath.h" #include "dbText.h" +#include "dbShape.h" #include #include @@ -250,6 +251,38 @@ ValueBase::create_from_string (tl::Extractor &ex) } } +ValueBase * +ValueBase::create_from_shape (const db::Shape &shape, const db::CplxTrans &trans) +{ + if (shape.is_polygon () || shape.is_box ()) { + + db::Polygon poly; + shape.polygon (poly); + return new rdb::Value (poly.transformed (trans)); + + } else if (shape.is_path ()) { + + db::Path path; + shape.path (path); + return new rdb::Value (path.transformed (trans)); + + } else if (shape.is_text ()) { + + db::Text text; + shape.text (text); + return new rdb::Value (text.transformed (trans)); + + } else if (shape.is_edge ()) { + + db::Edge edge; + shape.edge (edge); + return new rdb::Value (edge.transformed (trans)); + + } else { + return 0; + } +} + // ------------------------------------------------------------------------------------------ // ValueWrapper implementation diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index ae401399f..10e20a600 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -44,6 +44,11 @@ namespace tl class Extractor; } +namespace db +{ + class Shape; +} + namespace rdb { @@ -441,6 +446,8 @@ public: static ValueBase *create_from_string (const std::string &s); static ValueBase *create_from_string (tl::Extractor &ex); + + static ValueBase *create_from_shape (const db::Shape &shape, const db::CplxTrans &trans); }; /** diff --git a/testdata/ruby/rdbTest.rb b/testdata/ruby/rdbTest.rb index f5055fb6e..b19621ddb 100644 --- a/testdata/ruby/rdbTest.rb +++ b/testdata/ruby/rdbTest.rb @@ -450,15 +450,22 @@ class RDB_TestClass < TestBase item.add_value(RBA::DBox::new(11, 12, 13, 14)) item.add_value(RBA::DEdge::new(21, 22, 23, 24)) item.add_value(RBA::DEdgePair::new(RBA::DEdge::new(31, 32, 33, 34), RBA::DEdge::new(41, 42, 43, 44))) + shapes = RBA::Shapes::new + pts = [ RBA::Point::new(0, 0), RBA::Point::new(50, 150) ] + shapes.insert(RBA::Path::new(pts, 100)) + shapes.each do |s| + item.add_value(s, RBA::CplxTrans::new(0.001)) + end vv=[] item.each_value { |v| vv.push(v) } - assert_equal(vv.size, 6) + assert_equal(vv.size, 7) assert_equal(vv[0].to_s, "float: 1") assert_equal(vv[1].to_s, "text: hello") assert_equal(vv[2].to_s, "polygon: (1,2;1,4;3,4;3,2)") assert_equal(vv[3].to_s, "box: (11,12;13,14)") assert_equal(vv[4].to_s, "edge: (21,22;23,24)") assert_equal(vv[5].to_s, "edge-pair: (31,32;33,34)/(41,42;43,44)") + assert_equal(vv[6].to_s, "path: (0,0;0.05,0.15) w=0.1 bx=0 ex=0 r=false") end @@ -761,6 +768,64 @@ class RDB_TestClass < TestBase rdb.each_cell { |c| cn << c.to_s_items } assert_equal(cn.join(";"), "c1[polygon: (0,0.001;0,0.03;0.02,0.03;0.02,0.001),polygon: (0.01,0.021;0.01,0.051;0.031,0.051;0.031,0.021),polygon: (0.021,0.042;0.021,0.073;0.043,0.073;0.043,0.042)]") + rdb = RBA::ReportDatabase.new("neu") + cat = rdb.create_category("l1") + cat.scan_shapes(c1.begin_shapes_rec(l1)) + assert_equal(cat.num_items, 3) + cn = [] + rdb.each_cell { |c| cn << c.to_s_test } + assert_equal(cn.join(";"), "c1[]") + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[polygon: (0,0.001;0,0.03;0.02,0.03;0.02,0.001),polygon: (0.01,0.021;0.01,0.051;0.031,0.051;0.031,0.021),polygon: (0.021,0.042;0.021,0.073;0.043,0.073;0.043,0.042)]") + + end + + # shape insertion from shape, shapes, recursive iterator + def test_12 + + ly = RBA::Layout::new + c0 = ly.create_cell("c0") + c1 = ly.create_cell("c1") + c2 = ly.create_cell("c2") + c3 = ly.create_cell("c3") + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(10, 20))) + c2.insert(RBA::CellInstArray::new(c3.cell_index, RBA::Trans::new(11, 21))) + l1 = ly.insert_layer(RBA::LayerInfo::new(1, 0)) + c0.shapes(l1).insert(RBA::Box::new(0, 1, 2, 3)) + c1.shapes(l1).insert(RBA::Text::new("Hello, world!", RBA::Trans::new)) + c2.shapes(l1).insert(RBA::Edge::new(0, 1, 21, 31)) + c3.shapes(l1).insert(RBA::Polygon::new(RBA::Box::new(0, 1, 22, 32))) + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + c0.shapes(l1).each do |s| + rdb.create_item(cell1.rdb_id, cat1.rdb_id, s, RBA::CplxTrans::new(ly.dbu)) + end + assert_equal(cat1.num_items, 1) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[polygon: (0,0.001;0,0.003;0.002,0.003;0.002,0.001)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, c0.shapes(l1), RBA::CplxTrans::new(ly.dbu)) + assert_equal(cat1.num_items, 1) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[polygon: (0,0.001;0,0.003;0.002,0.003;0.002,0.001)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, c1.begin_shapes_rec(l1)) + assert_equal(cat1.num_items, 3) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[label: ('Hello, world!',r0 0,0),edge: (0.01,0.021;0.031,0.051),polygon: (0.021,0.042;0.021,0.073;0.043,0.073;0.043,0.042)]") + end end