From 1bd1bb06ce5d06fd9c2fccabfa8b0de06983328b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 2 Feb 2025 17:00:31 +0100 Subject: [PATCH] More support for objects with properties: RDB integration. --- src/db/db/dbObjectWithProperties.cc | 93 ++++++++++++++++-- src/db/db/dbObjectWithProperties.h | 52 ++++++++++ src/db/db/gsiDeclDbPropertiesSupport.h | 15 +++ .../unit_tests/dbObjectWithPropertiesTests.cc | 53 ++++++++++ src/db/unit_tests/unit_tests.pro | 1 + src/rdb/rdb/gsiDeclRdb.cc | 51 ++++++++++ src/rdb/rdb/rdb.h | 10 ++ src/rdb/rdb/rdbUtils.cc | 28 +++--- src/rdb/rdb/rdbUtils.h | 25 +++++ testdata/ruby/dbPolygonTest.rb | 16 +++ testdata/ruby/rdbTest.rb | 97 +++++++++++++++++++ 11 files changed, 420 insertions(+), 21 deletions(-) create mode 100644 src/db/unit_tests/dbObjectWithPropertiesTests.cc diff --git a/src/db/db/dbObjectWithProperties.cc b/src/db/db/dbObjectWithProperties.cc index fd2d68749..e30373fa2 100644 --- a/src/db/db/dbObjectWithProperties.cc +++ b/src/db/db/dbObjectWithProperties.cc @@ -21,14 +21,6 @@ */ #include "dbObjectWithProperties.h" -#include "dbUserObject.h" -#include "dbText.h" -#include "dbPolygon.h" -#include "dbBox.h" -#include "dbPath.h" -#include "dbPoint.h" -#include "dbEdge.h" -#include "dbEdgePair.h" namespace db { @@ -56,3 +48,88 @@ template class db::object_with_properties; template class db::object_with_properties; } + +namespace tl +{ + +template bool _test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) +{ + if (! tl::test_extractor_impl (ex, (T &) p)) { + return false; + } + + if (ex.test ("props")) { + + if (! ex.test ("=")) { + return false; + } + + tl::Variant v; + if (! tl::test_extractor_impl (ex, v)) { + return false; + } + if (! v.is_array ()) { + return false; + } + + db::PropertiesSet props; + for (auto i = v.begin_array (); i != v.end_array (); ++i) { + props.insert (i->first, i->second); + } + + p.properties_id (db::properties_id (props)); + + } + + return true; +} + +template void _extractor_impl (tl::Extractor &ex, db::object_with_properties &p) +{ + if (! test_extractor_impl (ex, p)) { + ex.error (tl::to_string (tr ("Expected a shape specification with properties"))); + } +} + +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } + +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } +template <> bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { return _test_extractor_impl (ex, p); } + +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } + +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } +template <> void extractor_impl (tl::Extractor &ex, db::object_with_properties &p) { _extractor_impl (ex, p); } + +} + diff --git a/src/db/db/dbObjectWithProperties.h b/src/db/db/dbObjectWithProperties.h index 03242ac61..9ab320b23 100644 --- a/src/db/db/dbObjectWithProperties.h +++ b/src/db/db/dbObjectWithProperties.h @@ -26,7 +26,9 @@ #include "tlException.h" #include "tlTypeTraits.h" +#include "tlString.h" #include "dbTypes.h" +#include "dbUserObject.h" #include "dbPolygon.h" #include "dbPath.h" #include "dbEdge.h" @@ -340,5 +342,55 @@ operator<< (std::ostream &os, const object_with_properties &p) } // namespace db + +namespace tl +{ + +/** + * @brief Special extractors + */ + +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); + +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::object_with_properties &p); + +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); + +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); +template <> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::object_with_properties &p); + +} // namespace tl + #endif diff --git a/src/db/db/gsiDeclDbPropertiesSupport.h b/src/db/db/gsiDeclDbPropertiesSupport.h index a97b687bc..f1780458b 100644 --- a/src/db/db/gsiDeclDbPropertiesSupport.h +++ b/src/db/db/gsiDeclDbPropertiesSupport.h @@ -132,10 +132,25 @@ static T moved_xy_meth_impl (const T *s, typename T::coord_type dx, typename T:: return s->moved (typename T::vector_type (dx, dy)); } +template +struct downcast_impl_helper; + +template +struct downcast_impl_helper > +{ + static T impl (const db::object_with_properties *obj) + { + return *obj; + } +}; + template static gsi::Methods properties_support_methods () { return + gsi::method_ext ("downcast", &downcast_impl_helper::impl, + "@brief Gets the corresponding object without the properties\n" + ) + gsi::method ("prop_id", (db::properties_id_type (T::*) () const) &T::properties_id, "@brief Gets the properties ID associated with the object\n" ) + diff --git a/src/db/unit_tests/dbObjectWithPropertiesTests.cc b/src/db/unit_tests/dbObjectWithPropertiesTests.cc new file mode 100644 index 000000000..c06a78800 --- /dev/null +++ b/src/db/unit_tests/dbObjectWithPropertiesTests.cc @@ -0,0 +1,53 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbObjectWithProperties.h" +#include "tlUnitTest.h" + +namespace { + +TEST(1) +{ + db::PropertiesSet ps; + ps.insert (tl::Variant (1), tl::Variant ("one")); + ps.insert (tl::Variant ("key"), tl::Variant (42.0)); + + db::PolygonWithProperties pwp (db::Polygon (db::Box (0, 0, 100, 200)), db::properties_id (ps)); + + EXPECT_EQ (pwp.to_string (), "(0,0;0,200;100,200;100,0) props={1=>one,key=>42}"); + + db::PolygonWithProperties pwp2; + + std::string s; + tl::Extractor ex (s.c_str ()); + + EXPECT_EQ (ex.try_read (pwp2), false); + + s = " (0,0;0,200;100,200;100,0) props= {1 => \"one\", key => 42} "; + ex = tl::Extractor (s.c_str ()); + + EXPECT_EQ (ex.try_read (pwp2), true); + EXPECT_EQ (pwp2.to_string (), "(0,0;0,200;100,200;100,0) props={1=>one,key=>42}"); +} + +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 67e131894..7363746df 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -11,6 +11,7 @@ SOURCES = \ dbEdgeNeighborhoodTests.cc \ dbFillToolTests.cc \ dbLogTests.cc \ + dbObjectWithPropertiesTests.cc \ dbRecursiveInstanceIteratorTests.cc \ dbRegionCheckUtilsTests.cc \ dbTriangleTests.cc \ diff --git a/src/rdb/rdb/gsiDeclRdb.cc b/src/rdb/rdb/gsiDeclRdb.cc index 78dc7a243..10307e96f 100644 --- a/src/rdb/rdb/gsiDeclRdb.cc +++ b/src/rdb/rdb/gsiDeclRdb.cc @@ -1211,6 +1211,21 @@ void create_items_from_edge_pair_array (rdb::Database *db, rdb::id_type cell_id, rdb::create_items_from_sequence (db, cell_id, cat_id, trans, collection.begin (), collection.end ()); } +void create_items_from_polygon_array_with_properties (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const std::vector &collection, bool with_properties) +{ + rdb::create_items_from_sequence_with_properties (db, cell_id, cat_id, trans, collection.begin (), collection.end (), with_properties); +} + +void create_items_from_edge_array_with_properties (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const std::vector &collection, bool with_properties) +{ + rdb::create_items_from_sequence_with_properties (db, cell_id, cat_id, trans, collection.begin (), collection.end (), with_properties); +} + +void create_items_from_edge_pair_array_with_properties (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const std::vector &collection, bool with_properties) +{ + rdb::create_items_from_sequence_with_properties (db, cell_id, cat_id, trans, collection.begin (), collection.end (), with_properties); +} + static rdb::Item *create_item (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id) { if (! db->cell_by_id (cell_id)) { @@ -1548,6 +1563,18 @@ Class decl_ReportDatabase ("rdb", "ReportDatabase", "@param trans The transformation to apply\n" "@param edges The list of edge pairs (an \\EdgePairs object) for which the items are created\n" ) + + gsi::method_ext ("create_items", &create_items_from_polygon_array_with_properties, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"), gsi::arg ("with_properties", true), + "@brief Creates new polygon items for the given cell/category combination\n" + "This version takes \\PolygonWithProperties objects. If \\with_properties is true (the default), the\n" + "properties are added to the item as tagged values.\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 trans The transformation to apply\n" + "@param polygons The list of polygons (with properties) for which the items are created\n" + "@param with_properties If true, the properties are transferred into the item as well" + "\n" + "This variant has been introduced in version 0.30." + ) + gsi::method_ext ("create_items", &create_items_from_polygon_array, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"), "@brief Creates new polygon items for the given cell/category combination\n" "For each polygon a single item will be created. The value of the item will be this " @@ -1562,6 +1589,18 @@ Class decl_ReportDatabase ("rdb", "ReportDatabase", "@param trans The transformation to apply\n" "@param polygons The list of polygons for which the items are created\n" ) + + gsi::method_ext ("create_items", &create_items_from_edge_array_with_properties, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"), gsi::arg ("with_properties", true), + "@brief Creates new edge items for the given cell/category combination\n" + "This version takes \\EdgeWithProperties objects. If \\with_properties is true (the default), the\n" + "properties are added to the item as tagged values.\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 trans The transformation to apply\n" + "@param polygons The list of edges (with properties) for which the items are created\n" + "@param with_properties If true, the properties are transferred into the item as well" + "\n" + "This variant has been introduced in version 0.30." + ) + gsi::method_ext ("create_items", &create_items_from_edge_array, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"), "@brief Creates new edge items for the given cell/category combination\n" "For each edge a single item will be created. The value of the item will be this " @@ -1576,6 +1615,18 @@ Class decl_ReportDatabase ("rdb", "ReportDatabase", "@param trans The transformation to apply\n" "@param edges The list of edges for which the items are created\n" ) + + gsi::method_ext ("create_items", &create_items_from_edge_pair_array_with_properties, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"), gsi::arg ("with_properties", true), + "@brief Creates new edge pair items for the given cell/category combination\n" + "This version takes \\EdgePairWithProperties objects. If \\with_properties is true (the default), the\n" + "properties are added to the item as tagged values.\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 trans The transformation to apply\n" + "@param polygons The list of edge pairs (with properties) for which the items are created\n" + "@param with_properties If true, the properties are transferred into the item as well" + "\n" + "This variant has been introduced in version 0.30." + ) + gsi::method_ext ("create_items", &create_items_from_edge_pair_array, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"), "@brief Creates new edge pair items for the given cell/category combination\n" "For each edge pair a single item will be created. The value of the item will be this " diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index 48d6e01db..b5c4e98a8 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -27,6 +27,7 @@ #include "rdbCommon.h" #include "dbTrans.h" +#include "dbObjectWithProperties.h" #include "gsi.h" #include "tlObject.h" #include "tlObjectCollection.h" @@ -532,6 +533,15 @@ RDB_PUBLIC_TEMPLATE ValueBase *make_value (const T &value) return new Value (value); } +/** + * @brief Type bindings + */ +template +RDB_PUBLIC_TEMPLATE ValueBase *make_value (const db::object_with_properties &value) +{ + return new Value (value); +} + /** * @brief A class encapsulating ValueBase pointer */ diff --git a/src/rdb/rdb/rdbUtils.cc b/src/rdb/rdb/rdbUtils.cc index 7478b897d..6d0181162 100644 --- a/src/rdb/rdb/rdbUtils.cc +++ b/src/rdb/rdb/rdbUtils.cc @@ -290,6 +290,19 @@ void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_ } } +void add_properties_to_item (rdb::Item *item, db::properties_id_type prop_id) +{ + if (! item->database ()) { + return; + } + + auto ps = db::properties (prop_id); + for (auto i = ps.begin (); i != ps.end (); ++i) { + id_type tag_id = item->database ()->tags ().tag (db::property_name (i->first).to_string (), true /*user tag*/).id (); + add_item_value (item, db::property_value (i->second), db::CplxTrans (), tag_id); + } +} + void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape, bool with_properties) { std::unique_ptr value (rdb::ValueBase::create_from_shape (shape, trans)); @@ -301,19 +314,8 @@ void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_ty item->values ().add (value.release ()); // translate properties - if (with_properties && shape.has_prop_id () && shape.shapes () && shape.shapes ()->cell ()) { - - const db::Layout *layout = shape.shapes ()->cell ()->layout (); - if (layout) { - - auto ps = db::properties (shape.prop_id ()); - for (auto i = ps.begin (); i != ps.end (); ++i) { - id_type tag_id = db->tags ().tag (db::property_name (i->first).to_string (), true /*user tag*/).id (); - add_item_value (item, db::property_value (i->second), trans, tag_id); - } - - } - + if (with_properties && shape.has_prop_id ()) { + add_properties_to_item (item, shape.prop_id ()); } } diff --git a/src/rdb/rdb/rdbUtils.h b/src/rdb/rdb/rdbUtils.h index 158553ed5..b65243b9f 100644 --- a/src/rdb/rdb/rdbUtils.h +++ b/src/rdb/rdb/rdbUtils.h @@ -109,6 +109,13 @@ RDB_PUBLIC void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_i */ RDB_PUBLIC void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape, bool with_properties = true); +/** + * @brief Adds properties to a RDB item + * + * The properties will be added as values with "tags" + */ +RDB_PUBLIC void add_properties_to_item (rdb::Item *item, db::properties_id_type prop_id); + /** * @brief Creates RDB items from a region * @@ -154,6 +161,24 @@ RDB_PUBLIC_TEMPLATE void create_items_from_sequence (rdb::Database *db, rdb::id_ } } +/** + * @brief Creates RDB items from a sequence of integer-type objects + * + * An arbitrary transformation can be applied to translate the shapes before turning them to items. + * This transformation is useful for providing the DBU-to-micron conversion. + */ +template +RDB_PUBLIC_TEMPLATE void create_items_from_sequence_with_properties (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const Trans &trans, Iter begin, Iter end, bool with_properties = true) +{ + for (Iter o = begin; o != end; ++o) { + rdb::Item *item = db->create_item (cell_id, cat_id); + item->values ().add (rdb::make_value (o->transformed (trans))); + if (with_properties && o->properties_id () != 0) { + add_properties_to_item (item, o->properties_id ()); + } + } +} + /** * @brief Creates a value from a tl::Variant * diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index 5c96489cd..114faf54d 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -914,6 +914,10 @@ class DBPolygon_TestClass < TestBase assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") assert_equal(s.property(1), nil) + # Test downcast + assert_equal(s.class.to_s, "RBA::PolygonWithProperties") + assert_equal(s.downcast.class.to_s, "RBA::Polygon") + s = RBA::DPolygonWithProperties::new assert_equal(s.to_s, "() props={}") @@ -932,6 +936,10 @@ class DBPolygon_TestClass < TestBase assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") assert_equal(s.property(1), nil) + # Test downcast + assert_equal(s.class.to_s, "RBA::DPolygonWithProperties") + assert_equal(s.downcast.class.to_s, "RBA::DPolygon") + s = RBA::SimplePolygonWithProperties::new assert_equal(s.to_s, "() props={}") @@ -950,6 +958,10 @@ class DBPolygon_TestClass < TestBase assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") assert_equal(s.property(1), nil) + # Test downcast + assert_equal(s.class.to_s, "RBA::SimplePolygonWithProperties") + assert_equal(s.downcast.class.to_s, "RBA::SimplePolygon") + s = RBA::DSimplePolygonWithProperties::new assert_equal(s.to_s, "() props={}") @@ -968,6 +980,10 @@ class DBPolygon_TestClass < TestBase assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}") assert_equal(s.property(1), nil) + # Test downcast + assert_equal(s.class.to_s, "RBA::DSimplePolygonWithProperties") + assert_equal(s.downcast.class.to_s, "RBA::DSimplePolygon") + end end diff --git a/testdata/ruby/rdbTest.rb b/testdata/ruby/rdbTest.rb index be37effa0..392e0cfa4 100644 --- a/testdata/ruby/rdbTest.rb +++ b/testdata/ruby/rdbTest.rb @@ -943,6 +943,103 @@ class RDB_TestClass < TestBase 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)]") + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ RBA::Polygon::new(RBA::Box::new(0, 0, 100, 200)), RBA::Polygon::new(RBA::Box::new(100, 200, 110, 210)) ]) + assert_equal(cat1.num_items, 2) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[polygon: (0,0;0,0.2;0.1,0.2;0.1,0),polygon: (0.1,0.2;0.1,0.21;0.11,0.21;0.11,0.2)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ RBA::Edge::new(0, 0, 100, 200), RBA::Edge::new(100, 200, 110, 210) ]) + assert_equal(cat1.num_items, 2) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[edge: (0,0;0.1,0.2),edge: (0.1,0.2;0.11,0.21)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 200), RBA::Edge::new(100, 200, 110, 210)) ]) + assert_equal(cat1.num_items, 1) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[edge-pair: (0,0;0.1,0.2)/(0.1,0.2;0.11,0.21)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ + RBA::PolygonWithProperties::new(RBA::Polygon::new(RBA::Box::new(0, 0, 100, 200)), { 1 => "one" }), + RBA::PolygonWithProperties::new(RBA::Polygon::new(RBA::Box::new(100, 200, 110, 210)), { 42 => 17 }) + ]) + assert_equal(cat1.num_items, 2) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[polygon: (0,0;0,0.2;0.1,0.2;0.1,0)/text: one,polygon: (0.1,0.2;0.1,0.21;0.11,0.21;0.11,0.2)/float: 17]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ + RBA::PolygonWithProperties::new(RBA::Polygon::new(RBA::Box::new(0, 0, 100, 200)), { 1 => "one" }), + RBA::PolygonWithProperties::new(RBA::Polygon::new(RBA::Box::new(100, 200, 110, 210)), { 42 => 17 }) + ], false) + assert_equal(cat1.num_items, 2) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[polygon: (0,0;0,0.2;0.1,0.2;0.1,0),polygon: (0.1,0.2;0.1,0.21;0.11,0.21;0.11,0.2)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ + RBA::EdgeWithProperties::new(RBA::Edge::new(0, 0, 100, 200), { 1 => "one" }), + RBA::EdgeWithProperties::new(RBA::Edge::new(100, 200, 110, 210), { 42 => 17 }) + ]) + assert_equal(cat1.num_items, 2) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[edge: (0,0;0.1,0.2)/text: one,edge: (0.1,0.2;0.11,0.21)/float: 17]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ + RBA::EdgeWithProperties::new(RBA::Edge::new(0, 0, 100, 200), { 1 => "one" }), + RBA::EdgeWithProperties::new(RBA::Edge::new(100, 200, 110, 210), { 42 => 17 }) + ], false) + assert_equal(cat1.num_items, 2) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[edge: (0,0;0.1,0.2),edge: (0.1,0.2;0.11,0.21)]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ + RBA::EdgePairWithProperties::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 200), RBA::Edge::new(100, 200, 110, 210)), { 1 => "one" }) + ]) + assert_equal(cat1.num_items, 1) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[edge-pair: (0,0;0.1,0.2)/(0.1,0.2;0.11,0.21)/text: one]") + + rdb = RBA::ReportDatabase.new("neu") + cat1 = rdb.create_category("l1") + cell1 = rdb.create_cell("c1") + rdb.create_items(cell1.rdb_id, cat1.rdb_id, RBA::CplxTrans::new(ly.dbu), [ + RBA::EdgePairWithProperties::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 200), RBA::Edge::new(100, 200, 110, 210)), { 1 => "one" }) + ], false) + assert_equal(cat1.num_items, 1) + cn = [] + rdb.each_cell { |c| cn << c.to_s_items } + assert_equal(cn.join(";"), "c1[edge-pair: (0,0;0.1,0.2)/(0.1,0.2;0.11,0.21)]") + end def test_13