Provide GSI bindings for the new edge pair support

This affects Shapes and Shape. New methods from EdgePairs are added
and minor enhancements of Region and Edges. Ruby tests added
This commit is contained in:
Matthias Koefferlein 2018-11-10 22:41:36 +01:00
parent 255abc5534
commit c91f54569a
22 changed files with 625 additions and 37 deletions

View File

@ -135,7 +135,8 @@ SOURCES = \
dbEmptyEdgePairs.cc \
dbFlatEdgePairs.cc \
dbOriginalLayerEdgePairs.cc \
dbEdgePairsDelegate.cc
dbEdgePairsDelegate.cc \
dbDeepShapeStore.cc
HEADERS = \
dbArray.h \
@ -240,7 +241,8 @@ HEADERS = \
dbEmptyEdgePairs.h \
dbFlatEdgePairs.h \
dbOriginalLayerEdgePairs.h \
dbEdgePairsDelegate.h
dbEdgePairsDelegate.h \
dbDeepShapeStore.h
!equals(HAVE_QT, "0") {

View File

@ -781,7 +781,7 @@ EdgesDelegate *
AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
{
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
EdgeBooleanClusterCollector<FlatEdges> cluster_collector (output.get (), op);
EdgeBooleanClusterCollector<db::Shapes> cluster_collector (&output->raw_edges (), op);
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + (other ? other->size () : 0));

View File

@ -0,0 +1,24 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
// ...

View File

@ -0,0 +1,122 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#ifndef HDR_dbDeepShapeStore
#define HDR_dbDeepShapeStore
#include "dbCommon.h"
#include "tlObject.h"
#include "dbLayout.h"
#include "dbRecursiveShapeIterator.h"
namespace db {
class DeepShapeStore;
/**
* @brief Represents a shape collection from the deep shape store
*
* This is a lightweight class pointing into the deep shape store.
* DeepLayer objects are issued by the DeepShapeStore class.
*/
class DB_PUBLIC DeepLayer
{
public:
/**
* @brief Destructor
*/
~DeepLayer ();
/**
* @brief Copy constructor
*/
DeepLayer (const DeepLayer &other);
/**
* @brief Assignment
*/
DeepLayer &operator= (const DeepLayer &other);
/**
* @brief Gets the layout object
*
* The return value is guaranteed to be non-null.
*/
db::Layout *layout ();
/**
* @brief Gets the layer
*/
unsigned int layer () const
{
return m_layer;
}
private:
friend class DeepShapeStore;
/**
* @brief The constructor
*/
DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer);
unsigned int layout () const { return m_layout; }
unsigned int layer () const { return m_layer; }
tl::weak_ptr<DeepShapeStore> mp_store;
unsigned int m_layout;
unsigned int m_layer;
};
/**
* @brief The "deep shape store" is a working model for the hierarchical ("deep") processor
*
* The deep shape store keep temporary data for the deep shape processor.
* It mainly consists of layout objects holding the hierarchy trees and layers
* for the actual shapes.
*
* The deep shape store provides the basis for working with deep regions. On preparation,
* shapes are copied into the deep shape store. After fininishing, the shapes are copied
* back into the original layout. The deep shape store provides the methods and
* algorithms for doing the preparation and transfer.
*/
class DB_PUBLIC DeepShapeStore
: public tl::Object
{
public:
/**
* @brief The default constructor
*/
DeepShapeStore ();
private:
// no copying
DeepShapeStore (const DeepShapeStore &);
DeepShapeStore &operator= (const DeepShapeStore &);
};
}
#endif

View File

@ -493,14 +493,24 @@ public:
/**
* @brief Returns the nth edge pair
*
* This operation is only cheap if "has_valid_edge_pairs" is true. Otherwise, the
* complexity is O(n).
* This operation is available only for flat regions - i.e. such for which
* "has_valid_edge_pairs" is true.
*/
const db::EdgePair *nth (size_t n) const
{
return mp_delegate->nth (n);
}
/**
* @brief Forces flattening of the edge pair collection
*
* This method will turn any edge pair collection into a flat one.
*/
void flatten ()
{
flat_edge_pairs ();
}
/**
* @brief Returns true, if the edge pair set has valid edges stored within itself
*

View File

@ -1172,14 +1172,23 @@ public:
/**
* @brief Returns the nth edge
*
* This operation is only cheap if "has_valid_edges" is true. Otherwise, the
* complexity is O(n).
* This operation is available only for flat regions - i.e. such for which "has_valid_edges" is true.
*/
const db::Edge *nth (size_t n) const
{
return mp_delegate->nth (n);
}
/**
* @brief Forces flattening of the edge collection
*
* This method will turn any edge collection into a flat one.
*/
void flatten ()
{
flat_edges ();
}
/**
* @brief Returns true, if the edge set has valid edges stored within itself
*

View File

@ -184,6 +184,7 @@ void
FlatEdgePairs::insert (const db::EdgePair &ep)
{
m_edge_pairs.insert (ep);
invalidate_cache ();
}
void

View File

@ -338,7 +338,12 @@ FlatEdges::insert (const db::SimplePolygon &polygon)
void
FlatEdges::insert (const db::Edge &edge)
{
if (! empty ()) {
m_is_merged = false;
}
m_edges.insert (edge);
invalidate_cache ();
}
void

View File

@ -23,6 +23,7 @@
#include "dbOriginalLayerEdgePairs.h"
#include "dbEdgePairs.h"
#include "tlInternational.h"
namespace db
{
@ -150,7 +151,7 @@ OriginalLayerEdgePairs::empty () const
const db::EdgePair *
OriginalLayerEdgePairs::nth (size_t) const
{
tl_assert (false);
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat collections")));
}
bool

View File

@ -195,7 +195,7 @@ OriginalLayerEdges::is_merged () const
const db::Edge *
OriginalLayerEdges::nth (size_t) const
{
tl_assert (false);
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat collections")));
}
bool

View File

@ -195,7 +195,7 @@ OriginalLayerRegion::is_merged () const
const db::Polygon *
OriginalLayerRegion::nth (size_t) const
{
tl_assert (false);
throw tl::Exception (tl::to_string (tr ("Random access to polygons is available only for flat regions")));
}
bool

View File

@ -1576,14 +1576,24 @@ public:
/**
* @brief Returns the nth polygon
*
* This operation is only cheap if "has_valid_polygons" is true. Otherwise, the
* complexity is O(n).
* This operation is available only for flat regions - i.e. such for which
* "has_valid_polygons" is true.
*/
const db::Polygon *nth (size_t n) const
{
return mp_delegate->nth (n);
}
/**
* @brief Forces flattening of the region
*
* This method will turn any region into a flat shape collection.
*/
void flatten ()
{
flat_region ();
}
/**
* @brief Returns true, if the region has valid polygons stored within itself
*

View File

@ -35,6 +35,35 @@ static db::EdgePairs *new_v ()
return new db::EdgePairs ();
}
static db::EdgePairs *new_a (const std::vector<db::EdgePair> &pairs)
{
return new db::EdgePairs (pairs.begin (), pairs.end ());
}
static db::EdgePairs *new_ep (const db::EdgePair &pair)
{
return new db::EdgePairs (pair);
}
static db::EdgePairs *new_shapes (const db::Shapes &s)
{
db::EdgePairs *r = new db::EdgePairs ();
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::EdgePairs); !i.at_end (); ++i) {
r->insert (*i);
}
return r;
}
static db::EdgePairs *new_si (const db::RecursiveShapeIterator &si)
{
return new db::EdgePairs (si);
}
static db::EdgePairs *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
{
return new db::EdgePairs (si, trans);
}
static std::string to_string0 (const db::EdgePairs *r)
{
return r->to_string ();
@ -135,6 +164,67 @@ Class<db::EdgePairs> decl_EdgePairs ("db", "EdgePairs",
"\n"
"This constructor creates an empty edge pair collection.\n"
) +
constructor ("new", &new_a,
"@brief Constructor from an edge pair array\n"
"@args array\n"
"\n"
"This constructor creates an edge pair collection from an array of \\EdgePair objects.\n"
"\n"
"This constructor has been introduced in version 0.26."
) +
constructor ("new", &new_ep,
"@brief Constructor from a single edge pair object\n"
"@args edge_pair\n"
"\n"
"This constructor creates an edge pair collection with a single edge pair.\n"
"\n"
"This constructor has been introduced in version 0.26."
) +
constructor ("new", &new_shapes,
"@brief Shapes constructor\n"
"@args shapes\n"
"\n"
"This constructor creates an edge pair collection from a \\Shapes collection.\n"
"\n"
"This constructor has been introduced in version 0.26."
) +
constructor ("new", &new_si,
"@brief Constructor from a hierarchical shape set\n"
"@args shape_iterator\n"
"\n"
"This constructor creates an edge pair collection from the shapes delivered by the given recursive shape iterator.\n"
"Only edge pairs are taken from the shape set and other shapes are ignored.\n"
"This method allows feeding the edge pair collection from a hierarchy of cells.\n"
"\n"
"@code\n"
"layout = ... # a layout\n"
"cell = ... # the index of the initial cell\n"
"layer = ... # the index of the layer from where to take the shapes from\n"
"r = RBA::EdgePairs::new(layout.begin_shapes(cell, layer))\n"
"@/code\n"
"\n"
"This constructor has been introduced in version 0.26."
) +
constructor ("new", &new_si2,
"@brief Constructor from a hierarchical shape set with a transformation\n"
"@args shape_iterator, trans\n"
"\n"
"This constructor creates an edge pair collection from the shapes delivered by the given recursive shape iterator.\n"
"Only edge pairs are taken from the shape set and other shapes are ignored.\n"
"The given transformation is applied to each edge pair taken.\n"
"This method allows feeding the edge pair collection from a hierarchy of cells.\n"
"The transformation is useful to scale to a specific database unit for example.\n"
"\n"
"@code\n"
"layout = ... # a layout\n"
"cell = ... # the index of the initial cell\n"
"layer = ... # the index of the layer from where to take the shapes from\n"
"dbu = 0.1 # the target database unit\n"
"r = RBA::EdgePairs::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
"@/code\n"
"\n"
"This constructor has been introduced in version 0.26."
) +
method ("insert", (void (db::EdgePairs::*) (const db::Edge &, const db::Edge &)) &db::EdgePairs::insert,
"@brief Inserts an edge pair into the collection\n"
"@args first, second\n"
@ -337,7 +427,23 @@ Class<db::EdgePairs> decl_EdgePairs ("db", "EdgePairs",
"@brief Returns the nth edge pair\n"
"@args n\n"
"\n"
"This method returns nil if the index is out of range.\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."
) +
method ("flatten", &db::EdgePairs::flatten,
"@brief Explicitly flattens an edge pair collection\n"
"\n"
"If the collection is already flat (i.e. \\has_valid_edge_pairs? returns true), this method will "
"not change the collection.\n"
"\n"
"This method has been introduced in version 0.26."
) +
method ("has_valid_edge_pairs?", &db::EdgePairs::has_valid_edge_pairs,
"@brief Returns true if the edge pair collection is flat and individual edge pairs can be accessed randomly\n"
"\n"
"This method has been introduced in version 0.26."
) +
method ("enable_progress", &db::EdgePairs::enable_progress,
"@brief Enable progress reporting\n"

View File

@ -1433,10 +1433,27 @@ Class<db::Edges> dec_Edges ("db", "Edges",
"This method has been introduced in version 0.25."
) +
method ("[]", &db::Edges::nth,
"@brief Returns the nth edge of the edge collection\n"
"@brief Returns the nth edge of the collection\n"
"@args n\n"
"\n"
"This method returns nil if the index is out of range.\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."
) +
method ("flatten", &db::Edges::flatten,
"@brief Explicitly flattens an edge collection\n"
"\n"
"If the collection is already flat (i.e. \\has_valid_edges? returns true), this method will "
"not change it.\n"
"\n"
"This method has been introduced in version 0.26."
) +
method ("has_valid_edges?", &db::Edges::has_valid_edges,
"@brief Returns true if the edge collection is flat and individual edges can be accessed randomly\n"
"\n"
"This method has been introduced in version 0.26."
) +
method_ext ("to_s", &to_string0,
"@brief Converts the edge collection to a string\n"

View File

@ -797,7 +797,7 @@ Class<db::Region> decl_Region ("db", "Region",
"@param as_pattern If true, the selection string is treated as a glob pattern. Otherwise the match is exact.\n"
"\n"
"This special constructor will create a region from the text objects delivered by the shape iterator. "
"Each text object will deliver a small (non-empty) box that represents the text origin.\n"
"Each text object will give a small (non-empty) box that represents the text origin.\n"
"Texts can be selected by their strings - either through a glob pattern or by exact comparison with "
"the given string. The following options are available:\n"
"\n"
@ -2320,11 +2320,24 @@ Class<db::Region> decl_Region ("db", "Region",
"@brief Returns the nth polygon of the region\n"
"@args n\n"
"\n"
"This method returns nil if the index is out of range.\n"
"This returns the raw polygon (not merged polygons if merged semantics is enabled).\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"
"Using this method may be costly in terms of memory since it will load the polygons into an array if they have been "
"stored in an hierarchical layout before. It is recommended to use the \\each iterator instead if possible."
"The \\each iterator is the more general approach to access the polygons."
) +
method ("flatten", &db::Region::flatten,
"@brief Explicitly flattens a region\n"
"\n"
"If the region is already flat (i.e. \\has_valid_polygons? returns true), this method will "
"not change it.\n"
"\n"
"This method has been introduced in version 0.26."
) +
method ("has_valid_polygons?", &db::Region::has_valid_polygons,
"@brief Returns true if the region is flat and individual polygons can be accessed randomly\n"
"\n"
"This method has been introduced in version 0.26."
) +
method_ext ("to_s", &to_string0,
"@brief Converts the region to a string\n"

View File

@ -689,6 +689,26 @@ static tl::Variant get_dedge (const db::Shape *s)
}
}
static tl::Variant get_edge_pair (const db::Shape *s)
{
db::Shape::edge_pair_type p;
if (s->edge_pair (p)) {
return tl::Variant (p);
} else {
return tl::Variant ();
}
}
static tl::Variant get_dedge_pair (const db::Shape *s)
{
db::Shape::edge_pair_type p;
if (s->edge_pair (p)) {
return tl::Variant (db::CplxTrans (shape_dbu (s)) * p);
} else {
return tl::Variant ();
}
}
static tl::Variant get_text (const db::Shape *s)
{
db::Shape::text_type p;
@ -1087,6 +1107,7 @@ static int t_simplePolygonRef () { return db::Shape::SimplePolygonRef
static int t_simplePolygonPtrArray () { return db::Shape::SimplePolygonPtrArray; }
static int t_simplePolygonPtrArrayMember () { return db::Shape::SimplePolygonPtrArrayMember; }
static int t_edge () { return db::Shape::Edge; }
static int t_edge_pair () { return db::Shape::EdgePair; }
static int t_path () { return db::Shape::Path; }
static int t_pathRef () { return db::Shape::PathRef; }
static int t_pathPtrArray () { return db::Shape::PathPtrArray; }
@ -1218,7 +1239,7 @@ Class<db::Shape> decl_Shape ("db", "Shape",
"\n"
"This method has been introduced in version 0.25."
) +
gsi::method_ext ("edge=", &set_shape<db::Edge>,
gsi::method_ext ("edge=", &set_shape<db::Edge>, gsi::arg("edge"),
"@brief Replaces the shape by the given edge\n"
"@args box\n"
"This method replaces the shape by the given edge. This method can only be called "
@ -1235,6 +1256,23 @@ Class<db::Shape> decl_Shape ("db", "Shape",
"\n"
"This method has been introduced in version 0.25."
) +
gsi::method_ext ("edge_pair=", &set_shape<db::EdgePair>, gsi::arg("edge_pair"),
"@brief Replaces the shape by the given edge pair\n"
"@args box\n"
"This method replaces the shape by the given edge pair. This method can only be called "
"for editable layouts. It does not change the user properties of the shape.\n"
"Calling this method will invalidate any iterators. It should not be called inside a "
"loop iterating over shapes.\n"
"\n"
"This method has been introduced in version 0.26."
) +
gsi::method_ext ("edge_pair=|dedge_pair=", &set_dshape<db::DEdgePair>, gsi::arg("edge_pair"),
"@brief Replaces the shape by the given edge pair (in micrometer units)\n"
"This method replaces the shape by the given edge pair, like \\edge_pair= with a \\EdgePair argument does. "
"This version translates the edge pair from micrometer units to database units internally.\n"
"\n"
"This method has been introduced in version 0.26."
) +
gsi::method_ext ("delete_property", &delete_property,
"@brief Deletes the user property with the given key\n"
"@args key\n"
@ -1713,12 +1751,29 @@ Class<db::Shape> decl_Shape ("db", "Shape",
"Starting with version 0.23, this method returns nil, if the shape does not represent an edge."
) +
gsi::method_ext ("dedge", &get_dedge,
"@brief Returns the path object as a \\DEdge object in micrometer units\n"
"@brief Returns the edge object as a \\DEdge object in micrometer units\n"
"See \\edge for a description of this method. This method returns the edge after translation to "
"micrometer units.\n"
"\n"
"This method has been added in version 0.25.\n"
) +
gsi::method ("is_edge_pair?", &db::Shape::is_edge_pair,
"@brief Returns true, if the object is an edge pair\n"
"\n"
"This method has been introduced in version 0.26."
) +
gsi::method_ext ("edge_pair", &get_edge_pair,
"@brief Returns the edge pair object\n"
"\n"
"This method has been introduced in version 0.26."
) +
gsi::method_ext ("dedge_pair", &get_dedge_pair,
"@brief Returns the edge pair object as a \\DEdgePair object in micrometer units\n"
"See \\edge_pair for a description of this method. This method returns the edge pair after translation to "
"micrometer units.\n"
"\n"
"This method has been added in version 0.26.\n"
) +
gsi::method ("is_text?", &db::Shape::is_text,
"@brief Returns true, if the object is a text\n"
) +
@ -1729,7 +1784,7 @@ Class<db::Shape> decl_Shape ("db", "Shape",
) +
gsi::method_ext ("dtext", &get_dtext,
"@brief Returns the path object as a \\DText object in micrometer units\n"
"See \\edge for a description of this method. This method returns the text after translation to "
"See \\text for a description of this method. This method returns the text after translation to "
"micrometer units.\n"
"\n"
"This method has been added in version 0.25.\n"
@ -2026,6 +2081,7 @@ Class<db::Shape> decl_Shape ("db", "Shape",
gsi::method ("TSimplePolygonPtrArray|#t_simple_polygon_ptr_array", &t_simplePolygonPtrArray) +
gsi::method ("TSimplePolygonPtrArrayMember|#t_simple_polygon_ptr_array_member", &t_simplePolygonPtrArrayMember) +
gsi::method ("TEdge|#t_edge", &t_edge) +
gsi::method ("TEdgePair|#t_edge_pair", &t_edge_pair) +
gsi::method ("TPath|#t_path", &t_path) +
gsi::method ("TPathRef|#t_path_ref", &t_pathRef) +
gsi::method ("TPathPtrArray|#t_path_ptr_array", &t_pathPtrArray) +

View File

@ -423,6 +423,7 @@ static unsigned int s_properties () { return db::ShapeIterator::Propert
static unsigned int s_polygons () { return db::ShapeIterator::Polygons; }
static unsigned int s_boxes () { return db::ShapeIterator::Boxes; }
static unsigned int s_edges () { return db::ShapeIterator::Edges; }
static unsigned int s_edge_pairs () { return db::ShapeIterator::EdgePairs; }
static unsigned int s_paths () { return db::ShapeIterator::Paths; }
static unsigned int s_texts () { return db::ShapeIterator::Texts; }
static unsigned int s_user_objects () { return db::ShapeIterator::UserObjects; }
@ -780,9 +781,8 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method_ext ("replace", &replace<db::Edge>,
gsi::method_ext ("replace", &replace<db::Edge>, gsi::arg ("shape"), gsi::arg ("edge"),
"@brief Replaces the given shape with an edge object\n"
"@args shape,edge\n"
"\n"
"This method has been introduced with version 0.16. It replaces the given shape with the "
"object specified. It does not change the property Id. To change the property Id, "
@ -792,7 +792,7 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"This method is permitted in editable mode only."
) +
gsi::method_ext ("replace", &dreplace<db::DEdge>, gsi::arg ("shape"), gsi::arg ("edge"),
"@brief Replaces the given shape with a edge given in micrometer units\n"
"@brief Replaces the given shape with an edge given in micrometer units\n"
"@return A reference to the new shape (a \\Shape object)\n"
"\n"
"This method behaves like the \\replace version with an \\Edge argument, except that it will "
@ -800,6 +800,27 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method_ext ("replace", &replace<db::EdgePair>, gsi::arg ("shape"), gsi::arg ("edge_pair"),
"@brief Replaces the given shape with an edge pair object\n"
"\n"
"It replaces the given shape with the "
"object specified. It does not change the property Id. To change the property Id, "
"use the \\replace_prop_id method. To replace a shape and discard the property Id, erase the "
"shape and insert a new shape."
"\n"
"This method is permitted in editable mode only.\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("replace", &dreplace<db::DEdgePair>, gsi::arg ("shape"), gsi::arg ("edge_pair"),
"@brief Replaces the given shape with an edge pair given in micrometer units\n"
"@return A reference to the new shape (a \\Shape object)\n"
"\n"
"This method behaves like the \\replace version with an \\EdgePair argument, except that it will "
"internally translate the edge pair from micrometer to database units.\n"
"\n"
"This variant has been introduced in version 0.26.\n"
) +
gsi::method_ext ("replace", &replace<db::Text>,
"@brief Replaces the given shape with a text object\n"
"@return A reference to the new shape (a \\Shape object)\n"
@ -893,9 +914,8 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method_ext ("insert|#insert_edge", &insert<db::Edge>,
"@brief Inserts a edge into the shapes list\n"
"@args edge\n"
gsi::method_ext ("insert|#insert_edge", &insert<db::Edge>, gsi::arg ("edge"),
"@brief Inserts an edge into the shapes list\n"
"\n"
"Starting with version 0.16, this method returns a reference to the newly created shape\n"
) +
@ -907,6 +927,19 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method_ext ("insert", &insert<db::EdgePair>, gsi::arg ("edge_pair"),
"@brief Inserts an edge pair into the shapes list\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("insert", &dinsert<db::DEdgePair>, gsi::arg ("edge_pair"),
"@brief Inserts a micrometer-unit edge pair into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
"This method behaves like the \\insert version with a \\EdgePair argument, except that it will "
"internally translate the edge pair from micrometer to database units.\n"
"\n"
"This variant has been introduced in version 0.26."
) +
gsi::method_ext ("insert|#insert_text", &insert<db::Text>,
"@brief Inserts a text into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
@ -986,14 +1019,13 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method_ext ("insert|#insert_edge_with_properties", &insert_with_properties<db::Edge>,
"@brief Inserts a edge with properties into the shapes list\n"
"@args edge, property_id\n"
gsi::method_ext ("insert|#insert_edge_with_properties", &insert_with_properties<db::Edge>, gsi::arg ("edge"), gsi::arg ("property_id"),
"@brief Inserts an edge with properties into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
"The property Id must be obtained from the \\Layout object's property_id method which "
"associates a property set with a property Id."
"\n"
"Starting with version 0.16, this method returns a reference to the newly created shape\n"
"Starting with version 0.16, this method returns a reference to the newly created shape.\n"
) +
gsi::method_ext ("insert", &dinsert_with_properties<db::DEdge, db::Edge>, gsi::arg ("edge"), gsi::arg ("property_id"),
"@brief Inserts a micrometer-unit edge with properties into the shapes list\n"
@ -1003,6 +1035,22 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method_ext ("insert", &insert_with_properties<db::EdgePair>, gsi::arg ("edge_pair"), gsi::arg ("property_id"),
"@brief Inserts an edge pair with properties into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
"The property Id must be obtained from the \\Layout object's property_id method which "
"associates a property set with a property Id."
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("insert", &dinsert_with_properties<db::DEdgePair, db::EdgePair>, gsi::arg ("edge_pair"), gsi::arg ("property_id"),
"@brief Inserts a micrometer-unit edge pair with properties into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
"This method behaves like the \\insert version with a \\EdgePair argument and a property ID, except that it will "
"internally translate the edge pair from micrometer to database units.\n"
"\n"
"This variant has been introduced in version 0.26."
) +
gsi::method_ext ("insert|#insert_text_with_properties", &insert_with_properties<db::Text>,
"@brief Inserts a text with properties into the shapes list\n"
"@args text, property_id\n"
@ -1185,6 +1233,9 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
gsi::method ("SEdges|#s_edges", &s_edges,
"@brief Indicates that edges shall be retrieved"
) +
gsi::method ("SEdgePairs|#s_edge_pairs", &s_edge_pairs,
"@brief Indicates that edge pairs shall be retrieved"
) +
gsi::method ("SPaths|#s_paths", &s_paths,
"@brief Indicates that paths shall be retrieved"
) +
@ -1203,7 +1254,7 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"@brief A collection of shapes\n"
"\n"
"A shapes collection is a collection of geometrical objects, such as "
"polygons, boxes, paths, edges or text objects.\n"
"polygons, boxes, paths, edges, edge pairs or text objects.\n"
"\n"
"Shapes objects are the basic containers for geometrical objects of a cell. Inside a cell, there is "
"one Shapes object per layer.\n"

View File

@ -238,6 +238,7 @@ TEST(3)
tp.input ("i2", ir2.begin_iter ().first, ir2.begin_iter ().second);
EXPECT_EQ (ir2.has_valid_polygons (), false);
db::Region ir3 (db::RecursiveShapeIterator (ly, ly.cell (top), l3));
ir3.flatten ();
tp.input ("i3", ir3.begin_iter ().first, ir3.begin_iter ().second);
EXPECT_EQ (ir3.has_valid_polygons (), true);
tp.output ("o1", ly, top, o1);

View File

@ -108,6 +108,51 @@ class DBEdgePairs_TestClass < TestBase
end
def test_3
ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 1, 2, 3), RBA::Edge::new(10, 11, 12, 13))
ep2 = RBA::EdgePair::new(RBA::Edge::new(20, 21, 22, 23), RBA::Edge::new(30, 31, 32, 33))
r1 = RBA::EdgePairs::new([ ep1, ep2 ])
assert_equal(r1.to_s, "(0,1;2,3)/(10,11;12,13);(20,21;22,23)/(30,31;32,33)")
r1 = RBA::EdgePairs::new(ep1)
assert_equal(r1.to_s, "(0,1;2,3)/(10,11;12,13)")
s = RBA::Shapes::new
s.insert(ep1)
s.insert(ep2)
r1 = RBA::EdgePairs::new(s)
assert_equal(r1.to_s, "(0,1;2,3)/(10,11;12,13);(20,21;22,23)/(30,31;32,33)")
ly = RBA::Layout::new
l1 = ly.layer("l1")
l2 = ly.layer("l2")
c1 = ly.create_cell("C1")
c2 = ly.create_cell("C2")
c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 0)))
c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 100)))
c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(200, 100)))
c2.shapes(l1).insert(ep1)
c2.shapes(l2).insert(ep2)
r = RBA::EdgePairs::new(ly.begin_shapes(c1.cell_index, l1))
assert_equal(r.to_s(30), "(0,1;2,3)/(10,11;12,13);(0,101;2,103)/(10,111;12,113);(200,101;202,103)/(210,111;212,113)")
assert_equal(r.to_s(2), "(0,1;2,3)/(10,11;12,13);(0,101;2,103)/(10,111;12,113)...")
assert_equal(r.is_empty?, false)
assert_equal(r.size, 3)
assert_equal(r.has_valid_edge_pairs?, false)
assert_equal(r.bbox.to_s, "(0,1;212,113)")
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[100].inspect, "nil")
assert_equal(r.bbox.to_s, "(0,1;212,113)")
end
end

View File

@ -40,6 +40,13 @@ class DBEdges_TestClass < TestBase
assert_equal(r.is_empty?, false)
assert_equal(r.size, 1)
assert_equal(r.bbox.to_s, "(10,20;100,200)")
assert_equal(r.is_merged?, true)
r.assign(RBA::Edges::new([RBA::Edge::new(10, 20, 100, 200), RBA::Edge::new(11, 21, 101, 201)]))
assert_equal(r.to_s, "(10,20;100,200);(11,21;101,201)")
assert_equal(r.is_empty?, false)
assert_equal(r.size, 2)
assert_equal(r.bbox.to_s, "(10,20;101,201)")
assert_equal(r.is_merged?, false)
r.assign(RBA::Edges::new(RBA::Edge::new(10, 20, 100, 200)))
@ -47,7 +54,7 @@ class DBEdges_TestClass < TestBase
assert_equal(r.is_empty?, false)
assert_equal(r.size, 1)
assert_equal(r.bbox.to_s, "(10,20;100,200)")
assert_equal(r.is_merged?, false)
assert_equal(r.is_merged?, true)
r.assign(RBA::Edges::new(RBA::Box::new(10, 20, 100, 200)))
assert_equal(r.to_s, "(10,20;10,200);(10,200;100,200);(100,200;100,20);(100,20;10,20)")
@ -60,7 +67,7 @@ class DBEdges_TestClass < TestBase
assert_equal(r.is_empty?, false)
assert_equal(r.size, 4)
assert_equal(r.bbox.to_s, "(10,20;100,200)")
assert_equal(r.is_merged?, false)
assert_equal(r.is_merged?, true)
assert_equal(r.moved(RBA::Point::new(10, 20)).bbox.to_s, "(20,40;110,220)")
assert_equal(r.moved(10, 20).bbox.to_s, "(20,40;110,220)")
@ -163,6 +170,12 @@ class DBEdges_TestClass < TestBase
assert_equal(r.to_s(2), "(-10,-20;10,20);(-10,80;10,120)...")
assert_equal(r.is_empty?, false)
assert_equal(r.size, 3)
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")
assert_equal(r.is_merged?, false)
assert_equal(r.has_valid_edges?, false)
r.flatten
assert_equal(r.has_valid_edges?, true)
assert_equal(r[1].to_s, "(-10,80;10,120)")
assert_equal(r[100].to_s, "")
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")

View File

@ -41,7 +41,7 @@ class DBRegion_TestClass < TestBase
assert_equal(r.is_empty?, false)
assert_equal(r.size, 1)
assert_equal(r.bbox.to_s, "(10,20;100,200)")
assert_equal(r.is_merged?, false)
assert_equal(r.is_merged?, true)
assert_equal(r.is_box?, true)
assert_equal(r.edges.to_s, "(10,20;10,200);(10,200;100,200);(100,200;100,20);(100,20;10,20)")
@ -149,6 +149,12 @@ class DBRegion_TestClass < TestBase
assert_equal(r.to_s, "(-10,-20;-10,20;10,20;10,-20);(-10,80;-10,120;10,120;10,80);(190,80;190,120;210,120;210,80)")
assert_equal(r.is_empty?, false)
assert_equal(r.size, 3)
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")
assert_equal(r.is_merged?, false)
assert_equal(r.has_valid_polygons?, false)
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[4].to_s, "")
assert_equal(r.bbox.to_s, "(-10,-20;210,120)")

View File

@ -155,6 +155,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].polygon.inspect, "(10,-10;10,40;50,40;50,-10)" )
assert_equal( arr[0].simple_polygon.inspect, "(10,-10;10,40;50,40;50,-10)" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.inspect, "(10,-10;50,40)" )
assert_equal( arr[0].path.inspect, "nil" )
assert_equal( arr[0].text.inspect, "nil" )
@ -178,6 +179,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].polygon.inspect, "nil" )
assert_equal( arr[0].simple_polygon.inspect, "nil" )
assert_equal( arr[0].edge.inspect, "(-1,2;5,2)" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
assert_equal( arr[0].path.inspect, "nil" )
assert_equal( arr[0].text.inspect, "nil" )
@ -188,6 +190,32 @@ class DBShapes_TestClass < TestBase
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# edge pairs
a = RBA::EdgePair::new(RBA::Edge::new(RBA::Point::new(-1, 2), RBA::Point::new(5, 2)), RBA::Edge::new(RBA::Point::new(-1, 5), RBA::Point::new(5, 5)))
c1.shapes( lindex ).insert( a )
arr = []
shapes.each( RBA::Shapes::SEdgePairs ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].prop_id, 0 )
assert_equal( arr[0].has_prop_id?, false )
assert_equal( arr[0].is_null?, false )
assert_equal( arr[0].type, RBA::Shape::t_edge_pair )
assert_equal( arr[0].is_edge_pair?, true )
assert_equal( arr[0].polygon.inspect, "nil" )
assert_equal( arr[0].simple_polygon.inspect, "nil" )
assert_equal( arr[0].edge_pair.inspect, "(-1,2;5,2)/(-1,5;5,5)" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
assert_equal( arr[0].path.inspect, "nil" )
assert_equal( arr[0].text.inspect, "nil" )
assert_equal( arr[0].edge_pair == a, true )
assert_equal( arr[0].bbox == a.bbox, true )
arr = []
shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# paths
a = RBA::Path::new( [ RBA::Point::new( 0, 10 ), RBA::Point::new( 10, 50 ) ], 25 )
@ -203,6 +231,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].polygon.inspect, "(12,7;-12,13;-2,53;22,47)" )
assert_equal( arr[0].simple_polygon.inspect, "(12,7;-12,13;-2,53;22,47)" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
assert_equal( arr[0].path.inspect, "(0,10;10,50) w=25 bx=0 ex=0 r=false" )
assert_equal( arr[0].text.inspect, "nil" )
@ -238,6 +267,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].polygon.inspect, "(0,1;1,5;5,5)" )
assert_equal( arr[0].simple_polygon.inspect, "(0,1;1,5;5,5)" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
assert_equal( arr[0].path.inspect, "nil" )
assert_equal( arr[0].text.inspect, "nil" )
@ -419,6 +449,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].dpolygon.inspect, "(0.01,-0.01;0.01,0.04;0.05,0.04;0.05,-0.01)" )
assert_equal( arr[0].dsimple_polygon.inspect, "(0.01,-0.01;0.01,0.04;0.05,0.04;0.05,-0.01)" )
assert_equal( arr[0].dedge.inspect, "nil" )
assert_equal( arr[0].dedge_pair.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "(0.01,-0.01;0.05,0.04)" )
assert_equal( arr[0].dpath.inspect, "nil" )
assert_equal( arr[0].dtext.inspect, "nil" )
@ -442,6 +473,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].dpolygon.inspect, "nil" )
assert_equal( arr[0].dsimple_polygon.inspect, "nil" )
assert_equal( arr[0].dedge.inspect, "(-0.001,0.002;0.005,0.002)" )
assert_equal( arr[0].dedge_pair.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "nil" )
assert_equal( arr[0].dpath.inspect, "nil" )
assert_equal( arr[0].dtext.inspect, "nil" )
@ -451,6 +483,31 @@ class DBShapes_TestClass < TestBase
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# edge pairs
a = RBA::DEdgePair::new(RBA::DEdge::new(RBA::DPoint::new(-0.001, 0.002), RBA::DPoint::new(0.005, 0.002)), RBA::DEdge::new(RBA::DPoint::new(-0.001, 0.005), RBA::DPoint::new(0.005, 0.005)))
c1.shapes( lindex ).insert( a )
arr = []
shapes.each( RBA::Shapes::SEdgePairs ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].prop_id, 0 )
assert_equal( arr[0].has_prop_id?, false )
assert_equal( arr[0].is_null?, false )
assert_equal( arr[0].type, RBA::Shape::t_edge_pair )
assert_equal( arr[0].is_edge_pair?, true )
assert_equal( arr[0].dpolygon.inspect, "nil" )
assert_equal( arr[0].dsimple_polygon.inspect, "nil" )
assert_equal( arr[0].dedge_pair.inspect, "(-0.001,0.002;0.005,0.002)/(-0.001,0.005;0.005,0.005)" )
assert_equal( arr[0].dedge.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "nil" )
assert_equal( arr[0].dpath.inspect, "nil" )
assert_equal( arr[0].dtext.inspect, "nil" )
assert_equal( arr[0].dbbox.inspect, "(-0.001,0.002;0.005,0.005)" )
arr = []
shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# paths
a = RBA::DPath::new( [ RBA::DPoint::new( 0, 0.010 ), RBA::DPoint::new( 0.010, 0.050 ) ], 0.025 )
@ -466,6 +523,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].dpolygon.inspect, "(0.012,0.007;-0.012,0.013;-0.002,0.053;0.022,0.047)" )
assert_equal( arr[0].dsimple_polygon.inspect, "(0.012,0.007;-0.012,0.013;-0.002,0.053;0.022,0.047)" )
assert_equal( arr[0].dedge.inspect, "nil" )
assert_equal( arr[0].dedge_pair.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "nil" )
assert_equal( arr[0].dpath.inspect, "(0,0.01;0.01,0.05) w=0.025 bx=0 ex=0 r=false" )
assert_equal( arr[0].dtext.inspect, "nil" )
@ -499,6 +557,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].dpolygon.inspect, "(0,0.001;0.001,0.005;0.005,0.005)" )
assert_equal( arr[0].dsimple_polygon.inspect, "(0,0.001;0.001,0.005;0.005,0.005)" )
assert_equal( arr[0].dedge.inspect, "nil" )
assert_equal( arr[0].dedge_pair.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "nil" )
assert_equal( arr[0].dpath.inspect, "nil" )
assert_equal( arr[0].dtext.inspect, "nil" )
@ -720,6 +779,18 @@ class DBShapes_TestClass < TestBase
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["simple_polygon (14,0;-21,35;7,64;42,28)", "box (10,-10;50,40) prop_id=17"] )
s2 = shapes.replace( s2, RBA::Edge::new( 10, -10, 50, 40 ) )
arr = []
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["simple_polygon (14,0;-21,35;7,64;42,28)", "edge (10,-10;50,40) prop_id=17"] )
s2 = shapes.replace( s2, RBA::EdgePair::new( RBA::Edge::new( 10, -10, 50, 40 ), RBA::Edge::new( 10, 0, 50, 30 ) ) )
arr = []
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["simple_polygon (14,0;-21,35;7,64;42,28)", "edge_pair (10,-10;50,40)/(10,0;50,30) prop_id=17"] )
shapes.erase( s2 )
arr = []
@ -775,6 +846,7 @@ class DBShapes_TestClass < TestBase
assert_equal(s2.simple_polygon.inspect, "nil")
assert_equal(s2.text.inspect, "('text',r0 100,200)")
assert_equal(s2.edge.inspect, "nil")
assert_equal(s2.edge_pair.inspect, "nil")
assert_equal(s2.path.inspect, "nil")
assert_equal(s2.box.inspect, "nil")
@ -784,6 +856,18 @@ class DBShapes_TestClass < TestBase
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["box (11,-11;51,41)", "box (200,-10;250,40)", "text ('text',r0 100,200)"] )
s3.edge_pair = RBA::EdgePair::new(RBA::Edge::new(RBA::Point::new(1, 2), RBA::Point::new(3, 4)), RBA::Edge::new(RBA::Point::new(1, 12), RBA::Point::new(3, 14)))
shapes = c1.shapes( lindex )
arr = []
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["edge_pair (1,2;3,4)/(1,12;3,14)", "box (11,-11;51,41)", "text ('text',r0 100,200)"] )
arr = []
shapes.each( RBA::Shapes::SEdgePairs ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["edge_pair (1,2;3,4)/(1,12;3,14)"] )
s3.edge = RBA::Edge::new( RBA::Point::new( 1, 2 ), RBA::Point::new( 3, 4 ) )
shapes = c1.shapes( lindex )
@ -792,6 +876,10 @@ class DBShapes_TestClass < TestBase
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["edge (1,2;3,4)", "box (11,-11;51,41)", "text ('text',r0 100,200)"] )
arr = []
shapes.each( RBA::Shapes::SEdges ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["edge (1,2;3,4)"] )
pts = [ RBA::Point::new( 100, 200 ), RBA::Point::new( 400, 300 ), RBA::Point::new( 500, 600 ) ]
s1.polygon = RBA::Polygon::new( pts )
@ -990,6 +1078,14 @@ class DBShapes_TestClass < TestBase
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["box (11,-11;51,41)", "box (200,-10;250,40)", "text ('text',r0 100,200)"] )
s3.edge_pair = RBA::DEdgePair::new(RBA::DEdge::new(RBA::DPoint::new(0.001, 0.002), RBA::DPoint::new(0.003, 0.004)), RBA::DEdge::new(RBA::DPoint::new(0.001, 0.012), RBA::DPoint::new(0.003, 0.014)))
shapes = c1.shapes( lindex )
arr = []
shapes.each( RBA::Shapes::SAll ) { |s| arr.push( s.to_s ) }
assert_equal( arr, ["edge_pair (1,2;3,4)/(1,12;3,14)", "box (11,-11;51,41)", "text ('text',r0 100,200)"] )
s3.edge = RBA::DEdge::new( RBA::DPoint::new( 0.001, 0.002 ), RBA::DPoint::new( 0.003, 0.004 ) )
shapes = c1.shapes( lindex )