Merge pull request #2006 from KLayout/bugfix/issue-2004

Bugfix/issue 2004
This commit is contained in:
Matthias Köfferlein 2025-04-05 19:21:05 +02:00 committed by GitHub
commit edcb283a87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 564 additions and 48 deletions

View File

@ -311,6 +311,11 @@ const db::EdgePair *DeepEdgePairs::nth (size_t) const
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat edge pair collections")));
}
db::properties_id_type DeepEdgePairs::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat edge pair collections")));
}
bool DeepEdgePairs::has_valid_edge_pairs () const
{
return false;

View File

@ -70,6 +70,7 @@ public:
virtual Box bbox () const;
virtual bool empty () const;
virtual const db::EdgePair *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edge_pairs () const;
virtual const db::RecursiveShapeIterator *iter () const;
virtual void apply_property_translator (const db::PropertiesTranslator &pt);

View File

@ -438,6 +438,12 @@ DeepEdges::nth (size_t /*n*/) const
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat edge collections")));
}
db::properties_id_type
DeepEdges::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat collections")));
}
bool
DeepEdges::has_valid_edges () const
{

View File

@ -76,6 +76,7 @@ public:
virtual bool is_merged () const;
virtual const db::Edge *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const;

View File

@ -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;

View File

@ -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);

View File

@ -678,7 +678,7 @@ public:
/**
* @brief Returns the nth edge pair
*
* This operation is available only for flat regions - i.e. such for which
* This operation is available only for flat edge pair collections - i.e. such for which
* "has_valid_edge_pairs" is true.
*/
const db::EdgePair *nth (size_t n) const
@ -686,6 +686,17 @@ public:
return mp_delegate->nth (n);
}
/**
* @brief Returns the nth edge pair's property ID
*
* This operation is available only for flat edge pair collections - i.e. such for which
* "has_valid_edge_pairs" 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 edge pair collection
*

View File

@ -273,6 +273,7 @@ public:
virtual EdgePairsDelegate *in (const EdgePairs &other, bool invert) const = 0;
virtual const db::EdgePair *nth (size_t n) const = 0;
virtual db::properties_id_type nth_prop_id (size_t n) const = 0;
virtual bool has_valid_edge_pairs () const = 0;
virtual const db::RecursiveShapeIterator *iter () const = 0;

View File

@ -1440,13 +1440,24 @@ public:
/**
* @brief Returns the nth edge
*
* This operation is available only for flat regions - i.e. such for which "has_valid_edges" is true.
* This operation is available only for flat edge collections - i.e. such for which "has_valid_edges" is true.
*/
const db::Edge *nth (size_t n) const
{
return mp_delegate->nth (n);
}
/**
* @brief Returns the nth edge's property ID
*
* This operation is available only for flat edge collections - i.e. such for which
* "has_valid_edges" 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 edge collection
*

View File

@ -280,6 +280,7 @@ public:
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const = 0;
virtual const db::Edge *nth (size_t n) const = 0;
virtual db::properties_id_type nth_prop_id (size_t n) const = 0;
virtual bool has_valid_edges () const = 0;
virtual bool has_valid_merged_edges () const = 0;

View File

@ -89,6 +89,7 @@ public:
virtual EdgePairsDelegate *in (const EdgePairs &, bool) const { return new EmptyEdgePairs (); }
virtual const db::EdgePair *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_edge_pairs () const { return true; }
virtual const db::RecursiveShapeIterator *iter () const { return 0; }

View File

@ -119,6 +119,7 @@ public:
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual const db::Edge *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_edges () const { return true; }
virtual bool has_valid_merged_edges () const { return true; }

View File

@ -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; }

View File

@ -173,7 +173,46 @@ EdgePairsDelegate *FlatEdgePairs::add_in_place (const EdgePairs &other)
const db::EdgePair *FlatEdgePairs::nth (size_t n) const
{
return n < mp_edge_pairs->size () ? &mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ().begin () [n] : 0;
// NOTE: this assumes that we iterate over non-property edge pairs first and then over edges with properties
if (n >= mp_edge_pairs->size ()) {
return 0;
}
const db::layer<db::EdgePair, db::unstable_layer_tag> &l = mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ();
if (n < l.size ()) {
return &l.begin () [n];
}
n -= l.size ();
const db::layer<db::EdgePairWithProperties, db::unstable_layer_tag> &lp = mp_edge_pairs->get_layer<db::EdgePairWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return &lp.begin () [n];
}
return 0;
}
db::properties_id_type FlatEdgePairs::nth_prop_id (size_t n) const
{
// NOTE: this assumes that we iterate over non-property edge pairs first and then over edges with properties
if (n >= mp_edge_pairs->size ()) {
return 0;
}
const db::layer<db::EdgePair, db::unstable_layer_tag> &l = mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ();
if (n < l.size ()) {
return 0;
}
n -= l.size ();
const db::layer<db::EdgePairWithProperties, db::unstable_layer_tag> &lp = mp_edge_pairs->get_layer<db::EdgePairWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return lp.begin () [n].properties_id ();
}
return 0;
}
bool FlatEdgePairs::has_valid_edge_pairs () const

View File

@ -75,6 +75,7 @@ public:
virtual EdgePairsDelegate *add (const EdgePairs &other) const;
virtual const db::EdgePair *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edge_pairs () const;
virtual const db::RecursiveShapeIterator *iter () const;

View File

@ -361,7 +361,46 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other)
const db::Edge *FlatEdges::nth (size_t n) const
{
return n < mp_edges->size () ? &mp_edges->get_layer<db::Edge, db::unstable_layer_tag> ().begin () [n] : 0;
// NOTE: this assumes that we iterate over non-property edges first and then over edges with properties
if (n >= mp_edges->size ()) {
return 0;
}
const db::layer<db::Edge, db::unstable_layer_tag> &l = mp_edges->get_layer<db::Edge, db::unstable_layer_tag> ();
if (n < l.size ()) {
return &l.begin () [n];
}
n -= l.size ();
const db::layer<db::EdgeWithProperties, db::unstable_layer_tag> &lp = mp_edges->get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return &lp.begin () [n];
}
return 0;
}
db::properties_id_type FlatEdges::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_edges->size ()) {
return 0;
}
const db::layer<db::Edge, db::unstable_layer_tag> &l = mp_edges->get_layer<db::Edge, db::unstable_layer_tag> ();
if (n < l.size ()) {
return 0;
}
n -= l.size ();
const db::layer<db::EdgeWithProperties, db::unstable_layer_tag> &lp = mp_edges->get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return lp.begin () [n].properties_id ();
}
return 0;
}
bool FlatEdges::has_valid_edges () const

View File

@ -89,6 +89,7 @@ public:
virtual EdgesDelegate *add (const Edges &other) const;
virtual const db::Edge *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const;

View File

@ -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<db::Text, db::unstable_layer_tag> ().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<db::Text, db::unstable_layer_tag> &l = mp_texts->get_layer<db::Text, db::unstable_layer_tag> ();
if (n < l.size ()) {
return &l.begin () [n];
}
n -= l.size ();
const db::layer<db::TextWithProperties, db::unstable_layer_tag> &lp = mp_texts->get_layer<db::TextWithProperties, db::unstable_layer_tag> ();
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<db::Text, db::unstable_layer_tag> &l = mp_texts->get_layer<db::Text, db::unstable_layer_tag> ();
if (n < l.size ()) {
return 0;
}
n -= l.size ();
const db::layer<db::TextWithProperties, db::unstable_layer_tag> &lp = mp_texts->get_layer<db::TextWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return lp.begin () [n].properties_id ();
}
return 0;
}
bool FlatTexts::has_valid_texts () const

View File

@ -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;

View File

@ -190,6 +190,12 @@ OriginalLayerEdgePairs::nth (size_t) const
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat collections")));
}
db::properties_id_type
OriginalLayerEdgePairs::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat collections")));
}
bool
OriginalLayerEdgePairs::has_valid_edge_pairs () const
{

View File

@ -53,6 +53,7 @@ public:
virtual bool empty () const;
virtual const db::EdgePair *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edge_pairs () const;
virtual const db::RecursiveShapeIterator *iter () const;

View File

@ -233,6 +233,12 @@ OriginalLayerEdges::nth (size_t) const
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat collections")));
}
db::properties_id_type
OriginalLayerEdges::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat collections")));
}
bool
OriginalLayerEdges::has_valid_edges () const
{

View File

@ -58,6 +58,7 @@ public:
virtual bool is_merged () const;
virtual const db::Edge *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const;

View File

@ -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
{

View File

@ -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;

View File

@ -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
*

View File

@ -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;

View File

@ -370,7 +370,7 @@ static db::DEdgePairWithProperties *new_dedge_pair_with_properties2 (const db::D
return new db::DEdgePairWithProperties (edge_pair, db::properties_id (db::PropertiesSet (properties.begin (), properties.end ())));
}
Class<db::DEdgePairWithProperties> decl_DEdgePairWithProperties (decl_EdgePair, "db", "DEdgePairWithProperties",
Class<db::DEdgePairWithProperties> decl_DEdgePairWithProperties (decl_DEdgePair, "db", "DEdgePairWithProperties",
gsi::properties_support_methods<db::DEdgePairWithProperties> () +
constructor ("new", &new_dedge_pair_with_properties, gsi::arg ("edge_pair"), gsi::arg ("properties_id", db::properties_id_type (0)),
"@brief Creates a new object from a property-less object and a properties ID."

View File

@ -783,6 +783,16 @@ static std::vector<db::EdgePairs> 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)));
}
}
static db::generic_shape_iterator<db::EdgePairWithProperties> begin_edge_pairs (const db::EdgePairs *edge_pairs)
{
return db::generic_shape_iterator<db::EdgePairWithProperties> (db::make_wp_iter (edge_pairs->delegate ()->begin ()));
@ -1855,13 +1865,15 @@ Class<db::EdgePairs> 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"

View File

@ -848,6 +848,16 @@ static std::vector<db::Edges> 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)));
}
}
static db::generic_shape_iterator<db::EdgeWithProperties> begin_edges (const db::Edges *edges)
{
return db::generic_shape_iterator<db::EdgeWithProperties> (db::make_wp_iter (edges->delegate ()->begin ()));
@ -2439,14 +2449,16 @@ Class<db::Edges> 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"

View File

@ -1379,6 +1379,16 @@ rasterize1 (const db::Region *region, const db::Point &origin, const db::Vector
return rasterize2 (region, origin, pixel_size, pixel_size, nx, ny);
}
static tl::Variant nth (const db::Region *region, size_t n)
{
const db::Polygon *poly = region->nth (n);
if (! poly) {
return tl::Variant ();
} else {
return tl::Variant (db::PolygonWithProperties (*poly, region->nth_prop_id (n)));
}
}
static db::generic_shape_iterator<db::PolygonWithProperties> begin_region (const db::Region *region)
{
return db::generic_shape_iterator<db::PolygonWithProperties> (db::make_wp_iter (region->delegate ()->begin ()));
@ -4103,14 +4113,16 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This returns the raw polygons if merged semantics is disabled or the merged ones if merged semantics is enabled.\n"
"Starting with version 0.30, the iterator delivers a RegionWithProperties object."
) +
method ("[]", &db::Region::nth, gsi::arg ("n"),
method_ext ("[]", &nth, gsi::arg ("n"),
"@brief Returns the nth polygon of the region\n"
"\n"
"This method returns nil if the index is out of range. It is available for flat regions only - i.e. "
"those for which \\has_valid_polygons? is true. Use \\flatten to explicitly flatten a region.\n"
"This method returns the raw polygon (not merged polygons, even if merged semantics is enabled).\n"
"\n"
"The \\each iterator is the more general approach to access the polygons."
"The \\each iterator is the more general approach to access the polygons.\n"
"\n"
"Since version 0.30.1, this method returns a \\PolygonWithProperties object."
) +
method ("flatten", &db::Region::flatten,
"@brief Explicitly flattens a region\n"

View File

@ -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<db::TextWithProperties> begin_texts (const db::Texts *texts)
{
return db::generic_shape_iterator<db::TextWithProperties> (db::make_wp_iter (texts->delegate ()->begin ()));
@ -846,13 +856,15 @@ Class<db::Texts> 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"

View File

@ -279,3 +279,24 @@ TEST(6_add_with_properties)
EXPECT_EQ ((ro1 + rf2).to_string (), "(10,20;-20,60)/(10,30;-20,70){net=>17};(-10,20;20,60)/(-10,30;20,70){net=>17}");
}
TEST(7_properties)
{
db::PropertiesSet ps;
ps.insert (tl::Variant ("id"), 1);
db::properties_id_type pid1 = db::properties_id (ps);
db::EdgePairs edge_pairs;
db::Edge e1 (db::Point (0, 0), db::Point (10, 20));
db::Edge e2 (db::Point (1, 2), db::Point (11, 22));
edge_pairs.insert (db::EdgePairWithProperties (db::EdgePair (e1, e2), pid1));
edge_pairs.insert (db::EdgePair (e1, e2));
EXPECT_EQ (edge_pairs.nth (0)->to_string (), "(0,0;10,20)/(1,2;11,22)");
EXPECT_EQ (edge_pairs.nth (1)->to_string (), "(0,0;10,20)/(1,2;11,22)");
EXPECT_EQ (edge_pairs.nth (2) == 0, true);
EXPECT_EQ (edge_pairs.nth_prop_id (0), db::properties_id_type (0));
EXPECT_EQ (edge_pairs.nth_prop_id (1), pid1);
}

View File

@ -1443,6 +1443,25 @@ TEST(32_add_with_properties)
EXPECT_EQ ((ro1 + rf2).to_string (), "(10,20;40,60){net=>17};(-10,20;20,60){net=>17}");
}
TEST(33_properties)
{
db::PropertiesSet ps;
ps.insert (tl::Variant ("id"), 1);
db::properties_id_type pid1 = db::properties_id (ps);
db::Edges edges;
edges.insert (db::EdgeWithProperties (db::Edge (db::Point (0, 0), db::Point (10, 20)), pid1));
edges.insert (db::Edge (db::Point (0, 0), db::Point (10, 20)));
EXPECT_EQ (edges.nth (0)->to_string (), "(0,0;10,20)");
EXPECT_EQ (edges.nth (1)->to_string (), "(0,0;10,20)");
EXPECT_EQ (edges.nth (2) == 0, true);
EXPECT_EQ (edges.nth_prop_id (0), db::properties_id_type (0));
EXPECT_EQ (edges.nth_prop_id (1), pid1);
}
// GitHub issue #72 (Edges/Region NOT issue)
TEST(100)
{

View File

@ -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);
}

View File

@ -952,9 +952,11 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
const tl::Variant *arg = i >= int (args.size ()) ? get_kwarg (*a, kwargs) : &args[i];
if (! arg) {
is_valid = a->spec ()->has_default ();
} else if (gsi::test_arg (*a, *arg, false /*strict*/)) {
} else if (gsi::test_arg (*a, *arg, false /*strict*/, false /*no object substitution*/)) {
sc += 100;
} else if (gsi::test_arg (*a, *arg, true /*loose*/, false /*no object substitution*/)) {
++sc;
} else if (test_arg (*a, *arg, true /*loose*/)) {
} else if (gsi::test_arg (*a, *arg, true /*loose*/, true /*with object substitution*/)) {
// non-scoring match
} else {
is_valid = false;

View File

@ -46,12 +46,12 @@ inline void *get_object (tl::Variant &var)
// -------------------------------------------------------------------
// Test if an argument can be converted to the given type
bool test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose);
bool test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose, bool object_substitution);
template <class R>
struct test_arg_func
{
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType & /*atype*/, bool /*loose*/)
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/)
{
*ret = arg.can_convert_to<R> ();
}
@ -60,7 +60,16 @@ struct test_arg_func
template <>
struct test_arg_func<gsi::VoidType>
{
void operator () (bool *ret, const tl::Variant & /*arg*/, const gsi::ArgType & /*atype*/, bool /*loose*/)
void operator () (bool *ret, const tl::Variant & /*arg*/, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/)
{
*ret = true;
}
};
template <>
struct test_arg_func<gsi::VariantType>
{
void operator () (bool *ret, const tl::Variant & /*arg*/, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/)
{
*ret = true;
}
@ -69,7 +78,7 @@ struct test_arg_func<gsi::VoidType>
template <>
struct test_arg_func<gsi::ObjectType>
{
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType &atype, bool loose)
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType &atype, bool loose, bool object_substitution)
{
// allow nil of pointers
if ((atype.is_ptr () || atype.is_cptr ()) && arg.is_nil ()) {
@ -77,7 +86,7 @@ struct test_arg_func<gsi::ObjectType>
return;
}
if (arg.is_list ()) {
if (object_substitution && arg.is_list ()) {
// we may implicitly convert an array into a constructor call of a target object -
// for now we only check whether the number of arguments is compatible with the array given.
@ -104,9 +113,9 @@ struct test_arg_func<gsi::ObjectType>
const tl::VariantUserClassBase *cls = arg.user_cls ();
if (! cls) {
*ret = false;
} else if (! cls->gsi_cls ()->is_derived_from (atype.cls ()) && (! loose || ! cls->gsi_cls ()->can_convert_to(atype.cls ()))) {
*ret = false;
} else if ((atype.is_ref () || atype.is_ptr ()) && cls->is_const ()) {
} else if (! (cls->gsi_cls () == atype.cls () ||
(loose && (cls->gsi_cls ()->is_derived_from (atype.cls ()) ||
(object_substitution && cls->gsi_cls ()->can_convert_to (atype.cls ())))))) {
*ret = false;
} else {
*ret = true;
@ -117,7 +126,7 @@ struct test_arg_func<gsi::ObjectType>
template <>
struct test_arg_func<gsi::VectorType>
{
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType &atype, bool loose)
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
{
if (! arg.is_list ()) {
*ret = false;
@ -129,7 +138,7 @@ struct test_arg_func<gsi::VectorType>
*ret = true;
for (tl::Variant::const_iterator v = arg.begin (); v != arg.end () && *ret; ++v) {
if (! test_arg (ainner, *v, loose)) {
if (! test_arg (ainner, *v, loose, true)) {
*ret = false;
}
}
@ -139,7 +148,7 @@ struct test_arg_func<gsi::VectorType>
template <>
struct test_arg_func<gsi::MapType>
{
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType &atype, bool loose)
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
{
// Note: delegating that to the function avoids "injected class name used as template template expression" warning
if (! arg.is_array ()) {
@ -152,16 +161,11 @@ struct test_arg_func<gsi::MapType>
const ArgType &ainner = *atype.inner ();
const ArgType &ainner_k = *atype.inner_k ();
if (! arg.is_list ()) {
*ret = false;
return;
}
*ret = true;
for (tl::Variant::const_array_iterator a = arg.begin_array (); a != arg.end_array () && *ret; ++a) {
if (! test_arg (ainner_k, a->first, loose)) {
if (! test_arg (ainner_k, a->first, loose, true)) {
*ret = false;
} else if (! test_arg (ainner, a->second, loose)) {
} else if (! test_arg (ainner, a->second, loose, true)) {
*ret = false;
}
}
@ -169,7 +173,7 @@ struct test_arg_func<gsi::MapType>
};
bool
test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose)
test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose, bool object_substitution)
{
// for const X * or X *, nil is an allowed value
if ((atype.is_cptr () || atype.is_ptr ()) && arg.is_nil ()) {
@ -177,7 +181,7 @@ test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose)
}
bool ret = false;
gsi::do_on_type<test_arg_func> () (atype.type (), &ret, arg, atype, loose);
gsi::do_on_type<test_arg_func> () (atype.type (), &ret, arg, atype, loose, object_substitution);
return ret;
}

View File

@ -70,10 +70,11 @@ GSI_PUBLIC void pull_arg (gsi::SerialArgs &retlist, const gsi::ArgType &atype, t
* @param atype The argument type
* @param arg The value to pass to it
* @param loose true for loose checking
* @param object_substitution true to substitute object arguments by lists (using constructor) or employing conversion constructors
*
* @return True, if the argument can be passed
*/
GSI_PUBLIC bool test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose);
GSI_PUBLIC bool test_arg (const gsi::ArgType &atype, const tl::Variant &arg, bool loose, bool object_substitution);
}

View File

@ -863,3 +863,38 @@ TEST(16)
}
}
// implicit conversions
TEST(17)
{
tl::Eval e;
tl::Variant v;
// smoke test
v = e.parse ("var rdb=ReportDatabase.new();"
"var cat=rdb.create_category('name');"
"var cell=rdb.create_cell('TOP');"
"var it=rdb.create_item(cell,cat);"
"var bwp=BoxWithProperties.new(Box.new(0,0,1,2), {1=>'value'});"
"it.add_value(bwp)").execute ();
v = e.parse ("var rdb=ReportDatabase.new();"
"var cat=rdb.create_category('name');"
"var cell=rdb.create_cell('TOP');"
"var it=rdb.create_item(cell,cat);"
"var bwp=DBoxWithProperties.new(DBox.new(0,0,1,2), {1=>'value'});"
"it.add_value(bwp)").execute ();
v = e.parse ("var rdb=ReportDatabase.new();"
"var cat=rdb.create_category('name');"
"var cell=rdb.create_cell('TOP');"
"var it=rdb.create_item(cell,cat);"
"var b=DBox.new(0,0,1,2);"
"it.add_value(b)").execute ();
v = e.parse ("var rdb=ReportDatabase.new();"
"var cat=rdb.create_category('name');"
"var cell=rdb.create_cell('TOP');"
"var it=rdb.create_item(cell,cat);"
"it.add_value(17.5)").execute ();
}

View File

@ -413,6 +413,8 @@ match_method (int mid, PyObject *self, PyObject *args, PyObject *kwargs, bool st
if (! arg) {
is_valid = a->spec ()->has_default ();
} else if (test_arg (*a, arg.get (), false /*strict*/, false /*object substitution*/)) {
sc += 100;
} else if (test_arg (*a, arg.get (), true /*loose*/, false /*object substitution*/)) {
++sc;
} else if (test_arg (*a, arg.get (), true /*loose*/, true /*object substitution*/)) {
// non-scoring match

View File

@ -1232,7 +1232,7 @@ struct test_arg_func<gsi::ObjectType>
return;
}
if (! (cls_decl == acls || (loose && (cls_decl->is_derived_from (atype.cls ()) || cls_decl->can_convert_to (atype.cls ()))))) {
if (! (cls_decl == acls || (loose && (cls_decl->is_derived_from (atype.cls ()) || (object_substitution && cls_decl->can_convert_to (atype.cls ())))))) {
*ret = false;
return;
}

View File

@ -539,6 +539,8 @@ private:
if (arg == Qundef) {
is_valid = a->spec ()->has_default ();
} else if (test_arg (*a, arg, false /*strict*/, false /*with object substitution*/)) {
sc += 100;
} else if (test_arg (*a, arg, true /*loose*/, false /*with object substitution*/)) {
++sc;
} else if (test_arg (*a, arg, true /*loose*/, true /*with object substitution*/)) {
// non-scoring match

View File

@ -1217,7 +1217,7 @@ struct test_arg_func<gsi::ObjectType>
// in loose mode (second pass) try to match the types via implicit constructors,
// in strict mode (first pass) require direct type match
if (p->cls_decl () == atype.cls () || (loose && (p->cls_decl ()->is_derived_from (atype.cls ()) || p->cls_decl ()->can_convert_to (atype.cls ())))) {
if (p->cls_decl () == atype.cls () || (loose && (p->cls_decl ()->is_derived_from (atype.cls ()) || (object_substitution && p->cls_decl ()->can_convert_to (atype.cls ()))))) {
// type matches: check constness
if ((atype.is_ref () || atype.is_ptr ()) && p->const_ref ()) {
*ret = false;

View File

@ -999,6 +999,11 @@ Class<rdb::Item> decl_RdbItem ("rdb", "RdbItem",
"@param value The box to add.\n"
"This method has been introduced in version 0.25 as a convenience method."
) +
gsi::method_ext ("add_value", &add_value_t<db::DText>, gsi::arg ("value"),
"@brief Adds a text object to the values of this item\n"
"@param value The text to add.\n"
"This method has been introduced in version 0.30.1 to support text objects with properties."
) +
gsi::method_ext ("add_value", &add_value_t<db::DEdge>, gsi::arg ("value"),
"@brief Adds an edge object to the values of this item\n"
"@param value The edge to add.\n"

View File

@ -972,6 +972,78 @@ class RDB_TestClass(unittest.TestCase):
_cat_same = None
self.assertEqual(_subcat.rdb_id(), _subcat_same.rdb_id())
def test_15(self):
p = pya.DPolygon(pya.DBox(0.5, 1, 2, 3))
pwp = pya.DPolygonWithProperties(p, { 1: "value" })
e = pya.DEdge(pya.DPoint(0, 0), pya.DPoint(1, 2))
ewp = pya.DEdgeWithProperties(e, { 1: "value" })
ep = pya.DEdgePair(e, e.moved(10, 10))
epwp = pya.DEdgePairWithProperties(ep, { 1: "value" })
t = pya.DText("text", pya.DTrans.R0)
twp = pya.DTextWithProperties(t, { 1: "value" })
b = pya.DBox(0, 0, 1, 2)
bwp = pya.DBoxWithProperties(b, { 1: "value" })
ip = pya.Polygon(pya.Box(0, 1, 2, 3))
ipwp = pya.PolygonWithProperties(ip, { 1: "value" })
ie = pya.Edge(pya.Point(0, 0), pya.Point(1, 2))
iewp = pya.EdgeWithProperties(ie, { 1: "value" })
iep = pya.EdgePair(ie, ie.moved(10, 10))
iepwp = pya.EdgePairWithProperties(iep, { 1: "value" })
it = pya.Text("text", pya.Trans.R0)
itwp = pya.TextWithProperties(it, { 1: "value" })
ib = pya.Box(0, 0, 1, 2)
ibwp = pya.BoxWithProperties(ib, { 1: "value" })
rdb = pya.ReportDatabase()
cat = rdb.create_category("name")
cell = rdb.create_cell("TOP")
item = rdb.create_item(cell, cat)
item.add_value(p)
item.add_value(pwp)
item.add_value(b)
item.add_value(bwp)
item.add_value(t)
item.add_value(twp)
item.add_value(e)
item.add_value(ewp)
item.add_value(ep)
item.add_value(epwp)
item.add_value(ip)
item.add_value(ipwp)
item.add_value(ib)
item.add_value(ibwp)
item.add_value(it)
item.add_value(itwp)
item.add_value(ie)
item.add_value(iewp)
item.add_value(iep)
item.add_value(iepwp)
item.add_value("string")
item.add_value(17.5)
values = [ str(v) for v in item.each_value() ]
self.assertEqual(values, [
'polygon: (0.5,1;0.5,3;2,3;2,1)', 'polygon: (0.5,1;0.5,3;2,3;2,1)',
'box: (0,0;1,2)', 'box: (0,0;1,2)',
"label: ('text',r0 0,0)", "label: ('text',r0 0,0)",
'edge: (0,0;1,2)', 'edge: (0,0;1,2)',
'edge-pair: (0,0;1,2)/(10,10;11,12)', 'edge-pair: (0,0;1,2)/(10,10;11,12)',
'polygon: (0,1;0,3;2,3;2,1)', 'polygon: (0,1;0,3;2,3;2,1)',
'box: (0,0;1,2)', 'box: (0,0;1,2)',
"label: ('text',r0 0,0)", "label: ('text',r0 0,0)",
'edge: (0,0;1,2)', 'edge: (0,0;1,2)',
'edge-pair: (0,0;1,2)/(10,10;11,12)', 'edge-pair: (0,0;1,2)/(10,10;11,12)',
'text: string',
'float: 17.5'
])
# run unit tests
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(RDB_TestClass)

View File

@ -111,7 +111,7 @@ class DBEdgePairs_TestClass < TestBase
assert_equal(csort(r.edges.to_s), csort("(0,0;0,100);(-10,0;-20,50)"))
assert_equal(r.is_empty?, false)
assert_equal(r.size, 1)
assert_equal(r[0].to_s, "(0,0;0,100)/(-10,0;-20,50)")
assert_equal(r[0].to_s, "(0,0;0,100)/(-10,0;-20,50) props={}")
assert_equal(r[1].to_s, "")
assert_equal(r.bbox.to_s, "(-20,0;0,100)")
@ -221,7 +221,7 @@ class DBEdgePairs_TestClass < TestBase
r.flatten
assert_equal(r.has_valid_edge_pairs?, true)
assert_equal(r[1].to_s, "(0,101;2,103)/(10,111;12,113)")
assert_equal(r[1].to_s, "(0,101;2,103)/(10,111;12,113) props={}")
assert_equal(r[100].inspect, "nil")
assert_equal(r.bbox.to_s, "(0,1;212,113)")
@ -622,6 +622,7 @@ class DBEdgePairs_TestClass < TestBase
r = RBA::EdgePairs::new([ RBA::EdgePairWithProperties::new(RBA::EdgePair::new(RBA::Edge::new(0, 0, 100, 100), RBA::Edge::new(200, 300, 200, 500)), { 1 => "one" }) ])
assert_equal(r.to_s, "(0,0;100,100)/(200,300;200,500){1=>one}")
assert_equal(r[0].to_s, "(0,0;100,100)/(200,300;200,500) props={1=>one}")
r = RBA::EdgePairs::new([])
assert_equal(r.to_s, "")

View File

@ -235,7 +235,7 @@ class DBEdges_TestClass < TestBase
assert_equal(r.is_empty?, false)
assert_equal(r.count, 12)
assert_equal(r.hier_count, 12)
assert_equal(r[1].to_s, "(-10,20;10,20)")
assert_equal(r[1].to_s, "(-10,20;10,20) props={}")
assert_equal(r[100].to_s, "")
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")
assert_equal(r.is_merged?, false)
@ -252,11 +252,11 @@ class DBEdges_TestClass < TestBase
r.flatten
assert_equal(r.has_valid_edges?, true)
assert_equal(r[1].to_s, "(-10,80;10,120)")
assert_equal(r[1].to_s, "(-10,80;10,120) props={}")
assert_equal(r[100].to_s, "")
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")
assert_equal(r.is_merged?, false)
r = RBA::Edges::new(ly.begin_shapes(c1.cell_index, l1), RBA::ICplxTrans::new(10, 20), true)
assert_equal(r.to_s(30), "(0,0;0,40);(0,40;20,40);(20,40;20,0);(20,0;0,0);(0,100;0,140);(0,140;20,140);(20,140;20,100);(20,100;0,100);(200,100;200,140);(200,140;220,140);(220,140;220,100);(220,100;200,100)")
assert_equal(r.is_empty?, false)
@ -970,6 +970,7 @@ class DBEdges_TestClass < TestBase
r = RBA::Edges::new([ RBA::EdgeWithProperties::new(RBA::Edge::new(0, 0, 100, 100), { 1 => "one" }) ])
assert_equal(r.to_s, "(0,0;100,100){1=>one}")
assert_equal(r[0].to_s, "(0,0;100,100) props={1=>one}")
r = RBA::Edges::new([])
assert_equal(r.to_s, "")

View File

@ -226,10 +226,16 @@ class DBRegion_TestClass < TestBase
r.flatten
assert_equal(r.has_valid_polygons?, true)
assert_equal(r[1].to_s, "(-10,80;-10,120;10,120;10,80)")
assert_equal(r[1].to_s, "(-10,80;-10,120;10,120;10,80) props={}")
assert_equal(r[4].to_s, "")
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")
assert_equal(r.is_merged?, false)
r = RBA::Region::new
r.insert(RBA::PolygonWithProperties::new(RBA::Box::new(0, 0, 10, 20), { 1 => 'value' }))
r.insert(RBA::Box::new(1, 2, 11, 22))
assert_equal(r[0].to_s, "(1,2;1,22;11,22;11,2) props={}")
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)"))

View File

@ -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)

View File

@ -1131,6 +1131,80 @@ class RDB_TestClass < TestBase
end
def test_15
p = RBA::DPolygon::new(RBA::DBox::new(0.5, 1, 2, 3))
pwp = RBA::DPolygonWithProperties::new(p, { 1 => "value" })
e = RBA::DEdge::new(RBA::DPoint::new(0, 0), RBA::DPoint::new(1, 2))
ewp = RBA::DEdgeWithProperties::new(e, { 1 => "value" })
ep = RBA::DEdgePair::new(e, e.moved(10, 10))
epwp = RBA::DEdgePairWithProperties::new(ep, { 1 => "value" })
t = RBA::DText::new("text", RBA::DTrans::R0)
twp = RBA::DTextWithProperties::new(t, { 1 => "value" })
b = RBA::DBox::new(0, 0, 1, 2)
bwp = RBA::DBoxWithProperties::new(b, { 1 => "value" })
ip = RBA::Polygon::new(RBA::Box::new(0, 1, 2, 3))
ipwp = RBA::PolygonWithProperties::new(ip, { 1 => "value" })
ie = RBA::Edge::new(RBA::Point::new(0, 0), RBA::Point::new(1, 2))
iewp = RBA::EdgeWithProperties::new(ie, { 1 => "value" })
iep = RBA::EdgePair::new(ie, ie.moved(10, 10))
iepwp = RBA::EdgePairWithProperties::new(iep, { 1 => "value" })
it = RBA::Text::new("text", RBA::Trans::R0)
itwp = RBA::TextWithProperties::new(it, { 1 => "value" })
ib = RBA::Box::new(0, 0, 1, 2)
ibwp = RBA::BoxWithProperties::new(ib, { 1 => "value" })
rdb = RBA::ReportDatabase::new
cat = rdb.create_category("name")
cell = rdb.create_cell("TOP")
item = rdb.create_item(cell, cat)
item.add_value(p)
item.add_value(pwp)
item.add_value(b)
item.add_value(bwp)
item.add_value(t)
item.add_value(twp)
item.add_value(e)
item.add_value(ewp)
item.add_value(ep)
item.add_value(epwp)
item.add_value(ip)
item.add_value(ipwp)
item.add_value(ib)
item.add_value(ibwp)
item.add_value(it)
item.add_value(itwp)
item.add_value(ie)
item.add_value(iewp)
item.add_value(iep)
item.add_value(iepwp)
item.add_value("string")
item.add_value(17.5)
values = item.each_value.collect(&:to_s)
assert_equal(values, [
'polygon: (0.5,1;0.5,3;2,3;2,1)', 'polygon: (0.5,1;0.5,3;2,3;2,1)',
'box: (0,0;1,2)', 'box: (0,0;1,2)',
"label: ('text',r0 0,0)", "label: ('text',r0 0,0)",
'edge: (0,0;1,2)', 'edge: (0,0;1,2)',
'edge-pair: (0,0;1,2)/(10,10;11,12)', 'edge-pair: (0,0;1,2)/(10,10;11,12)',
'polygon: (0,1;0,3;2,3;2,1)', 'polygon: (0,1;0,3;2,3;2,1)',
'box: (0,0;1,2)', 'box: (0,0;1,2)',
"label: ('text',r0 0,0)", "label: ('text',r0 0,0)",
'edge: (0,0;1,2)', 'edge: (0,0;1,2)',
'edge-pair: (0,0;1,2)/(10,10;11,12)', 'edge-pair: (0,0;1,2)/(10,10;11,12)',
'text: string',
'float: 17.5'
])
end
end
load("test_epilogue.rb")