Region: hierarchical text object detection implementated.

This commit is contained in:
Matthias Koefferlein 2019-02-23 00:56:55 +01:00
parent c7b17fb65a
commit 3c6aafcc0c
9 changed files with 441 additions and 71 deletions

View File

@ -426,6 +426,33 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
return DeepLayer (this, layout_index, layer_index);
}
DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const db::ICplxTrans &trans)
{
unsigned int layout_index = layout_for_iter (si, trans);
db::Layout &layout = m_layouts[layout_index]->layout;
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
unsigned int layer_index = layout.insert_layer ();
builder.set_target_layer (layer_index);
// Build the working hierarchy from the recursive shape iterator
try {
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy")));
builder.set_shape_receiver (pipe);
db::RecursiveShapeIterator (si).push (& builder);
builder.set_shape_receiver (0);
} catch (...) {
builder.set_shape_receiver (0);
throw;
}
return DeepLayer (this, layout_index, layer_index);
}
DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &si, bool as_edges, const db::ICplxTrans &trans)
{
unsigned int layout_index = layout_for_iter (si, trans);

View File

@ -285,6 +285,15 @@ public:
*/
DeepLayer create_edge_pair_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ());
/**
* @brief Inserts a polygon layer into the deep shape store using a custom preparation pipeline
*
* This method will create a new layer inside the deep shapes store and
* feed it through the given pipeline. The pipeline may perform shape translations and
* finally will feed the target hierarchy.
*/
DeepLayer create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const ICplxTrans &trans = db::ICplxTrans ());
/**
* @brief Inserts the deep layer's shapes into some target layout
*/

View File

@ -23,8 +23,13 @@
#include "dbOriginalLayerRegion.h"
#include "dbFlatRegion.h"
#include "dbFlatEdges.h"
#include "dbRegion.h"
#include "dbShapeProcessor.h"
#include "dbDeepEdges.h"
#include "dbDeepRegion.h"
#include "dbDeepShapeStore.h"
#include "tlGlobPattern.h"
namespace db
{
@ -279,4 +284,165 @@ OriginalLayerRegion::ensure_merged_polygons_valid () const
}
}
namespace
{
template <class Container>
struct dot_delivery
{
typedef Container container_type;
dot_delivery ()
{
// .. nothing yet ..
}
void insert (const db::Point &pt, Container *container) const
{
container->insert (db::Edge (pt, pt));
}
};
template <class Container>
struct box_delivery
{
typedef Container container_type;
box_delivery (db::Coord enl)
: m_d (enl, enl)
{
// .. nothing yet ..
}
void insert (const db::Point &pt, Container *container) const
{
container->insert (db::Box (pt - m_d, pt + m_d));
}
private:
db::Vector m_d;
};
template <class Iter, class Delivery>
static void fill_texts (const Iter &iter, const std::string &pat, bool pattern, const Delivery &delivery, typename Delivery::container_type *container)
{
tl::GlobPattern glob_pat;
bool all = false;
if (pattern) {
if (pat == "*") {
all = true;
} else {
glob_pat = tl::GlobPattern (pat);
}
}
for (Iter si = iter; ! si.at_end (); ++si) {
if (si->is_text () &&
(all || (pattern && glob_pat.match (si->text_string ())) || (!pattern && si->text_string () == pat))) {
db::Text t;
si->text (t);
t.transform (si.trans ());
delivery.insert (t.box ().center (), container);
}
}
}
template <class Delivery>
class text_shape_receiver
: public db::HierarchyBuilderShapeReceiver
{
public:
text_shape_receiver (const Delivery &delivery, const std::string &pat, bool pattern)
: m_delivery (delivery), m_glob_pat (), m_all (false), m_pattern (pattern), m_pat (pat)
{
if (pattern) {
if (m_pat == "*") {
m_all = true;
} else {
m_glob_pat = tl::GlobPattern (pat);
}
}
}
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
if (shape.is_text () &&
(m_all || (m_pattern && m_glob_pat.match (shape.text_string ())) || (!m_pattern && shape.text_string () == m_pat))) {
db::Point pt = shape.bbox ().center ();
if (! complex_region) {
if (region.contains (pt)) {
m_delivery.insert (pt.transformed (trans), target);
}
} else {
if (! complex_region->begin_overlapping (db::Box (pt, pt), db::box_convert<db::Box> ()).at_end ()) {
m_delivery.insert (pt.transformed (trans), target);
}
}
}
}
virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
private:
Delivery m_delivery;
tl::GlobPattern m_glob_pat;
bool m_all;
bool m_pattern;
std::string m_pat;
};
}
db::EdgesDelegate *
OriginalLayerRegion::texts_as_dots (const std::string &pat, bool pattern) const
{
db::RecursiveShapeIterator iter (m_iter);
iter.shape_flags (db::ShapeIterator::Texts);
std::auto_ptr<db::FlatEdges> res (new db::FlatEdges ());
res->set_merged_semantics (false);
fill_texts (iter, pat, pattern, dot_delivery<db::FlatEdges> (), res.get ());
return res.release ();
}
db::EdgesDelegate *
OriginalLayerRegion::texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore &store) const
{
db::RecursiveShapeIterator iter (m_iter);
iter.shape_flags (db::ShapeIterator::Texts);
text_shape_receiver<dot_delivery<db::Shapes> > pipe = text_shape_receiver<dot_delivery<db::Shapes> > (dot_delivery<db::Shapes> (), pat, pattern);
return new db::DeepEdges (store.create_custom_layer (iter, &pipe));
}
db::RegionDelegate *
OriginalLayerRegion::texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl) const
{
db::RecursiveShapeIterator iter (m_iter);
iter.shape_flags (db::ShapeIterator::Texts);
std::auto_ptr<db::FlatRegion> res (new db::FlatRegion ());
res->set_merged_semantics (false);
fill_texts (iter, pat, pattern, box_delivery<db::FlatRegion> (enl), res.get ());
return res.release ();
}
db::RegionDelegate *
OriginalLayerRegion::texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl, db::DeepShapeStore &store) const
{
db::RecursiveShapeIterator iter (m_iter);
iter.shape_flags (db::ShapeIterator::Texts);
text_shape_receiver<box_delivery<db::Shapes> > pipe = text_shape_receiver<box_delivery<db::Shapes> > (box_delivery<db::Shapes> (enl), pat, pattern);
return new db::DeepRegion (store.create_custom_layer (iter, &pipe));
}
}

View File

@ -30,6 +30,10 @@
namespace db {
class EdgesDelegate;
class RegionDelegate;
class DeepShapeStore;
/**
* @brief An original layerregion based on a RecursiveShapeIterator
*/
@ -64,6 +68,11 @@ public:
virtual bool equals (const Region &other) const;
virtual bool less (const Region &other) const;
db::EdgesDelegate *texts_as_dots (const std::string &pat, bool pattern) const;
db::EdgesDelegate *texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore &store) const;
db::RegionDelegate *texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl) const;
db::RegionDelegate *texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl, db::DeepShapeStore &store) const;
protected:
virtual void merged_semantics_changed ();

View File

@ -28,6 +28,7 @@
#include "dbEdgesUtils.h"
#include "dbDeepEdges.h"
#include "dbRegion.h"
#include "dbOriginalLayerRegion.h"
#include "dbLayoutUtils.h"
namespace gsi
@ -389,6 +390,17 @@ static bool is_deep (const db::Edges *e)
return dynamic_cast<const db::DeepEdges *> (e->delegate ()) != 0;
}
static db::Edges *new_texts_as_dots1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern)
{
return new db::Edges (db::OriginalLayerRegion (si, false).texts_as_dots (pat, pattern));
}
static db::Edges *new_texts_as_dots2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const std::string &pat, bool pattern)
{
return new db::Edges (db::OriginalLayerRegion (si, false).texts_as_dots (pat, pattern, dss));
}
Class<db::Edges> dec_Edges ("db", "Edges",
constructor ("new", &new_v,
"@brief Default constructor\n"
@ -519,6 +531,47 @@ Class<db::Edges> dec_Edges ("db", "Edges",
"r = RBA::Edges::new(layout.begin_shapes(cell, layer), dss, RBA::ICplxTrans::new(layout.dbu / dbu), false)\n"
"@/code\n"
) +
constructor ("new", &new_texts_as_dots1, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true),
"@brief Constructor from a text set\n"
"\n"
"@param shape_iterator The iterator from which to derive the texts\n"
"@param expr The selection string\n"
"@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 dot-like edges from the text objects delivered by the shape iterator. "
"Each text object will give a degenerated edge (a dot) 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"
"@code\n"
"dots = RBA::Edges::new(iter, \"*\") # all texts\n"
"dots = RBA::Edges::new(iter, \"A*\") # all texts starting with an 'A'\n"
"dots = RBA::Edges::new(iter, \"A*\", false) # all texts exactly matchin 'A*'\n"
"@/code\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
constructor ("new", &new_texts_as_dots2, gsi::arg("shape_iterator"), gsi::arg ("dss"), gsi::arg ("expr"), gsi::arg ("as_pattern", true),
"@brief Constructor from a text set\n"
"\n"
"@param shape_iterator The iterator from which to derive the texts\n"
"@param dss The \\DeepShapeStore object that acts as a heap for hierarchical operations.\n"
"@param expr The selection string\n"
"@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 deep edge set from the text objects delivered by the shape iterator. "
"Each text object will give a degenerated edge (a dot) 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"
"@code\n"
"region = RBA::Region::new(iter, dss, \"*\") # all texts\n"
"region = RBA::Region::new(iter, dss, \"A*\") # all texts starting with an 'A'\n"
"region = RBA::Region::new(iter, dss, \"A*\", false) # all texts exactly matchin 'A*'\n"
"@/code\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
method ("insert_into", &db::Edges::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
"@brief Inserts this edge collection into the given layout, below the given cell and into the given layer.\n"
"If the edge collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "

View File

@ -25,6 +25,7 @@
#include "dbRegion.h"
#include "dbRegionUtils.h"
#include "dbDeepRegion.h"
#include "dbOriginalLayerRegion.h"
#include "dbPolygonTools.h"
#include "dbLayoutUtils.h"
#include "dbShapes.h"
@ -77,77 +78,43 @@ static db::Region *new_shapes (const db::Shapes &s)
return r;
}
struct DotDelivery
static db::Region *new_texts_as_boxes1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern, db::Coord enl)
{
typedef db::Edges container_type;
DotDelivery () : container ()
{
container.reset (new container_type ());
container->set_merged_semantics (false);
}
void insert (const db::Point &pt)
{
container->insert (db::Edge (pt, pt));
}
std::auto_ptr<container_type> container;
};
struct BoxDelivery
{
typedef db::Region container_type;
BoxDelivery () : container ()
{
container.reset (new container_type ());
}
void insert (const db::Point &pt)
{
container->insert (db::Box (pt - db::Vector (1, 1), pt + db::Vector (1, 1)));
}
std::auto_ptr<container_type> container;
};
template <class Delivery>
static typename Delivery::container_type *new_texts (const db::RecursiveShapeIterator &si_in, const std::string &pat, bool pattern)
{
db::RecursiveShapeIterator si (si_in);
si.shape_flags (db::ShapeIterator::Texts);
tl::GlobPattern glob_pat;
bool all = false;
if (pattern) {
if (pat == "*") {
all = true;
} else {
glob_pat = tl::GlobPattern (pat);
}
}
Delivery delivery;
while (! si.at_end ()) {
if (si.shape ().is_text () &&
(all || (pattern && glob_pat.match (si.shape ().text_string ())) || (!pattern && si.shape ().text_string () == pat))) {
db::Text t;
si.shape ().text (t);
t.transform (si.trans ());
delivery.insert (t.box ().center ());
}
si.next ();
}
return delivery.container.release ();
return new db::Region (db::OriginalLayerRegion (si, false).texts_as_boxes (pat, pattern, enl));
}
template <class Delivery>
static typename Delivery::container_type *texts (const db::Region *r, const std::string &pat, bool pattern)
static db::Region *new_texts_as_boxes2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const std::string &pat, bool pattern, db::Coord enl)
{
return new_texts<Delivery> (r->iter (), pat, pattern);
return new db::Region (db::OriginalLayerRegion (si, false).texts_as_boxes (pat, pattern, enl, dss));
}
static const db::OriginalLayerRegion *org_layer (const db::Region *r)
{
const db::OriginalLayerRegion *org_layer = dynamic_cast<const db::OriginalLayerRegion *> (r->delegate ());
if (! org_layer) {
throw tl::Exception (tl::to_string (tr ("Texts can only be identified on an original layer")));
}
return org_layer;
}
static db::Edges *texts_as_dots1 (const db::Region *r, const std::string &pat, bool pattern)
{
return new db::Edges (org_layer (r)->texts_as_dots (pat, pattern));
}
static db::Edges *texts_as_dots2 (const db::Region *r, db::DeepShapeStore &dss, const std::string &pat, bool pattern)
{
return new db::Edges (org_layer (r)->texts_as_dots (pat, pattern, dss));
}
static db::Region *texts_as_boxes1 (const db::Region *r, const std::string &pat, bool pattern, db::Coord enl)
{
return new db::Region (org_layer (r)->texts_as_boxes (pat, pattern, enl));
}
static db::Region *texts_as_boxes2 (const db::Region *r, db::DeepShapeStore &dss, const std::string &pat, bool pattern, db::Coord enl)
{
return new db::Region (org_layer (r)->texts_as_boxes (pat, pattern, enl, dss));
}
static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end)
@ -730,12 +697,13 @@ Class<db::Region> decl_Region ("db", "Region",
"\n"
"This method has been introduced in version 0.26.\n"
) +
constructor ("new", &new_texts<BoxDelivery>, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true),
constructor ("new", &new_texts_as_boxes1, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
"@brief Constructor from a text set\n"
"\n"
"@param shape_iterator The iterator from which to derive the texts\n"
"@param expr The selection string\n"
"@param as_pattern If true, the selection string is treated as a glob pattern. Otherwise the match is exact.\n"
"@param enl The per-side enlargement of the box to mark the text (1 gives a 2x2 DBU box)"
"\n"
"This special constructor will create a region from the text objects delivered by the shape iterator. "
"Each text object will give a small (non-empty) box that represents the text origin.\n"
@ -748,7 +716,29 @@ Class<db::Region> decl_Region ("db", "Region",
"region = RBA::Region::new(iter, \"A*\", false) # all texts exactly matchin 'A*'\n"
"@/code\n"
"\n"
"This method has been introduced in version 0.25."
"This method has been introduced in version 0.25. The enlargement parameter has been added in version 0.26.\n"
) +
constructor ("new", &new_texts_as_boxes2, gsi::arg("shape_iterator"), gsi::arg ("dss"), gsi::arg ("expr"), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
"@brief Constructor from a text set\n"
"\n"
"@param shape_iterator The iterator from which to derive the texts\n"
"@param dss The \\DeepShapeStore object that acts as a heap for hierarchical operations.\n"
"@param expr The selection string\n"
"@param as_pattern If true, the selection string is treated as a glob pattern. Otherwise the match is exact.\n"
"@param enl The per-side enlargement of the box to mark the text (1 gives a 2x2 DBU box)"
"\n"
"This special constructor will create a deep region from the text objects delivered by the shape iterator. "
"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"
"@code\n"
"region = RBA::Region::new(iter, dss, \"*\") # all texts\n"
"region = RBA::Region::new(iter, dss, \"A*\") # all texts starting with an 'A'\n"
"region = RBA::Region::new(iter, dss, \"A*\", false) # all texts exactly matchin 'A*'\n"
"@/code\n"
"\n"
"This variant has been introduced in version 0.26.\n"
) +
method ("insert_into", &db::Region::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
"@brief Inserts this region into the given layout, below the given cell and into the given layer.\n"
@ -757,11 +747,19 @@ Class<db::Region> decl_Region ("db", "Region",
"\n"
"This method has been introduced in version 0.26."
) +
factory_ext ("texts", &texts<BoxDelivery>, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
factory_ext ("texts", &texts_as_boxes1, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
"@hide\n"
"This method is provided for DRC implementation only."
) +
factory_ext ("texts_dots", &texts<DotDelivery>, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
factory_ext ("texts", &texts_as_boxes2, gsi::arg ("dss"), gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
"@hide\n"
"This method is provided for DRC implementation only."
) +
factory_ext ("texts_dots", &texts_as_dots1, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
"@hide\n"
"This method is provided for DRC implementation only."
) +
factory_ext ("texts_dots", &texts_as_dots2, gsi::arg ("dss"), gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true),
"@hide\n"
"This method is provided for DRC implementation only."
) +

View File

@ -30,6 +30,7 @@
#include "dbRegionProcessors.h"
#include "dbEdgesUtils.h"
#include "dbDeepShapeStore.h"
#include "dbOriginalLayerRegion.h"
#include "tlUnitTest.h"
#include "tlStream.h"
@ -1178,6 +1179,57 @@ TEST(22_TwoLayoutsWithDifferentDBU)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au22.gds");
}
TEST(23_Texts)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/deep_region_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
db::DeepShapeStore dss;
unsigned int l6 = ly.get_layer (db::LayerProperties (6, 1));
unsigned int l8 = ly.get_layer (db::LayerProperties (8, 1));
db::Region r6boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_boxes ("*", true, 100, dss));
db::Region r6dots;
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_dots ("*", true, dss)).extended (r6dots, 20, 20, 20, 20);
db::Region r8boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_boxes ("VDD", false, 100, dss));
db::Region r8dots;
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_dots ("V*", true, dss)).extended (r8dots, 20, 20, 20, 20);
db::Region rf6boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_boxes ("*", true, 100));
db::Region rf6dots;
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_dots ("*", true)).extended (rf6dots, 20, 20, 20, 20);
db::Region rf8boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_boxes ("VDD", false, 100));
db::Region rf8dots;
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_dots ("V*", true)).extended (rf8dots, 20, 20, 20, 20);
{
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r6boxes);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r6dots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), rf6boxes);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rf6dots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r8boxes);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r8dots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), rf8boxes);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), rf8dots);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au23.gds");
}
}
TEST(100_Integration)
{
db::Layout ly;

BIN
testdata/algo/deep_region_au23.gds vendored Normal file

Binary file not shown.

View File

@ -786,6 +786,62 @@ class DBRegion_TestClass < TestBase
end
# texts
def test_15
r = RBA::Region::new
ex = nil
begin
t = r.texts("*", true)
rescue => ex
end
assert_equal(ex.to_s, "Texts can only be identified on an original layer in Region::texts")
r.insert(RBA::Box::new(1, 2, 3, 4))
ex = nil
begin
t = r.texts("*", true)
rescue => ex
end
assert_equal(ex.to_s, "Texts can only be identified on an original layer in Region::texts")
ly = RBA::Layout::new
top = ly.create_cell("TOP")
l1 = ly.layer(1, 0)
top.shapes(l1).insert(RBA::Text::new("ABC", RBA::Trans::new(RBA::Vector::new(100, 200))))
r = RBA::Region::new(top.begin_shapes_rec(l1))
t = r.texts("*", true)
assert_equal(t.to_s, "(99,199;99,201;101,201;101,199)")
assert_equal(t.is_deep?, false)
t = r.texts("*", true, 10)
assert_equal(t.to_s, "(90,190;90,210;110,210;110,190)")
t = r.texts("A*", true, 10)
assert_equal(t.to_s, "(90,190;90,210;110,210;110,190)")
t = r.texts("A*", false, 10)
assert_equal(t.to_s, "")
t = r.texts("ABC", false, 10)
assert_equal(t.to_s, "(90,190;90,210;110,210;110,190)")
dss = RBA::DeepShapeStore::new
r = RBA::Region::new(top.begin_shapes_rec(l1))
t = r.texts(dss, "*", true)
assert_equal(t.to_s, "(99,199;99,201;101,201;101,199)")
assert_equal(t.is_deep?, true)
r = RBA::Region::new(top.begin_shapes_rec(l1))
t = r.texts_dots("*", true)
assert_equal(t.to_s, "(100,200;100,200)")
assert_equal(t.is_deep?, false)
dss = RBA::DeepShapeStore::new
r = RBA::Region::new(top.begin_shapes_rec(l1))
t = r.texts_dots(dss, "A*", true)
assert_equal(t.to_s, "(100,200;100,200)")
assert_equal(t.is_deep?, true)
end
# deep region tests
def test_deep1