diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index e272e25ca..d15bb3601 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -332,6 +332,12 @@ const db::Text *DeepTexts::nth (size_t) const throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat text collections"))); } +db::properties_id_type +DeepTexts::nth_prop_id (size_t) const +{ + throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat collections"))); +} + bool DeepTexts::has_valid_texts () const { return false; diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index 7425df7cd..0c9a6eabb 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -71,6 +71,7 @@ public: virtual Box bbox () const; virtual bool empty () const; virtual const db::Text *nth (size_t n) const; + virtual db::properties_id_type nth_prop_id (size_t n) const; virtual bool has_valid_texts () const; virtual const db::RecursiveShapeIterator *iter () const; virtual void apply_property_translator (const db::PropertiesTranslator &pt); diff --git a/src/db/db/dbEmptyTexts.h b/src/db/db/dbEmptyTexts.h index 37cdd6725..202a72399 100644 --- a/src/db/db/dbEmptyTexts.h +++ b/src/db/db/dbEmptyTexts.h @@ -71,6 +71,7 @@ public: virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); } virtual const db::Text *nth (size_t) const { tl_assert (false); } + virtual db::properties_id_type nth_prop_id (size_t) const { tl_assert (false); } virtual bool has_valid_texts () const { return true; } virtual const db::RecursiveShapeIterator *iter () const { return 0; } diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc index e2e0e54a2..ef6dda20d 100644 --- a/src/db/db/dbFlatTexts.cc +++ b/src/db/db/dbFlatTexts.cc @@ -171,7 +171,46 @@ TextsDelegate *FlatTexts::add_in_place (const Texts &other) const db::Text *FlatTexts::nth (size_t n) const { - return n < mp_texts->size () ? &mp_texts->get_layer ().begin () [n] : 0; + // NOTE: this assumes that we iterate over non-property texts first and then over texts with properties + + if (n >= mp_texts->size ()) { + return 0; + } + + const db::layer &l = mp_texts->get_layer (); + if (n < l.size ()) { + return &l.begin () [n]; + } + n -= l.size (); + + const db::layer &lp = mp_texts->get_layer (); + if (n < lp.size ()) { + return &lp.begin () [n]; + } + + return 0; +} + +db::properties_id_type FlatTexts::nth_prop_id (size_t n) const +{ + // NOTE: this assumes that we iterate over non-property polygons first and then over polygons with properties + + if (n >= mp_texts->size ()) { + return 0; + } + + const db::layer &l = mp_texts->get_layer (); + if (n < l.size ()) { + return 0; + } + n -= l.size (); + + const db::layer &lp = mp_texts->get_layer (); + if (n < lp.size ()) { + return lp.begin () [n].properties_id (); + } + + return 0; } bool FlatTexts::has_valid_texts () const diff --git a/src/db/db/dbFlatTexts.h b/src/db/db/dbFlatTexts.h index f7e5ff16c..553dd58d5 100644 --- a/src/db/db/dbFlatTexts.h +++ b/src/db/db/dbFlatTexts.h @@ -76,6 +76,7 @@ public: virtual TextsDelegate *add (const Texts &other) const; virtual const db::Text *nth (size_t n) const; + virtual db::properties_id_type nth_prop_id (size_t n) const; virtual bool has_valid_texts () const; virtual const db::RecursiveShapeIterator *iter () const; diff --git a/src/db/db/dbOriginalLayerTexts.cc b/src/db/db/dbOriginalLayerTexts.cc index e4f53eb27..af633ebe5 100644 --- a/src/db/db/dbOriginalLayerTexts.cc +++ b/src/db/db/dbOriginalLayerTexts.cc @@ -190,6 +190,12 @@ OriginalLayerTexts::nth (size_t) const throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat collections"))); } +db::properties_id_type +OriginalLayerTexts::nth_prop_id (size_t) const +{ + throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat collections"))); +} + bool OriginalLayerTexts::has_valid_texts () const { diff --git a/src/db/db/dbOriginalLayerTexts.h b/src/db/db/dbOriginalLayerTexts.h index d294e2803..81971bd44 100644 --- a/src/db/db/dbOriginalLayerTexts.h +++ b/src/db/db/dbOriginalLayerTexts.h @@ -53,6 +53,7 @@ public: virtual bool empty () const; virtual const db::Text *nth (size_t n) const; + virtual db::properties_id_type nth_prop_id (size_t n) const; virtual bool has_valid_texts () const; virtual const db::RecursiveShapeIterator *iter () const; diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index a948f3366..51b05a5d6 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -495,7 +495,7 @@ public: /** * @brief Returns the nth text * - * This operation is available only for flat regions - i.e. such for which + * This operation is available only for flat text collections - i.e. such for which * "has_valid_texts" is true. */ const db::Text *nth (size_t n) const @@ -503,6 +503,17 @@ public: return mp_delegate->nth (n); } + /** + * @brief Returns the nth text's property ID + * + * This operation is available only for flat text collections - i.e. such for which + * "has_valid_texts" is true. + */ + db::properties_id_type nth_prop_id (size_t n) const + { + return mp_delegate->nth_prop_id (n); + } + /** * @brief Forces flattening of the text collection * diff --git a/src/db/db/dbTextsDelegate.h b/src/db/db/dbTextsDelegate.h index 4808e9679..895b1808e 100644 --- a/src/db/db/dbTextsDelegate.h +++ b/src/db/db/dbTextsDelegate.h @@ -109,6 +109,7 @@ public: virtual TextsDelegate *in (const Texts &other, bool invert) const = 0; virtual const db::Text *nth (size_t n) const = 0; + virtual db::properties_id_type nth_prop_id (size_t n) const = 0; virtual bool has_valid_texts () const = 0; virtual const db::RecursiveShapeIterator *iter () const = 0; diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc index 2a50e6747..282c917a8 100644 --- a/src/db/db/gsiDeclDbEdgePairs.cc +++ b/src/db/db/gsiDeclDbEdgePairs.cc @@ -783,6 +783,17 @@ static std::vector split_with_area2 (const db::EdgePairs *r, db:: return as_2edge_pairs_vector (r->split_filter (f)); } +static tl::Variant nth (const db::EdgePairs *edge_pairs, size_t n) +{ + const db::EdgePair *ep = edge_pairs->nth (n); + if (! ep) { + return tl::Variant (); + } else { + // @@@ return tl::Variant (db::EdgePairWithProperties (*ep, edge_pairs->nth_prop_id (n))); + return tl::Variant (); // @@@ + } +} + static db::generic_shape_iterator begin_edge_pairs (const db::EdgePairs *edge_pairs) { return db::generic_shape_iterator (db::make_wp_iter (edge_pairs->delegate ()->begin ())); @@ -1855,13 +1866,15 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", "\n" "Starting with version 0.30, the iterator delivers EdgePairWithProperties objects." ) + - method ("[]", &db::EdgePairs::nth, gsi::arg ("n"), + method_ext ("[]", &nth, gsi::arg ("n"), "@brief Returns the nth edge pair\n" "\n" "This method returns nil if the index is out of range. It is available for flat edge pairs only - i.e. " "those for which \\has_valid_edge_pairs? is true. Use \\flatten to explicitly flatten an edge pair collection.\n" "\n" - "The \\each iterator is the more general approach to access the edge pairs." + "The \\each iterator is the more general approach to access the edge pairs.\n" + "\n" + "Since version 0.30.1, this method returns a \\EdgePairWithProperties object." ) + method ("flatten", &db::EdgePairs::flatten, "@brief Explicitly flattens an edge pair collection\n" diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index d4da722f4..3eb98edc0 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -848,6 +848,17 @@ static std::vector split_interacting_with_region (const db::Edges *r, return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count)); } +static tl::Variant nth (const db::Edges *edges, size_t n) +{ + const db::Edge *e = edges->nth (n); + if (! e) { + return tl::Variant (); + } else { + // @@@ return tl::Variant (db::EdgeWithProperties (*e, edges->nth_prop_id (n))); + return tl::Variant (); // @@@ + } +} + static db::generic_shape_iterator begin_edges (const db::Edges *edges) { return db::generic_shape_iterator (db::make_wp_iter (edges->delegate ()->begin ())); @@ -2439,14 +2450,16 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges", "This method has been introduced in version 0.25." "Starting with version 0.30, the iterator delivers an EdgeWithProperties object." ) + - method ("[]", &db::Edges::nth, gsi::arg ("n"), + method_ext ("[]", &nth, gsi::arg ("n"), "@brief Returns the nth edge of the collection\n" "\n" "This method returns nil if the index is out of range. It is available for flat edge collections only - i.e. " "those for which \\has_valid_edges? is true. Use \\flatten to explicitly flatten an edge collection.\n" "This method returns the raw edge (not merged edges, even if merged semantics is enabled).\n" "\n" - "The \\each iterator is the more general approach to access the edges." + "The \\each iterator is the more general approach to access the edges.\n" + "\n" + "Since version 0.30.1, this method returns an \\EdgeWithProperties object." ) + method ("flatten", &db::Edges::flatten, "@brief Explicitly flattens an edge collection\n" diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 66e1d34a6..17a9563c9 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -455,6 +455,16 @@ static db::Region pull_interacting (const db::Texts *r, const db::Region &other) return out; } +static tl::Variant nth (const db::Texts *texts, size_t n) +{ + const db::Text *t = texts->nth (n); + if (! t) { + return tl::Variant (); + } else { + return tl::Variant (db::TextWithProperties (*t, texts->nth_prop_id (n))); + } +} + static db::generic_shape_iterator begin_texts (const db::Texts *texts) { return db::generic_shape_iterator (db::make_wp_iter (texts->delegate ()->begin ())); @@ -846,13 +856,15 @@ Class decl_Texts (decl_dbShapeCollection, "db", "Texts", "\n" "Starting with version 0.30, the iterator delivers TextWithProperties objects." ) + - method ("[]", &db::Texts::nth, gsi::arg ("n"), + method_ext ("[]", &nth, gsi::arg ("n"), "@brief Returns the nth text\n" "\n" "This method returns nil if the index is out of range. It is available for flat texts only - i.e. " "those for which \\has_valid_texts? is true. Use \\flatten to explicitly flatten an text collection.\n" "\n" - "The \\each iterator is the more general approach to access the texts." + "The \\each iterator is the more general approach to access the texts.\n" + "\n" + "Since version 0.30.1, this method returns a \\TextWithProperties object." ) + method ("flatten", &db::Texts::flatten, "@brief Explicitly flattens an text collection\n" diff --git a/src/db/unit_tests/dbTextsTests.cc b/src/db/unit_tests/dbTextsTests.cc index 2fc3e652b..e7666647e 100644 --- a/src/db/unit_tests/dbTextsTests.cc +++ b/src/db/unit_tests/dbTextsTests.cc @@ -307,3 +307,22 @@ TEST(9_polygons) EXPECT_EQ (r.to_string (), "(9,19;9,21;11,21;11,19){17=>ABC};(-11,-21;-11,-19;-9,-19;-9,-21){17=>XZY}"); } +TEST(10_properties) +{ + db::PropertiesSet ps; + + ps.insert (tl::Variant ("id"), 1); + db::properties_id_type pid1 = db::properties_id (ps); + + db::Texts texts; + texts.insert (db::TextWithProperties (db::Text ("string", db::Trans ()), pid1)); + texts.insert (db::Text ("abc", db::Trans ())); + + EXPECT_EQ (texts.nth (0)->to_string (), "('abc',r0 0,0)"); + EXPECT_EQ (texts.nth (1)->to_string (), "('string',r0 0,0)"); + EXPECT_EQ (texts.nth (2) == 0, true); + + EXPECT_EQ (texts.nth_prop_id (0), db::properties_id_type (0)); + EXPECT_EQ (texts.nth_prop_id (1), pid1); +} + diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index e92798056..9ccdadf82 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -233,7 +233,9 @@ class DBRegion_TestClass < TestBase r = RBA::Region::new r.insert(RBA::PolygonWithProperties::new(RBA::Box::new(0, 0, 10, 20), { 1 => 'value' })) - assert_equal(r[0].to_s, "(0,0;0,20;10,20;10,0) props={1=>value}") + r.insert(RBA::Box::new(1, 2, 11, 22)) + assert_equal(r[0].to_s, "@@@") + assert_equal(r[1].to_s, "(0,0;0,20;10,20;10,0) props={1=>value}") r = RBA::Region::new(ly.begin_shapes(c1.cell_index, l2), "*") assert_equal(csort(r.to_s), csort("(-11,-21;-11,-19;-9,-19;-9,-21);(9,19;9,21;11,21;11,19);(-11,79;-11,81;-9,81;-9,79);(9,119;9,121;11,121;11,119);(189,79;189,81;191,81;191,79);(209,119;209,121;211,121;211,119)")) diff --git a/testdata/ruby/dbTextsTest.rb b/testdata/ruby/dbTextsTest.rb index 145379068..4f481ef3f 100644 --- a/testdata/ruby/dbTextsTest.rb +++ b/testdata/ruby/dbTextsTest.rb @@ -103,7 +103,7 @@ class DBTexts_TestClass < TestBase assert_equal(r.is_empty?, false) assert_equal(r.count, 1) assert_equal(r.hier_count, 1) - assert_equal(r[0].to_s, "('uvw',r0 110,210)") + assert_equal(r[0].to_s, "('uvw',r0 110,210) props={}") assert_equal(r[1].to_s, "") assert_equal(r.bbox.to_s, "(110,210;110,210)") @@ -223,9 +223,13 @@ class DBTexts_TestClass < TestBase r.flatten assert_equal(r.has_valid_texts?, true) - assert_equal(r[1].to_s, "('abc',r0 100,-100)") + assert_equal(r[1].to_s, "('abc',r0 100,-100) props={}") assert_equal(r[100].inspect, "nil") assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + r = RBA::Texts::new + r.insert(RBA::TextWithProperties::new(RBA::Text::new("string", RBA::Trans::new), { 1 => "value" })) + assert_equal(r[0].to_s, "('string',r0 0,0) props={1=>value}") dss = RBA::DeepShapeStore::new r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1), dss)