Merge branch 'api-enhancements'

This commit is contained in:
Matthias Koefferlein 2022-02-11 19:10:21 +01:00
commit 2ed572e684
31 changed files with 1264 additions and 180 deletions

View File

@ -42,10 +42,69 @@ namespace db
// --------------------------------------------------------------------------------
// Some utilities
bool check_trailing_reserved_word (const tl::Extractor &ex0)
static const char *s_select = "select";
static const char *s_delete = "delete";
static const char *s_or = "or";
static const char *s_of = "of";
static const char *s_on = "on";
static const char *s_do = "do";
static const char *s_from = "from";
static const char *s_layer = "layer";
static const char *s_layers = "layers";
static const char *s_cell = "cell";
static const char *s_cells = "cells";
static const char *s_where = "where";
static const char *s_shapes = "shapes";
static const char *s_polygons = "polygons";
static const char *s_boxes = "boxes";
static const char *s_edges = "edges";
static const char *s_paths = "paths";
static const char *s_texts = "texts";
static const char *s_instances = "instances";
static const char *s_arrays = "arrays";
static const char *s_sorted = "sorted";
static const char *s_unique = "unique";
static const char *s_by = "by";
static const char *s_with = "with";
static const char *s_pass = "pass";
const char *s_reserved_words[] = {
s_select,
s_delete,
s_or,
s_of,
s_on,
s_do,
s_from,
s_layer,
s_layers,
s_cell,
s_cells,
s_where,
s_shapes,
s_polygons,
s_boxes,
s_edges,
s_paths,
s_texts,
s_instances,
s_arrays,
s_sorted,
s_unique,
s_by,
s_with,
s_pass
};
bool check_trailing_reserved_word (const tl::Extractor &ex0)
{
tl::Extractor ex = ex0;
return (ex.test ("do") || ex.test ("sorted") || ex.test ("pass") || ex.test ("where"));
for (size_t i = 0; i < sizeof (s_reserved_words) / sizeof (s_reserved_words[0]); ++i) {
if (ex.test (s_reserved_words[i])) {
return true;
}
}
return false;
}
// --------------------------------------------------------------------------------
@ -202,7 +261,9 @@ struct ShapeFilterPropertyIDs
ShapeFilterPropertyIDs (LayoutQuery *q)
{
bbox = q->register_property ("bbox", LQ_box);
dbbox = q->register_property ("dbbox", LQ_dbox);
shape_bbox = q->register_property ("shape_bbox", LQ_box);
shape_dbbox = q->register_property ("shape_dbbox", LQ_dbox);
shape = q->register_property ("shape", LQ_shape);
layer_info = q->register_property ("layer_info", LQ_layer);
layer_index = q->register_property ("layer_index", LQ_variant);
@ -211,7 +272,9 @@ struct ShapeFilterPropertyIDs
}
unsigned int bbox; // bbox -> The shape's bounding box
unsigned int dbbox; // dbbox -> The shape's bounding box in micrometer units
unsigned int shape_bbox; // shape_bbox -> == box
unsigned int shape_dbbox; // shape_dbbox -> == dbox
unsigned int shape; // shape -> The shape object
unsigned int layer_info; // layer_info -> The layer (a LayerInfo object)
unsigned int layer_index; // layer_index -> The layer index
@ -309,6 +372,12 @@ public:
v = tl::Variant::make_variant (m_shape->bbox ());
return true;
} else if (id == m_pids.dbbox || id == m_pids.shape_dbbox) {
tl_assert (mp_parent->layout ());
v = tl::Variant::make_variant (db::CplxTrans (mp_parent->layout ()->dbu ()) * m_shape->bbox ());
return true;
} else if (id == m_pids.shape) {
if (m_reading) {
@ -418,7 +487,9 @@ struct ChildCellFilterPropertyIDs
parent_cell_name = q->register_property ("parent_cell_name", LQ_variant);
hier_levels = q->register_property ("hier_levels", LQ_variant);
bbox = q->register_property ("bbox", LQ_box);
dbbox = q->register_property ("dbbox", LQ_dbox);
cell_bbox = q->register_property ("cell_bbox", LQ_box);
cell_dbbox = q->register_property ("cell_dbbox", LQ_dbox);
// with instance_mode == NoInstances:
if (instance_mode == NoInstances) {
@ -434,21 +505,31 @@ struct ChildCellFilterPropertyIDs
// with instance_mode != NoInstances:
if (instance_mode != NoInstances) {
path_trans = q->register_property ("path_trans", LQ_trans);
path_dtrans = q->register_property ("path_dtrans", LQ_dtrans);
trans = q->register_property ("trans", LQ_trans);
dtrans = q->register_property ("dtrans", LQ_dtrans);
inst_bbox = q->register_property ("inst_bbox", LQ_box);
inst_dbbox = q->register_property ("inst_dbbox", LQ_box);
inst = q->register_property ("inst", LQ_instance);
array_a = q->register_property ("array_a", LQ_point);
array_da = q->register_property ("array_da", LQ_dpoint);
array_na = q->register_property ("array_na", LQ_variant);
array_b = q->register_property ("array_b", LQ_point);
array_db = q->register_property ("array_db", LQ_dpoint);
array_nb = q->register_property ("array_nb", LQ_variant);
} else {
path_trans = std::numeric_limits<unsigned int>::max ();
path_dtrans = std::numeric_limits<unsigned int>::max ();
trans = std::numeric_limits<unsigned int>::max ();
dtrans = std::numeric_limits<unsigned int>::max ();
inst_bbox = std::numeric_limits<unsigned int>::max ();
inst_dbbox = std::numeric_limits<unsigned int>::max ();
inst = std::numeric_limits<unsigned int>::max ();
array_a = std::numeric_limits<unsigned int>::max ();
array_da = std::numeric_limits<unsigned int>::max ();
array_na = std::numeric_limits<unsigned int>::max ();
array_b = std::numeric_limits<unsigned int>::max ();
array_db = std::numeric_limits<unsigned int>::max ();
array_nb = std::numeric_limits<unsigned int>::max ();
}
@ -475,7 +556,9 @@ struct ChildCellFilterPropertyIDs
unsigned int parent_cell_name; // parent_cell_name -> Name of parent cell (next in path) or nil
unsigned int hier_levels; // hier_levels -> Number of hierarchy levels in path (length of path - 1)
unsigned int bbox; // bbox -> Cell bounding box
unsigned int dbbox; // dbbox -> Cell bounding box in micrometer units
unsigned int cell_bbox; // cell_bbox -> == bbox
unsigned int cell_dbbox; // cell_dbbox -> == dbbox
// with instance_mode == NoInstances:
unsigned int references; // references -> The number of instances (arefs count as 1) of this cell in the parent cell
@ -484,17 +567,22 @@ struct ChildCellFilterPropertyIDs
// with instance_mode != NoInstances:
unsigned int path_trans; // path_trans -> The transformation of that instance into the top cell
unsigned int path_dtrans; // path_dtrans -> The transformation of that instance into the top cell in micrometer units
unsigned int trans; // trans -> The transformation of that instance (first instance if an array)
unsigned int dtrans; // dtrans -> The transformation of that instance (first instance if an array) in micrometer units
unsigned int inst_bbox; // inst_bbox -> The instance bounding box in the top cell
unsigned int inst_dbbox; // inst_dbbox -> The instance bounding box in the top cell in micrometer units
unsigned int inst; // inst -> The instance object
unsigned int array_a; // array_a -> The a vector for an array instance
unsigned int array_da; // array_da -> The a vector for an array instance in micrometer units
unsigned int array_na; // array_na -> The a axis array dimension
unsigned int array_b; // array_b -> The b vector for an array instance
unsigned int array_db; // array_db -> The b vector for an array instance in micrometer units
unsigned int array_nb; // array_nb -> The b axis array dimension
// with instance_mode == ExplodedInstances:
unsigned int array_ia; // array_ia -> The a index when an array is iterated
unsigned int array_ib; // array_ib -> The b index when an array is iterated
unsigned int array_ib; // array_ib -> The b index when an array is iterated
};
class DB_PUBLIC ChildCellFilterState
@ -764,6 +852,15 @@ public:
}
return true;
} else if (id == m_pids.dbbox || id == m_pids.cell_dbbox) {
if (! layout ()->is_valid_cell_index (cell_index ())) {
v = tl::Variant ();
} else {
v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * layout ()->cell (cell_index ()).bbox ());
}
return true;
} else if (id == m_pids.cell_name) {
if (! layout ()->is_valid_cell_index (cell_index ())) {
@ -983,6 +1080,35 @@ public:
return false;
}
} else if (id == m_pids.inst_dbbox) {
if (mp_parent) {
if (m_instance_mode == ExplodedInstances) {
db::ICplxTrans t = m_parent_trans;
t *= (*m_inst)->complex_trans (*m_array_iter);
db::DBox box (db::CplxTrans (layout ()->dbu ()) * t * layout ()->cell ((*m_inst)->object ().cell_index ()).bbox ());
v = tl::Variant::make_variant (box);
return true;
} else if (m_instance_mode == ArrayInstances) {
db::ICplxTrans t = m_parent_trans;
t *= (*m_inst)->complex_trans ();
db::box_convert <db::CellInst> bc (*layout ());
db::DBox box (db::CplxTrans (layout ()->dbu ()) * t * (*m_inst)->bbox (bc));
v = tl::Variant::make_variant (box);
return true;
} else {
return false;
}
} else {
return false;
}
} else if (id == m_pids.path_trans) {
if (mp_parent) {
@ -1011,6 +1137,36 @@ public:
return true;
}
} else if (id == m_pids.path_dtrans) {
if (mp_parent) {
if (m_instance_mode == ExplodedInstances) {
db::ICplxTrans t = m_parent_trans;
t *= (*m_inst)->complex_trans (*m_array_iter);
db::CplxTrans tdbu (layout ()->dbu ());
v = tl::Variant::make_variant (tdbu * t * tdbu.inverted ());
return true;
} else if (m_instance_mode == ArrayInstances) {
db::ICplxTrans t = m_parent_trans;
t *= (*m_inst)->complex_trans ();
db::CplxTrans tdbu (layout ()->dbu ());
v = tl::Variant::make_variant (tdbu * t * tdbu.inverted ());
return true;
} else {
v = tl::Variant::make_variant (db::ICplxTrans ());
return true;
}
} else {
v = tl::Variant::make_variant (db::ICplxTrans ());
return true;
}
} else if (id == m_pids.trans) {
if (mp_parent) {
@ -1033,6 +1189,30 @@ public:
return false;
}
} else if (id == m_pids.dtrans) {
if (mp_parent) {
if (m_instance_mode == ExplodedInstances) {
db::CplxTrans tdbu (layout ()->dbu ());
v = tl::Variant::make_variant (tdbu * (*m_inst)->complex_trans (*m_array_iter) * tdbu.inverted ());
return true;
} else if (m_instance_mode == ArrayInstances) {
db::CplxTrans tdbu (layout ()->dbu ());
v = tl::Variant::make_variant (tdbu * (*m_inst)->complex_trans () * tdbu.inverted ());
return true;
} else {
return false;
}
} else {
return false;
}
} else if (id == m_pids.inst) {
if (! mp_parent || m_instance_mode == NoInstances) {
@ -1064,7 +1244,7 @@ public:
return true;
}
} else if (id == m_pids.array_a || id == m_pids.array_b || id == m_pids.array_na || id == m_pids.array_nb) {
} else if (id == m_pids.array_a || id == m_pids.array_b || id == m_pids.array_da || id == m_pids.array_db || id == m_pids.array_na || id == m_pids.array_nb) {
if (! mp_parent || m_instance_mode == NoInstances) {
return false;
@ -1074,8 +1254,12 @@ public:
if ((*m_inst)->is_regular_array (a, b, na, nb)) {
if (id == m_pids.array_a) {
v = tl::Variant::make_variant (a);
} else if (id == m_pids.array_da) {
v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * a);
} else if (id == m_pids.array_b) {
v = tl::Variant::make_variant (b);
} else if (id == m_pids.array_db) {
v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * b);
} else if (id == m_pids.array_na) {
v = na;
} else if (id == m_pids.array_nb) {
@ -1178,8 +1362,11 @@ struct CellFilterPropertyIDs
tot_weight = q->register_property ("tot_weight", LQ_variant);
instances = q->register_property ("instances", LQ_variant);
bbox = q->register_property ("bbox", LQ_box);
dbbox = q->register_property ("dbbox", LQ_dbox);
cell_bbox = q->register_property ("cell_bbox", LQ_box);
cell_dbbox = q->register_property ("cell_dbbox", LQ_dbox);
path_trans = q->register_property ("path_trans", LQ_trans);
path_dtrans = q->register_property ("path_dtrans", LQ_dtrans);
}
unsigned int path; // path -> Variant array with the indexes of the cells in that path
@ -1200,8 +1387,11 @@ struct CellFilterPropertyIDs
unsigned int tot_weight; // tot_weight -> The number of instances of this cell in the initial cell along the given path
unsigned int instances; // instances -> The number of instances of this cell in the previous cell (or over all if there is no previous cell)
unsigned int bbox; // bbox -> Cell bounding box
unsigned int dbbox; // dbbox -> Cell bounding box in micrometer units
unsigned int cell_bbox; // cell_bbox -> == bbox
unsigned int cell_dbbox; // cell_dbbox -> == dbbox
unsigned int path_trans; // parent_trans -> transformation to initial cell
unsigned int path_dtrans; // parent_dtrans -> transformation to initial cell in micrometer units
};
class DB_PUBLIC CellFilterState
@ -1283,6 +1473,15 @@ public:
}
return true;
} else if (id == m_pids.dbbox || id == m_pids.cell_dbbox) {
if (! layout ()->is_valid_cell_index (*m_cell)) {
v = tl::Variant ();
} else {
v = tl::Variant::make_variant (db::CplxTrans (layout ()->dbu ()) * layout ()->cell (*m_cell).bbox ());
}
return true;
} else if (id == m_pids.cell_name || id == m_pids.initial_cell_name) {
if (! layout ()->is_valid_cell_index (*m_cell)) {
@ -1363,6 +1562,11 @@ public:
v = tl::Variant::make_variant (db::ICplxTrans ());
return true;
} else if (id == m_pids.path_dtrans) {
v = tl::Variant::make_variant (db::DCplxTrans ());
return true;
} else {
return FilterStateBase::get_property (id, v);
}
@ -2225,7 +2429,7 @@ parse_cell_name_filter_element (tl::Extractor &ex, LayoutQuery *q, ChildCellFilt
std::unique_ptr<FilterBracket> b (new FilterBracket (q));
do {
parse_cell_name_filter_seq (ex, q, b.get (), instance_mode, reading);
} while (ex.test (",") || ex.test ("or"));
} while (ex.test (",") || ex.test (s_or));
// TODO: do this in the optimization
if (b->children ().size () == 1 && dynamic_cast<FilterBracket *> (b->children ()[0])) {
@ -2362,21 +2566,21 @@ parse_cell_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bo
std::unique_ptr<FilterBracket> b (new FilterBracket (q));
if (ex.test ("instances")) {
(ex.test ("of") || ex.test ("from")) && (ex.test ("cells") || ex.test ("cell"));
if (ex.test (s_instances)) {
(ex.test (s_of) || ex.test (s_from)) && (ex.test (s_cells) || ex.test (s_cell));
// Because an array member cannot be modified we use ArrayInstances in the modification case always
parse_cell_name_filter_seq (ex, q, b.get (), reading ? ExplodedInstances : ArrayInstances, reading);
} else if (ex.test ("arrays")) {
(ex.test ("of") || ex.test ("from")) && (ex.test ("cells") || ex.test ("cell"));
} else if (ex.test (s_arrays)) {
(ex.test (s_of) || ex.test (s_from)) && (ex.test (s_cells) || ex.test (s_cell));
parse_cell_name_filter_seq (ex, q, b.get (), ArrayInstances, reading);
} else {
ex.test ("cells") || ex.test ("cell");
ex.test (s_cells) || ex.test (s_cell);
parse_cell_name_filter_seq (ex, q, b.get (), NoInstances, reading);
}
FilterBase *fl = 0, *f = 0;
if (with_where_clause && ex.test ("where")) {
if (with_where_clause && ex.test (s_where)) {
std::string expr = tl::Eval::parse_expr (ex, true);
@ -2407,22 +2611,22 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re
{
unsigned int sf = (unsigned int) db::ShapeIterator::Nothing;
do {
if (ex.test ("shapes")) {
if (ex.test (s_shapes)) {
sf |= (unsigned int) db::ShapeIterator::All;
} else if (ex.test ("polygons")) {
} else if (ex.test (s_polygons)) {
sf |= (unsigned int) db::ShapeIterator::Polygons;
} else if (ex.test ("boxes")) {
} else if (ex.test (s_boxes)) {
sf |= (unsigned int) db::ShapeIterator::Boxes;
} else if (ex.test ("edges")) {
} else if (ex.test (s_edges)) {
sf |= (unsigned int) db::ShapeIterator::Edges;
} else if (ex.test ("paths")) {
} else if (ex.test (s_paths)) {
sf |= (unsigned int) db::ShapeIterator::Paths;
} else if (ex.test ("texts")) {
} else if (ex.test (s_texts)) {
sf |= (unsigned int) db::ShapeIterator::Texts;
} else {
break;
}
} while (ex.test (",") || ex.test ("or"));
} while (ex.test (",") || ex.test (s_or));
db::ShapeIterator::flags_type shapes = (db::ShapeIterator::flags_type) sf;
@ -2430,12 +2634,12 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re
db::LayerMap lm;
if (ex.test ("on")) {
ex.test ("layer") || ex.test ("layers");
if (ex.test (s_on)) {
ex.test (s_layer) || ex.test (s_layers);
lm.map_expr (ex, 0);
}
ex.test ("of") || ex.test ("from");
ex.test (s_of) || ex.test (s_from);
std::unique_ptr<FilterBracket> b (new FilterBracket (q));
parse_cell_filter (ex, q, b.get (), false, reading);
@ -2451,7 +2655,7 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re
bracket->add_child (f);
fl->connect (f);
if (ex.test ("where")) {
if (ex.test (s_where)) {
std::string expr = tl::Eval::parse_expr (ex, true);
@ -2472,7 +2676,7 @@ parse_filter (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool re
void
parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool reading)
{
if (ex.test ("select")) {
if (ex.test (s_select)) {
std::vector<std::string> expressions;
@ -2480,7 +2684,7 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool
expressions.push_back (tl::Eval::parse_expr (ex, true));
} while (ex.test (","));
ex.expect ("from");
ex.expect (s_from);
std::unique_ptr<FilterBracket> b (new FilterBracket (q));
parse_filter (ex, q, b.get (), true);
@ -2488,10 +2692,10 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool
bool unique = false;
std::string sort_expression;
if (ex.test ("sorted")) {
ex.test ("by");
if (ex.test (s_sorted)) {
ex.test (s_by);
sort_expression = tl::Eval::parse_expr (ex, true);
unique = ex.test ("unique");
unique = ex.test (s_unique);
}
FilterBase *f = b.release ();
@ -2504,16 +2708,16 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool
bracket->connect_exit (ff);
} else if (! reading && ex.test ("with")) {
} else if (! reading && ex.test (s_with)) {
std::unique_ptr<FilterBracket> b (new FilterBracket (q));
parse_filter (ex, q, b.get (), false);
ex.expect ("do");
ex.expect (s_do);
std::string expression = tl::Eval::parse_expr (ex, true);
bool transparent = ex.test ("pass");
bool transparent = ex.test (s_pass);
FilterBase *f = b.release ();
bracket->add_child (f);
@ -2525,12 +2729,12 @@ parse_statement (tl::Extractor &ex, LayoutQuery *q, FilterBracket *bracket, bool
bracket->connect_exit (ff);
} else if (! reading && ex.test ("delete")) {
} else if (! reading && ex.test (s_delete)) {
std::unique_ptr<FilterBracket> b (new FilterBracket (q));
parse_filter (ex, q, b.get (), false);
bool transparent = ex.test ("pass");
bool transparent = ex.test (s_pass);
FilterBase *f = b.release ();
bracket->add_child (f);
@ -2554,7 +2758,10 @@ LayoutQuery::LayoutQuery (const std::string &query)
tl::Extractor ex (query.c_str ());
parse_statement (ex, this, r.get (), false);
ex.expect_end ();
if (! ex.at_end ()) {
ex.error (tl::to_string (tr ("Unexpected text")));
}
r->optimize ();
mp_root = r.release ();

View File

@ -51,11 +51,14 @@ enum LayoutQueryPropertyType
LQ_variant,
LQ_shape,
LQ_trans,
LQ_dtrans,
LQ_layer,
LQ_instance,
LQ_cell,
LQ_point,
LQ_dpoint,
LQ_box,
LQ_dbox,
LQ_polygon,
LQ_path,
LQ_edge,

View File

@ -83,7 +83,6 @@ RecursiveInstanceIterator &RecursiveInstanceIterator::operator= (const Recursive
RecursiveInstanceIterator::RecursiveInstanceIterator ()
{
// anything. Not necessary reasonable.
mp_layout = 0;
mp_top_cell = 0;
mp_cell = 0;
m_overlapping = false;
@ -97,7 +96,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator ()
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const box_type &region, bool overlapping)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_layout = const_cast<db::Layout *> (&layout);
mp_top_cell = &cell;
m_overlapping = overlapping;
init ();
@ -107,7 +106,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout,
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell, const region_type &region, bool overlapping)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_layout = const_cast<db::Layout *> (&layout);
mp_top_cell = &cell;
m_overlapping = overlapping;
init ();
@ -117,7 +116,7 @@ RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout,
RecursiveInstanceIterator::RecursiveInstanceIterator (const layout_type &layout, const cell_type &cell)
: m_box_convert (layout)
{
mp_layout = &layout;
mp_layout = const_cast<db::Layout *> (&layout);
mp_top_cell = &cell;
m_overlapping = false;
init ();
@ -272,6 +271,7 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const
m_inst_array_iterators.clear ();
m_cells.clear ();
m_trans = cplx_trans_type ();
m_target_tree.clear ();
m_local_region_stack.clear ();
m_local_region_stack.push_back (m_region);
@ -300,10 +300,9 @@ RecursiveInstanceIterator::validate (RecursiveInstanceReceiver *receiver) const
}
if (mp_top_cell) {
if (mp_top_cell && mp_layout) {
if (! m_all_targets) {
m_target_tree.clear ();
mp_top_cell->collect_called_cells (m_target_tree);
}
@ -501,6 +500,8 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c
void
RecursiveInstanceIterator::down (RecursiveInstanceReceiver *receiver) const
{
tl_assert (mp_layout);
m_trans_stack.push_back (m_trans);
m_cells.push_back (mp_cell);

View File

@ -29,6 +29,7 @@
#include "dbLayout.h"
#include "dbInstElement.h"
#include "tlAssert.h"
#include "tlObject.h"
#include <map>
#include <set>
@ -180,7 +181,7 @@ public:
*/
const layout_type *layout () const
{
return mp_layout;
return mp_layout.get ();
}
/**
@ -544,7 +545,7 @@ private:
std::set<db::cell_index_type> m_targets;
bool m_all_targets;
const layout_type *mp_layout;
tl::weak_ptr<layout_type> mp_layout;
const cell_type *mp_top_cell;
box_type m_region;

View File

@ -93,7 +93,6 @@ RecursiveShapeIterator::RecursiveShapeIterator ()
// anything. Not necessary reasonable.
m_layer = 0;
m_has_layers = false;
mp_layout = 0;
mp_shapes = 0;
mp_top_cell = 0;
mp_cell = 0;
@ -113,7 +112,6 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes)
{
m_layer = 0;
m_has_layers = false;
mp_layout = 0;
mp_shapes = &shapes;
mp_top_cell = 0;
m_overlapping = false;
@ -125,7 +123,6 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
{
m_layer = 0;
m_has_layers = false;
mp_layout = 0;
mp_shapes = &shapes;
mp_top_cell = 0;
m_overlapping = overlapping;
@ -137,7 +134,6 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
{
m_layer = 0;
m_has_layers = false;
mp_layout = 0;
mp_shapes = &shapes;
mp_top_cell = 0;
m_overlapping = overlapping;
@ -150,7 +146,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
{
m_layer = layer;
m_has_layers = false;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
@ -163,7 +159,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
{
m_layer = layer;
m_has_layers = false;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
@ -176,7 +172,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
{
m_layer = layer;
m_has_layers = false;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = false;
@ -190,7 +186,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
m_layer = 0;
m_layers = layers;
m_has_layers = true;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
@ -204,7 +200,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
m_layer = 0;
m_layers = layers;
m_has_layers = true;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
@ -218,7 +214,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
m_layer = 0;
m_layers = layers;
m_has_layers = true;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = false;
@ -232,7 +228,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
m_layer = 0;
m_layers.insert (m_layers.end (), layers.begin (), layers.end ());
m_has_layers = true;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
@ -246,7 +242,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
m_layer = 0;
m_layers.insert (m_layers.end (), layers.begin (), layers.end ());
m_has_layers = true;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
@ -260,7 +256,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
m_layer = 0;
m_layers.insert (m_layers.end (), layers.begin (), layers.end ());
m_has_layers = true;
mp_layout = &layout;
mp_layout.reset (const_cast<db::Layout *> (&layout));
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = false;
@ -691,6 +687,8 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
if (! m_inst.at_end () && int (m_inst_iterators.size ()) < m_max_depth) {
tl_assert (mp_layout);
// determine whether the cell is empty with respect to the layers specified
bool is_empty = false;
if (! m_has_layers) {
@ -754,6 +752,8 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
void
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
{
tl_assert (mp_layout);
m_trans_stack.push_back (m_trans);
m_cells.push_back (mp_cell);

View File

@ -29,6 +29,7 @@
#include "dbLayout.h"
#include "dbInstElement.h"
#include "tlAssert.h"
#include "tlObject.h"
#include <map>
#include <set>
@ -306,7 +307,7 @@ public:
*/
const layout_type *layout () const
{
return mp_layout;
return mp_layout.get ();
}
/**
@ -765,7 +766,7 @@ private:
std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans;
const layout_type *mp_layout;
tl::weak_ptr<layout_type> mp_layout;
const cell_type *mp_top_cell;
const shapes_type *mp_shapes;

View File

@ -49,6 +49,11 @@ struct box_defs
return c.release ();
}
static C world ()
{
return C::world ();
}
static C *new_v ()
{
return new C ();
@ -132,6 +137,22 @@ struct box_defs
"are not provided in the correct order (i.e. right < left), these are "
"swapped."
) +
method ("world", &world,
"@brief Gets the 'world' box\n"
"The world box is the biggest box that can be represented. So it is basically 'all'. The "
"world box behaves neutral on intersections for example. In other operations such as displacement or transformations, "
"the world box may render unexpected results because of coordinate overflow.\n"
"\n"
"The world box can be used\n"
"@ul\n"
" @li for comparison ('==', '!=', '<') @/li\n"
" @li in union and intersection ('+' and '&') @/li\n"
" @li in relations (\\contains?, \\overlaps?, \\touches?) @/li\n"
" @li as 'all' argument in region queries @/li\n"
"@/ul\n"
"\n"
"This method has been introduced in version 0.28."
) +
method ("p1", &C::p1,
"@brief Gets the lower left point of the box\n"
) +

View File

@ -68,6 +68,12 @@ struct cell_inst_array_defs
return new C ();
}
static C *
new_cell_inst_vector (db::cell_index_type ci, const vector_type &v)
{
return new C (db::CellInst (ci), trans_type (v));
}
static C *
new_cell_inst (db::cell_index_type ci, const trans_type &t)
{
@ -84,6 +90,13 @@ struct cell_inst_array_defs
}
}
static C *
new_cell_inst_array_vector (db::cell_index_type ci, const vector_type &v,
const vector_type &a, const vector_type &b, unsigned int na, unsigned int nb)
{
return new C (db::CellInst (ci), trans_type (v), a, b, na, nb);
}
static C *
new_cell_inst_array (db::cell_index_type ci, const trans_type &t,
const vector_type &a, const vector_type &b, unsigned int na, unsigned int nb)
@ -397,6 +410,12 @@ struct cell_inst_array_defs
"@param cell_index The cell to instantiate\n"
"@param trans The transformation by which to instantiate the cell\n"
) +
gsi::constructor ("new", &new_cell_inst_vector, gsi::arg ("cell_index"), gsi::arg ("disp"),
"@brief Creates a single cell instance\n"
"@param cell_index The cell to instantiate\n"
"@param disp The displacement\n"
"This convenience initializer has been introduced in version 0.28."
) +
gsi::constructor ("new", &new_cell_inst_cplx, gsi::arg ("cell_index"), gsi::arg ("trans"),
"@brief Creates a single cell instance with a complex transformation\n"
"@param cell_index The cell to instantiate\n"
@ -415,6 +434,17 @@ struct cell_inst_array_defs
"Starting with version 0.25 the displacements are of vector type."
)
) +
gsi::constructor ("new", &new_cell_inst_array_vector, gsi::arg ("cell_index"), gsi::arg ("disp"), gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("na"), gsi::arg ("nb"),
"@brief Creates a single cell instance\n"
"@param cell_index The cell to instantiate\n"
"@param disp The basic displacement of the first instance\n"
"@param a The displacement vector of the array in the 'a' axis\n"
"@param b The displacement vector of the array in the 'b' axis\n"
"@param na The number of placements in the 'a' axis\n"
"@param nb The number of placements in the 'b' axis\n"
"\n"
"This convenience initializer has been introduced in version 0.28."
) +
gsi::constructor ("new", &new_cell_inst_array_cplx, gsi::arg ("cell_index"), gsi::arg ("trans"), gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("na"), gsi::arg ("nb"),
"@brief Creates a single cell instance with a complex transformation\n"
"@param cell_index The cell to instantiate\n"

View File

@ -353,6 +353,33 @@ static db::cell_index_type clip (db::Layout *l, db::cell_index_type c, const db:
return cc [0];
}
static db::cell_index_type clip_dbox (db::Layout *l, db::cell_index_type c, const db::DBox &box)
{
std::vector <db::Box> boxes;
boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box);
std::vector <db::cell_index_type> cc = db::clip_layout(*l, *l, c, boxes, true);
tl_assert (! cc.empty ());
return cc [0];
}
static db::Cell *clip_cell_dbox (db::Layout *l, const db::Cell &c, const db::DBox &box)
{
std::vector <db::Box> boxes;
boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box);
std::vector <db::cell_index_type> cc = db::clip_layout(*l, *l, c.cell_index (), boxes, true);
tl_assert (! cc.empty ());
return &l->cell (cc [0]);
}
static db::Cell *clip_cell (db::Layout *l, const db::Cell &c, const db::Box &box)
{
std::vector <db::Box> boxes;
boxes.push_back (box);
std::vector <db::cell_index_type> cc = db::clip_layout(*l, *l, c.cell_index (), boxes, true);
tl_assert (! cc.empty ());
return &l->cell (cc [0]);
}
static db::cell_index_type clip_into (const db::Layout *l, db::cell_index_type c, db::Layout *t, const db::Box &box)
{
std::vector <db::Box> boxes;
@ -362,14 +389,92 @@ static db::cell_index_type clip_into (const db::Layout *l, db::cell_index_type c
return cc [0];
}
static db::cell_index_type clip_into_dbox (const db::Layout *l, db::cell_index_type c, db::Layout *t, const db::DBox &box)
{
std::vector <db::Box> boxes;
boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box);
std::vector <db::cell_index_type> cc = db::clip_layout(*l, *t, c, boxes, true);
tl_assert (! cc.empty ());
return cc [0];
}
static db::Cell *clip_into_cell (const db::Layout *l, const db::Cell &c, db::Layout *t, const db::Box &box)
{
std::vector <db::Box> boxes;
boxes.push_back (box);
std::vector <db::cell_index_type> cc = db::clip_layout(*l, *t, c.cell_index (), boxes, true);
tl_assert (! cc.empty ());
return &t->cell (cc [0]);
}
static db::Cell *clip_into_cell_dbox (const db::Layout *l, const db::Cell &c, db::Layout *t, const db::DBox &box)
{
std::vector <db::Box> boxes;
boxes.push_back (db::CplxTrans (l->dbu ()).inverted () * box);
std::vector <db::cell_index_type> cc = db::clip_layout(*l, *t, c.cell_index (), boxes, true);
tl_assert (! cc.empty ());
return &t->cell (cc [0]);
}
static std::vector<db::Box> transform_boxes (const db::Layout *l, const std::vector<db::DBox> &boxes)
{
std::vector<db::Box> result;
result.reserve (boxes.size ());
db::VCplxTrans t = db::CplxTrans (l->dbu ()).inverted ();
for (std::vector<db::DBox>::const_iterator i = boxes.begin (); i != boxes.end (); ++i) {
result.push_back (t * *i);
}
return result;
}
static std::vector<db::Cell *> to_cell_refs (db::Layout *l, const std::vector<db::cell_index_type> &cell_indexes)
{
std::vector<db::Cell *> result;
result.reserve (cell_indexes.size ());
for (std::vector<db::cell_index_type>::const_iterator i = cell_indexes.begin (); i != cell_indexes.end (); ++i) {
result.push_back (&l->cell (*i));
}
return result;
}
static std::vector<db::cell_index_type> multi_clip (db::Layout *l, db::cell_index_type c, const std::vector<db::Box> &boxes)
{
return db::clip_layout(*l, *l, c, boxes, true);
return db::clip_layout (*l, *l, c, boxes, true);
}
static std::vector<db::Cell *> multi_clip_cells (db::Layout *l, const db::Cell &c, const std::vector<db::Box> &boxes)
{
return to_cell_refs (l, db::clip_layout (*l, *l, c.cell_index (), boxes, true));
}
static std::vector<db::cell_index_type> multi_clip_dboxes (db::Layout *l, db::cell_index_type c, const std::vector<db::DBox> &boxes)
{
return db::clip_layout (*l, *l, c, transform_boxes (l, boxes), true);
}
static std::vector<db::Cell *> multi_clip_cells_dboxes (db::Layout *l, const db::Cell &c, const std::vector<db::DBox> &boxes)
{
return to_cell_refs (l, db::clip_layout (*l, *l, c.cell_index (), transform_boxes (l, boxes), true));
}
static std::vector<db::cell_index_type> multi_clip_into (db::Layout *l, db::cell_index_type c, db::Layout *t, const std::vector<db::Box> &boxes)
{
return db::clip_layout(*l, *t, c, boxes, true);
return db::clip_layout (*l, *t, c, boxes, true);
}
static std::vector<db::Cell *> multi_clip_into_cells (db::Layout *l, const db::Cell &c, db::Layout *t, const std::vector<db::Box> &boxes)
{
return to_cell_refs (l, db::clip_layout (*l, *t, c.cell_index (), boxes, true));
}
static std::vector<db::cell_index_type> multi_clip_into_dboxes (db::Layout *l, db::cell_index_type c, db::Layout *t, const std::vector<db::DBox> &boxes)
{
return db::clip_layout (*l, *t, c, transform_boxes (l, boxes), true);
}
static std::vector<db::Cell *> multi_clip_into_cells_dboxes (db::Layout *l, const db::Cell &c, db::Layout *t, const std::vector<db::DBox> &boxes)
{
return to_cell_refs (l, db::clip_layout (*l, *t, c.cell_index (), transform_boxes (l, boxes), true));
}
static unsigned int get_layer0 (db::Layout *l)
@ -1104,7 +1209,18 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"@param properties_id The properties ID to get the properties for\n"
"@return The array of variants (see \\properties_id)\n"
) +
gsi::method_ext ("top_cell", &top_cell,
gsi::method ("unique_cell_name", &db::Layout::uniquify_cell_name, gsi::arg ("name"),
"@brief Creates a new unique cell name from the given name\n"
"@return A unique name derived from the argument\n"
"\n"
"If a cell with the given name exists, a suffix will be added to make the name unique. "
"Otherwise, the argument will be returned unchanged.\n"
"\n"
"The returned name can be used to rename cells without risk of creating name clashes.\n"
"\n"
"This method has been introduced in version 0.28."
) +
gsi::method_ext ("top_cell", &top_cell,
"@brief Returns the top cell object\n"
"@return The \\Cell object of the top cell\n"
"If the layout has a single top cell, this method returns the top cell's \\Cell object.\n"
@ -1146,14 +1262,21 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduce in version 0.23 and replaces \\add_cell.\n"
) +
gsi::method_ext ("create_cell", &create_cell2, gsi::arg ("name"), gsi::arg ("params"),
"@brief Creates a cell as a PCell variant with the given name\n"
"@param name The name of the PCell and the name of the cell to create\n"
gsi::method_ext ("create_cell", &create_cell2, gsi::arg ("pcell_name"), gsi::arg ("params"),
"@brief Creates a cell as a PCell variant for the PCell with the given name\n"
"@param pcell_name The name of the PCell and also the name of the cell to create\n"
"@param params The PCell parameters (key/value dictionary)\n"
"@return The \\Cell object of the newly created cell.\n"
"@return The \\Cell object of the newly created cell or an existing cell if the PCell has already been used with these parameters.\n"
"\n"
"This method will look up the PCell by the given name and create a new PCell variant "
"with the given parameters. The parameters are specified as a key/value dictionary with "
"PCells are instantiated by creating a PCell variant. A PCell variant is linked to the PCell and represents "
"this PCell with a particular parameter set.\n"
"\n"
"This method will look up the PCell by the PCell name and create a new PCell variant "
"for the given parameters. If the PCell has already been instantiated with the same parameters, the "
"original variant will be returned. Hence this method is not strictly creating a cell - only if the required variant has "
"not been created yet.\n"
"\n"
"The parameters are specified as a key/value dictionary with "
"the names being the ones from the PCell declaration.\n"
"\n"
"If no PCell with the given name exists, nil is returned.\n"
@ -1164,25 +1287,34 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"@brief Creates a cell with the given name\n"
"@param name The name of the library cell and the name of the cell to create\n"
"@param lib_name The name of the library where to take the cell from\n"
"@return The \\Cell object of the newly created cell.\n"
"@return The \\Cell object of the newly created cell or an existing cell if the library cell has already been used in this layout.\n"
"\n"
"Library cells are imported by creating a 'library proxy'. This is a cell which represents "
"the library cell in the framework of the current layout. The library proxy is linked to the "
"library and will be updated if the library cell is changed.\n"
"\n"
"This method will look up the cell by the given name in the specified library and create a new library proxy for this cell.\n"
"If the same library cell has already been used, the original library proxy is returned. Hence, strictly speaking this "
"method does not always create a new cell but may return a reference to an existing cell.\n"
"\n"
"This method will look up the cell by the given name in the specified library and create a new library proxy to this cell.\n"
"If the library name is not valid, nil is returned.\n"
"\n"
"This method has been introduce in version 0.24.\n"
) +
gsi::method_ext ("create_cell", &create_cell4, gsi::arg ("name"), gsi::arg ("lib_name"), gsi::arg ("params"),
"@brief Creates a cell with the given name\n"
"@param name The name of the PCell and the name of the cell to create\n"
gsi::method_ext ("create_cell", &create_cell4, gsi::arg ("pcell_name"), gsi::arg ("lib_name"), gsi::arg ("params"),
"@brief Creates a cell for a PCell with the given PCell name from the given library\n"
"@param pcell_name The name of the PCell and also the name of the cell to create\n"
"@param lib_name The name of the library where to take the PCell from\n"
"@param params The PCell parameters (key/value dictionary)\n"
"@return The \\Cell object of the newly created cell.\n"
"@return The \\Cell object of the newly created cell or an existing cell if this PCell has already been used with the given parameters\n"
"\n"
"This method will look up the PCell by the given name in the specified library and create a new PCell variant "
"with the given parameters. The parameters are specified as a key/value dictionary with "
"This method will look up the PCell by the PCell name in the specified library and create a new PCell variant "
"for the given parameters plus the library proxy. The parameters must be specified as a key/value dictionary with "
"the names being the ones from the PCell declaration.\n"
"\n"
"If no PCell with the given name exists or the library name is not valid, nil is returned.\n"
"If no PCell with the given name exists or the library name is not valid, nil is returned. Note that "
"this function - despite the name - may not always create a new cell, but return an existing cell if the "
"PCell from the library has already been used with the given parameters.\n"
"\n"
"This method has been introduce in version 0.24.\n"
) +
@ -1194,7 +1326,10 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"is returns a \\Cell object (\\create_cell).\n"
) +
gsi::method ("rename_cell", &db::Layout::rename_cell, gsi::arg ("index"), gsi::arg ("name"),
"@brief name\n"
"@brief Renames the cell with given index\n"
"The cell with the given index is renamed to the given name. NOTE: it is not ensured that the name is unique. "
"This method allows assigning identical names to different cells which usually breaks things.\n"
"Consider using \\unique_cell_name to generate truely unique names.\n"
) +
gsi::method ("delete_cell", &db::Layout::delete_cell, gsi::arg ("cell_index"),
"@brief Deletes a cell \n"
@ -1916,6 +2051,30 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been added in version 0.21.\n"
) +
gsi::method_ext ("clip", &clip_dbox, gsi::arg ("cell"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The cell index of the cell to clip\n"
"@param box The clip box in micrometer units\n"
"@return The index of the new cell\n"
"\n"
"This variant which takes a micrometer-unit box has been added in version 0.28."
) +
gsi::method_ext ("clip", &clip_cell, gsi::arg ("cell"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The cell reference of the cell to clip\n"
"@param box The clip box in database units\n"
"@return The reference to the new cell\n"
"\n"
"This variant which takes cell references instead of cell indexes has been added in version 0.28."
) +
gsi::method_ext ("clip", &clip_cell_dbox, gsi::arg ("cell"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The cell reference of the cell to clip\n"
"@param box The clip box in micrometer units\n"
"@return The reference to the new cell\n"
"\n"
"This variant which takes a micrometer-unit box and cell references has been added in version 0.28."
) +
gsi::method_ext ("clip_into", &clip_into, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The cell index of the cell to clip\n"
@ -1935,8 +2094,35 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been added in version 0.21.\n"
) +
gsi::method_ext ("clip_into", &clip_into_dbox, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The cell index of the cell to clip\n"
"@param box The clip box in micrometer units\n"
"@param target The target layout\n"
"@return The index of the new cell in the target layout\n"
"\n"
"This variant which takes a micrometer-unit box has been added in version 0.28."
) +
gsi::method_ext ("clip_into", &clip_into_cell, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The reference to the cell to clip\n"
"@param box The clip box in database units\n"
"@param target The target layout\n"
"@return The reference to the new cell in the target layout\n"
"\n"
"This variant which takes cell references instead of cell indexes has been added in version 0.28."
) +
gsi::method_ext ("clip_into", &clip_into_cell_dbox, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("box"),
"@brief Clips the given cell by the given rectangle and produce a new cell with the clip\n"
"@param cell The reference to the cell to clip\n"
"@param box The clip box in micrometer units\n"
"@param target The target layout\n"
"@return The reference to the new cell in the target layout\n"
"\n"
"This variant which takes a micrometer-unit box and cell references has been added in version 0.28."
) +
gsi::method_ext ("multi_clip", &multi_clip, gsi::arg ("cell"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produce new cells with the clips, one for each rectangle.\n"
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The cell index of the cell to clip\n"
"@param boxes The clip boxes in database units\n"
"@return The indexes of the new cells\n"
@ -1949,8 +2135,32 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been added in version 0.21.\n"
) +
gsi::method_ext ("multi_clip", &multi_clip_dboxes, gsi::arg ("cell"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The cell index of the cell to clip\n"
"@param boxes The clip boxes in micrometer units\n"
"@return The indexes of the new cells\n"
"\n"
"This variant which takes micrometer-unit boxes has been added in version 0.28."
) +
gsi::method_ext ("multi_clip", &multi_clip_cells, gsi::arg ("cell"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The reference to the cell to clip\n"
"@param boxes The clip boxes in database units\n"
"@return The references to the new cells\n"
"\n"
"This variant which takes cell references has been added in version 0.28."
) +
gsi::method_ext ("multi_clip", &multi_clip_cells_dboxes, gsi::arg ("cell"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The reference to the cell to clip\n"
"@param boxes The clip boxes in micrometer units\n"
"@return The references to the new cells\n"
"\n"
"This variant which takes cell references and micrometer-unit boxes has been added in version 0.28."
) +
gsi::method_ext ("multi_clip_into", &multi_clip_into, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produce new cells with the clips, one for each rectangle.\n"
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The cell index of the cell to clip\n"
"@param boxes The clip boxes in database units\n"
"@param target The target layout\n"
@ -1969,6 +2179,33 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been added in version 0.21.\n"
) +
gsi::method_ext ("multi_clip_into", &multi_clip_into_dboxes, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The cell index of the cell to clip\n"
"@param boxes The clip boxes in database units\n"
"@param target The target layout\n"
"@return The indexes of the new cells\n"
"\n"
"This variant which takes micrometer-unit boxes has been added in version 0.28."
) +
gsi::method_ext ("multi_clip_into", &multi_clip_into_cells, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The reference the cell to clip\n"
"@param boxes The clip boxes in database units\n"
"@param target The target layout\n"
"@return The references to the new cells\n"
"\n"
"This variant which takes cell references boxes has been added in version 0.28."
) +
gsi::method_ext ("multi_clip_into", &multi_clip_into_cells_dboxes, gsi::arg ("cell"), gsi::arg ("target"), gsi::arg ("boxes"),
"@brief Clips the given cell by the given rectangles and produces new cells with the clips, one for each rectangle.\n"
"@param cell The reference the cell to clip\n"
"@param boxes The clip boxes in micrometer units\n"
"@param target The target layout\n"
"@return The references to the new cells\n"
"\n"
"This variant which takes cell references and micrometer-unit boxes has been added in version 0.28."
) +
gsi::method ("convert_cell_to_static", &db::Layout::convert_cell_to_static, gsi::arg ("cell_index"),
"@brief Converts a PCell or library cell to a usual (static) cell\n"
"@return The index of the new cell\n"

View File

@ -111,7 +111,9 @@ char shape_query_property_name[] = "shape";
char layer_index_query_property_name[] = "layer_index";
char inst_query_property_name[] = "inst";
char path_trans_query_property_name[] = "path_trans";
char path_dtrans_query_property_name[] = "path_dtrans";
char trans_query_property_name[] = "trans";
char dtrans_query_property_name[] = "dtrans";
char cell_index_query_property_name[] = "cell_index";
char cell_query_property_name[] = "cell";
char parent_cell_index_query_property_name[] = "parent_cell_index";
@ -138,7 +140,9 @@ Class<db::LayoutQueryIterator> decl_LayoutQueryIterator ("db", "LayoutQueryItera
make_shortcut_method<layer_index_query_property_name>() +
make_shortcut_method<inst_query_property_name>() +
make_shortcut_method<path_trans_query_property_name>() +
make_shortcut_method<path_dtrans_query_property_name>() +
make_shortcut_method<trans_query_property_name>() +
make_shortcut_method<dtrans_query_property_name>() +
make_shortcut_method<cell_index_query_property_name>() +
make_shortcut_method<cell_query_property_name>() +
make_shortcut_method<parent_cell_index_query_property_name>() +

View File

@ -965,9 +965,9 @@ struct polygon_defs
poly->size (d, d, mode);
}
static void size_d (C *poly, coord_type d)
static void size_dvm (C *poly, const db::Vector &dv, unsigned int mode)
{
poly->size (d, d, 2);
poly->size (dv.x (), dv.y (), mode);
}
static C sized_xy (const C *poly, coord_type dx, coord_type dy, unsigned int mode)
@ -980,9 +980,9 @@ struct polygon_defs
return poly->sized (d, d, mode);
}
static C sized_d (const C *poly, coord_type d)
static C sized_dvm (const C *poly, const db::Vector &dv, unsigned int mode)
{
return poly->sized (d, d, 2);
return poly->sized (dv.x (), dv.y (), mode);
}
static bool inside (const C *poly, point_type pt)
@ -1272,7 +1272,19 @@ struct polygon_defs
"result = ep.simple_merge_p2p([ poly ], false, false, 1)\n"
"@/code\n"
) +
method_ext ("size", &size_dm, gsi::arg ("d"), gsi::arg ("mode"),
method_ext ("size", &size_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2),
"@brief Sizes the polygon (biasing)\n"
"\n"
"This method is equivalent to\n"
"@code\n"
"size(dv.x, dv.y, mode)\n"
"@/code\n"
"\n"
"See \\size for a detailed description.\n"
"\n"
"This version has been introduced in version 0.28.\n"
) +
method_ext ("size", &size_dm, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2),
"@brief Sizes the polygon (biasing)\n"
"\n"
"Shifts the contour outwards (d>0) or inwards (d<0).\n"
@ -1294,7 +1306,19 @@ struct polygon_defs
"\n"
"This method has been introduced in version 0.23.\n"
) +
method_ext ("sized", &sized_dm, gsi::arg ("d"), gsi::arg ("mode"),
method_ext ("sized", &sized_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2),
"@brief Sizes the polygon (biasing) without modifying self\n"
"\n"
"This method is equivalent to\n"
"@code\n"
"sized(dv.x, dv.y, mode)\n"
"@/code\n"
"\n"
"See \\size and \\sized for a detailed description.\n"
"\n"
"This version has been introduced in version 0.28.\n"
) +
method_ext ("sized", &sized_dm, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2),
"@brief Sizes the polygon (biasing) without modifying self\n"
"\n"
"Shifts the contour outwards (d>0) or inwards (d<0).\n"
@ -1305,28 +1329,6 @@ struct polygon_defs
"\n"
"See \\size and \\sized for a detailed description.\n"
) +
method_ext ("sized", &sized_d, gsi::arg ("d"),
"@brief Sizes the polygon (biasing)\n"
"\n"
"@brief Sizing (biasing) without modifying self\n"
"This method is equivalent to\n"
"@code\n"
"sized(d, d, 2)\n"
"@/code\n"
"\n"
"See \\size and \\sized for a detailed description.\n"
) +
method_ext ("size", &size_d, gsi::arg ("d"),
"@brief Sizes the polygon (biasing)\n"
"\n"
"Shifts the contour outwards (d>0) or inwards (d<0).\n"
"This method is equivalent to\n"
"@code\n"
"size(d, d, 2)\n"
"@/code\n"
"\n"
"See \\size for a detailed description.\n"
) +
method ("holes", &C::holes,
"@brief Returns the number of holes"
) +

View File

@ -30,6 +30,31 @@
namespace gsi
{
namespace {
/**
* @brief A wrapper that allows using "each" on the iterator
*/
class IteratorIterator
{
public:
typedef db::RecursiveInstanceIterator value_type;
typedef db::RecursiveInstanceIterator &reference;
typedef db::RecursiveInstanceIterator *pointer;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
IteratorIterator (db::RecursiveInstanceIterator *iter) : mp_iter (iter) { }
bool at_end () const { return mp_iter->at_end (); }
reference operator* () const { return *mp_iter; }
void operator++ () { ++*mp_iter; }
private:
db::RecursiveInstanceIterator *mp_iter;
};
}
// ---------------------------------------------------------------
// db::RecursiveInstanceIterator binding
@ -48,6 +73,11 @@ static db::RecursiveInstanceIterator *new_si2a (const db::Layout &layout, const
return new db::RecursiveInstanceIterator (layout, cell, region, overlapping);
}
static IteratorIterator each (db::RecursiveInstanceIterator *r)
{
return IteratorIterator (r);
}
static db::DCplxTrans si_dtrans (const db::RecursiveInstanceIterator *r)
{
const db::Layout *ly = r->layout ();
@ -184,6 +214,21 @@ Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "Recu
"bounding box touches the search region are reported. The bounding box of instances is measured taking all layers "
"of the target cell into account.\n"
) +
gsi::iterator_ext ("each", &each,
"@brief Native iteration\n"
"This method enables native iteration, e.g.\n"
"\n"
"@code\n"
" iter = ... # RecursiveInstanceIterator\n"
" iter.each do |i|\n"
" ... i is the iterator itself\n"
" end\n"
"@/code\n"
"\n"
"This is slightly more convenient than the 'at_end' .. 'next' loop.\n"
"\n"
"This feature has been introduced in version 0.28.\n"
) +
gsi::method ("max_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::max_depth, gsi::arg ("depth"),
"@brief Specifies the maximum hierarchy depth to look into\n"
"\n"
@ -466,6 +511,11 @@ Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "Recu
" puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n"
" iter.next\n"
"end\n"
"\n"
"# or shorter:\n"
"cell.begin_instances_rec.each do |iter|\n"
" puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n"
"end\n"
"@/code\n"
"\n"
"Here, a target cell is specified which confines the search to instances of this particular cell.\n"

View File

@ -1,4 +1,4 @@
#
/*
KLayout Layout Viewer
@ -27,12 +27,39 @@
#include "tlGlobPattern.h"
#include <iterator>
namespace gsi
{
// ---------------------------------------------------------------
// db::RecursiveShapeIterator binding
namespace {
/**
* @brief A wrapper that allows using "each" on the iterator
*/
class IteratorIterator
{
public:
typedef db::RecursiveShapeIterator value_type;
typedef db::RecursiveShapeIterator &reference;
typedef db::RecursiveShapeIterator *pointer;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
IteratorIterator (db::RecursiveShapeIterator *iter) : mp_iter (iter) { }
bool at_end () const { return mp_iter->at_end (); }
reference operator* () const { return *mp_iter; }
void operator++ () { ++*mp_iter; }
private:
db::RecursiveShapeIterator *mp_iter;
};
}
static db::RecursiveShapeIterator *new_si1 (const db::Layout &layout, const db::Cell &cell, unsigned int layer)
{
return new db::RecursiveShapeIterator (layout, cell, layer);
@ -63,6 +90,11 @@ static db::RecursiveShapeIterator *new_si4a (const db::Layout &layout, const db:
return new db::RecursiveShapeIterator (layout, cell, layers, region, overlapping);
}
static IteratorIterator each (db::RecursiveShapeIterator *r)
{
return IteratorIterator (r);
}
static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
@ -236,6 +268,21 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n"
) +
gsi::iterator_ext ("each", &each,
"@brief Native iteration\n"
"This method enables native iteration, e.g.\n"
"\n"
"@code\n"
" iter = ... # RecursiveShapeIterator\n"
" iter.each do |i|\n"
" ... i is the iterator itself\n"
" end\n"
"@/code\n"
"\n"
"This is slightly more convenient than the 'at_end' .. 'next' loop.\n"
"\n"
"This feature has been introduced in version 0.28.\n"
) +
gsi::method ("max_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::max_depth, gsi::arg ("depth"),
"@brief Specifies the maximum hierarchy depth to look into\n"
"\n"
@ -560,6 +607,14 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
" end\n"
" iter.next\n"
"end\n"
"\n"
"# or shorter:\n"
"cell.begin_shapes_rec(layer).each do |iter|\n"
" if iter.shape.renders_polygon?\n"
" polygon = iter.shape.polygon.transformed(iter.itrans)\n"
" puts \"In cell #{iter.cell.name}: \" + polygon.to_s\n"
" end\n"
"end\n"
"@/code\n"
"\n"
"\\Cell offers three methods to get these iterators: begin_shapes_rec, begin_shapes_rec_touching and begin_shapes_rec_overlapping.\n"

View File

@ -471,17 +471,6 @@ static void break_polygons (db::Region *r, size_t max_vertex_count, double max_a
r->process (db::PolygonBreaker (max_vertex_count, max_area_ratio));
}
static db::Region &size_ext (db::Region *r, db::Coord d)
{
r->size (d);
return *r;
}
static db::Region sized_ext (db::Region *r, db::Coord d)
{
return r->sized (d);
}
static db::Region &merge_ext1 (db::Region *r, int min_wc)
{
r->merge (false, std::max (0, min_wc - 1));
@ -740,6 +729,19 @@ fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fil
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
}
static db::Region
sized_dvm (const db::Region *region, const db::Vector &dv, unsigned int mode)
{
return region->sized (dv.x (), dv.y (), mode);
}
static db::Region &
size_dvm (db::Region *region, const db::Vector &dv, unsigned int mode)
{
region->size (dv.x (), dv.y (), mode);
return *region;
}
static db::Point default_origin;
// provided by gsiDeclDbPolygon.cc:
@ -1537,7 +1539,18 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"# r now is (50,-50;50,100;100,100;100,-50)\n"
"@/code\n"
) +
method ("size", (db::Region & (db::Region::*) (db::Coord, unsigned int)) &db::Region::size, gsi::arg ("d"), gsi::arg ("mode"),
method_ext ("size", &size_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2),
"@brief Anisotropic sizing (biasing)\n"
"\n"
"@return The region after the sizing has applied (self)\n"
"\n"
"This method is equivalent to \"size(dv.x, dv.y, mode)\".\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This variant has been introduced in version 0.28."
) +
method ("size", (db::Region & (db::Region::*) (db::Coord, unsigned int)) &db::Region::size, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2),
"@brief Isotropic sizing (biasing)\n"
"\n"
"@return The region after the sizing has applied (self)\n"
@ -1546,39 +1559,34 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("size", size_ext, gsi::arg ("d"),
"@brief Isotropic sizing (biasing)\n"
"\n"
"@return The region after the sizing has applied (self)\n"
"\n"
"This method is equivalent to \"size(d, d, 2)\".\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("sized", (db::Region (db::Region::*) (db::Coord, db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
"@brief Returns the anisotropically sized region\n"
"\n"
"@return The sized region\n"
"\n"
"This method is returns the sized region (see \\size), but does not modify self.\n"
"This method returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode"),
method_ext ("sized", &sized_dvm, gsi::arg ("dv"), gsi::arg ("mode", (unsigned int) 2),
"@brief Returns the (an)isotropically sized region\n"
"\n"
"@return The sized region\n"
"\n"
"This method is equivalent to \"sized(dv.x, dv.y, mode)\".\n"
"This method returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This variant has been introduced in version 0.28."
) +
method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode", (unsigned int) 2),
"@brief Returns the isotropically sized region\n"
"\n"
"@return The sized region\n"
"\n"
"This method is returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("sized", sized_ext, gsi::arg ("d"),
"@brief Isotropic sizing (biasing)\n"
"\n"
"@return The region after the sizing has applied (self)\n"
"\n"
"This method is equivalent to \"sized(d, d, 2)\".\n"
"This method is equivalent to \"sized(d, d, mode)\".\n"
"This method returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +

View File

@ -22,6 +22,7 @@
#include "gsiDecl.h"
#include "gsiEnums.h"
#include "dbPoint.h"
#include "dbText.h"
#include "dbHash.h"
@ -36,6 +37,7 @@ template <class C>
struct text_defs
{
typedef typename C::coord_type coord_type;
typedef typename C::box_type box_type;
typedef typename C::point_type point_type;
typedef typename C::vector_type vector_type;
typedef db::simple_trans<coord_type> simple_trans_type;
@ -101,22 +103,43 @@ struct text_defs
return t->font ();
}
static void set_halign (C *t, int f)
static point_type get_pos (C *t)
{
return t->trans () * point_type ();
}
static box_type get_bbox (C *t)
{
point_type p = get_pos (t);
return box_type (p, p);
}
static void set_halign (C *t, db::HAlign f)
{
t->halign (f);
}
static void set_halign_int (C *t, int f)
{
t->halign (db::HAlign (f));
}
static int get_halign (C *t)
static db::HAlign get_halign (C *t)
{
return t->halign ();
}
static void set_valign (C *t, int f)
static void set_valign (C *t, db::VAlign f)
{
t->valign (f);
}
static void set_valign_int (C *t, int f)
{
t->valign (db::VAlign (f));
}
static int get_valign (C *t)
static db::VAlign get_valign (C *t)
{
return t->valign ();
}
@ -186,6 +209,18 @@ struct text_defs
method ("string", (const char *(C::*) () const) &C::string,
"@brief Get the text string\n"
) +
method_ext ("position", get_pos,
"@brief Gets the position of the text\n"
"\n"
"This convenience method has been added in version 0.28."
) +
method_ext ("bbox", get_bbox,
"@brief Gets the bounding box of the text\n"
"The bounding box of the text is a single point - the location of the text. "
"Both points of the box are identical.\n"
"\n"
"This method has been added in version 0.28."
) +
method_ext ("x=", set_x, gsi::arg ("x"),
"@brief Sets the x location of the text\n"
"\n"
@ -210,43 +245,54 @@ struct text_defs
"@brief Assign a transformation (text position and orientation) to this object\n"
) +
method ("trans", (const simple_trans_type & (C::*) () const) &C::trans,
"@brief Get the transformation\n"
"@brief Gets the transformation\n"
) +
method ("size=", (void (C::*) (coord_type)) &C::size, gsi::arg ("s"),
"@brief Set the text height of this object\n"
"@brief Sets the text height of this object\n"
) +
method ("size", (coord_type (C::*) () const) &C::size,
"@brief Get the text height\n"
"@brief Gets the text height\n"
) +
method_ext ("font=", &set_font, gsi::arg ("f"),
"@brief Set the font number\n"
"@brief Sets the font number\n"
"The font number does not play a role for KLayout. This property is provided "
"for compatibility with other systems which allow using different fonts for the text objects."
) +
method_ext ("font", &get_font,
"@brief Get the font number\n"
"@brief Gets the font number\n"
"See \\font= for a description of this property."
) +
method_ext ("#halign=", &set_halign_int, gsi::arg ("a"),
"@brief Sets the horizontal alignment\n"
"\n"
"This is the version accepting integer values. It's provided for backward compatibility.\n"
) +
method_ext ("halign=", &set_halign, gsi::arg ("a"),
"@brief Set the horizontal alignment\n"
"@brief Sets the horizontal alignment\n"
"\n"
"This property specifies how the text is aligned relative to the anchor point. "
"Allowed values for this property are 0 (left), 1 (center) and 2 (right)."
"\n"
"This property has been introduced in version 0.22.\n"
"This property has been introduced in version 0.22 and extended to enums in 0.28.\n"
) +
method_ext ("halign", &get_halign,
"@brief Get the horizontal alignment\n"
"@brief Gets the horizontal alignment\n"
"\n"
"See \\halign= for a description of this property.\n"
) +
method_ext ("#valign=", &set_valign_int, gsi::arg ("a"),
"@brief Sets the vertical alignment\n"
"\n"
"This is the version accepting integer values. It's provided for backward compatibility.\n"
) +
method_ext ("valign=", &set_valign, gsi::arg ("a"),
"@brief Set the vertical alignment\n"
"@brief Sets the vertical alignment\n"
"\n"
"This property specifies how the text is aligned relative to the anchor point. "
"Allowed values for this property are 0 (top), 1 (center) and 2 (bottom)."
"\n"
"This property has been introduced in version 0.22.\n"
"This property has been introduced in version 0.22 and extended to enums in 0.28.\n"
) +
method_ext ("valign", &get_valign,
"@brief Get the vertical alignment\n"
"@brief Gets the vertical alignment\n"
"\n"
"See \\valign= for a description of this property.\n"
) +
@ -303,14 +349,14 @@ struct text_defs
"This method was introduced in version 0.23."
) +
method ("transformed", &C::template transformed<simple_trans_type>, gsi::arg ("t"),
"@brief Transform the text with the given simple transformation\n"
"@brief Transforms the text with the given simple transformation\n"
"\n"
"\n"
"@param t The transformation to apply\n"
"@return The transformed text\n"
) +
method ("transformed", &C::template transformed<complex_trans_type>, gsi::arg ("t"),
"@brief Transform the text with the given complex transformation\n"
"@brief Transforms the text with the given complex transformation\n"
"\n"
"\n"
"@param t The magnifying transformation to apply\n"
@ -346,7 +392,7 @@ struct text_defs
"This method has been added in version 0.23.\n"
) +
method ("to_s", &C::to_string, gsi::arg ("dbu", 0.0),
"@brief Convert to a string.\n"
"@brief Converts the object to a string.\n"
"If a DBU is given, the output units will be micrometers.\n"
"\n"
"The DBU argument has been added in version 0.27.6.\n"
@ -451,4 +497,44 @@ Class<db::DText> decl_DText ("db", "DText",
"database objects."
);
gsi::Enum<db::HAlign> decl_HAlign ("db", "HAlign",
gsi::enum_const ("HAlignLeft", db::HAlignLeft,
"@brief Left horizontal alignment\n"
) +
gsi::enum_const ("HAlignCenter", db::HAlignCenter,
"@brief Centered horizontal alignment\n"
) +
gsi::enum_const ("HAlignRight", db::HAlignRight,
"@brief Right horizontal alignment\n"
) +
gsi::enum_const ("NoHAlign", db::NoHAlign,
"@brief Undefined horizontal alignment\n"
),
"@brief This class represents the horizontal alignment modes.\n"
"This enum has been introduced in version 0.28."
);
gsi::Enum<db::VAlign> decl_VAlign ("db", "VAlign",
gsi::enum_const ("VAlignBottom", db::VAlignBottom,
"@brief Bottom vertical alignment\n"
) +
gsi::enum_const ("VAlignCenter", db::VAlignCenter,
"@brief Centered vertical alignment\n"
) +
gsi::enum_const ("VAlignTop", db::VAlignTop,
"@brief Top vertical alignment\n"
) +
gsi::enum_const ("NoVAlign", db::NoVAlign,
"@brief Undefined vertical alignment\n"
),
"@brief This class represents the vertical alignment modes.\n"
"This enum has been introduced in version 0.28."
);
// Inject the alignment enums
gsi::ClassExt<db::Text> inject_Text_HAlign_in_parent (decl_HAlign.defs ());
gsi::ClassExt<db::DText> inject_DText_HAlign_in_parent (decl_HAlign.defs ());
gsi::ClassExt<db::Text> inject_Text_VAlign_in_parent (decl_VAlign.defs ());
gsi::ClassExt<db::DText> inject_DText_VAlign_in_parent (decl_VAlign.defs ());
}

View File

@ -742,7 +742,7 @@ struct cplx_trans_defs
"\n"
"@return The inverted transformation\n"
) +
method ("ctrans", &C::ctrans, arg ("d"),
method ("ctrans|*", &C::ctrans, arg ("d"),
"@brief Transforms a distance\n"
"\n"
"The \"ctrans\" method transforms the given distance.\n"

View File

@ -232,6 +232,8 @@ TEST(1)
EXPECT_EQ (s, "1,8");
s = q2s_var (iq, "bbox");
EXPECT_EQ (s, "(0,1;2,3),()");
s = q2s_var (iq, "dbbox");
EXPECT_EQ (s, "(0,0.001;0.002,0.003),()");
}
{
@ -568,16 +570,26 @@ TEST(2)
EXPECT_EQ (s, "c1,c1");
s = q2s_var (iq, "trans");
EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20");
s = q2s_var (iq, "dtrans");
EXPECT_EQ (s, "r0 *1 0.01,-0.02,m45 *1 -0.01,0.02");
s = q2s_var (iq, "path_trans");
EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20");
s = q2s_var (iq, "path_dtrans");
EXPECT_EQ (s, "r0 *1 0.01,-0.02,m45 *1 -0.01,0.02");
s = q2s_var (iq, "inst_bbox");
EXPECT_EQ (s, "(10,-10;20,10),(0,20;20,30)");
s = q2s_var (iq, "inst_dbbox");
EXPECT_EQ (s, "(0.01,-0.01;0.02,0.01),(0,0.02;0.02,0.03)");
s = q2s_var (iq, "inst");
EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20");
s = q2s_var (iq, "array_a");
EXPECT_EQ (s, "nil,nil");
s = q2s_var (iq, "array_da");
EXPECT_EQ (s, "nil,nil");
s = q2s_var (iq, "array_b");
EXPECT_EQ (s, "nil,nil");
s = q2s_var (iq, "array_db");
EXPECT_EQ (s, "nil,nil");
s = q2s_var (iq, "array_na");
EXPECT_EQ (s, "nil,nil");
s = q2s_var (iq, "array_nb");
@ -603,8 +615,12 @@ TEST(2)
EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3)");
s = q2s_var (iq, "array_a");
EXPECT_EQ (s, "nil,1,1,1,1,1,1,1,1,1,1,1,1");
s = q2s_var (iq, "array_da");
EXPECT_EQ (s, "nil,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001,0.001");
s = q2s_var (iq, "array_b");
EXPECT_EQ (s, "nil,0,2,0,2,0,2,0,2,0,2,0,2");
s = q2s_var (iq, "array_db");
EXPECT_EQ (s, "nil,0,0.002,0,0.002,0,0.002,0,0.002,0,0.002,0,0.002");
s = q2s_var (iq, "array_na");
EXPECT_EQ (s, "nil,2,2,2,2,2,2");
s = q2s_var (iq, "array_nb");
@ -788,6 +804,12 @@ TEST(3)
EXPECT_EQ (s, "0,1,1,2");
s = q2s_var (iq, "bbox");
EXPECT_EQ (s, "(0,1;2,3),(0,1;2,3),(0,1;2,3),(10,11;10,11)");
s = q2s_var (iq, "dbbox");
EXPECT_EQ (s, "(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0.01,0.011;0.01,0.011)");
s = q2s_var (iq, "shape_bbox");
EXPECT_EQ (s, "(0,1;2,3),(0,1;2,3),(0,1;2,3),(10,11;10,11)");
s = q2s_var (iq, "shape_dbbox");
EXPECT_EQ (s, "(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0,0.001;0.002,0.003),(0.01,0.011;0.01,0.011)");
}
{

View File

@ -619,3 +619,44 @@ TEST(4)
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
}
TEST(5)
{
std::unique_ptr<db::Layout> g (new db::Layout ());
g->insert_layer (0);
g->insert_layer (1);
g->insert_layer (2);
db::Cell &c0 (g->cell (g->add_cell ()));
db::Cell &c1 (g->cell (g->add_cell ()));
db::Cell &c2 (g->cell (g->add_cell ()));
db::Cell &c3 (g->cell (g->add_cell ()));
db::Box b (0, 100, 1000, 1200);
c0.shapes (0).insert (b);
c1.shapes (0).insert (b);
c2.shapes (0).insert (b);
c3.shapes (0).insert (b);
c0.shapes (2).insert (b);
c0.shapes (2).insert (b.moved (db::Vector (50, 50)));
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100))));
c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1)));
c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0))));
std::string x;
db::RecursiveInstanceIterator i1 (*g, c0, db::Box (0, 0, 100, 100));
x = collect(i1, *g);
EXPECT_EQ (x, "[$1]$2 r0 0,0/[$1]$3 r0 100,-100");
g.reset (new db::Layout ());
// now the layout is gone and the iterator stays silent (weak pointer to layout)
// NOTE: this only works on reset or re-initialization. Not during iteration.
i1.reset ();
x = collect(i1, *g);
EXPECT_EQ (x, "");
}

View File

@ -1515,3 +1515,42 @@ TEST(10)
"end\n"
);
}
TEST(11_LayoutIsWeakPointer)
{
std::unique_ptr<db::Layout> g (new db::Layout ());
g->insert_layer (0);
g->insert_layer (1);
db::Cell &c0 (g->cell (g->add_cell ()));
db::Cell &c1 (g->cell (g->add_cell ()));
db::Cell &c2 (g->cell (g->add_cell ()));
db::Cell &c3 (g->cell (g->add_cell ()));
db::Box b (0, 100, 1000, 1200);
c1.shapes (0).insert (b);
c2.shapes (0).insert (b);
c3.shapes (0).insert (b);
db::Box bb (1, 101, 1001, 1201);
c2.shapes (1).insert (bb);
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100))));
c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1)));
c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0))));
std::string x;
db::RecursiveShapeIterator i1 (*g, c0, 0, db::Box (0, 0, 100, 100));
x = collect(i1, *g);
EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
g.reset (new db::Layout ());
// now the layout is gone and the iterator stays silent (weak pointer to layout)
// NOTE: this only works on reset or re-initialization. Not during iteration.
i1.reset ();
x = collect(i1, *g);
EXPECT_EQ (x, "");
}

View File

@ -388,7 +388,7 @@ shapes on layer METAL, POLY from cell TOP
Any kind of cell query can be used inside the shape query. If a cell query renders multiple
cells, the shape query will be applied to each of the cells returned. If instances are selected
by the cell query, the shapes will be reported for each instance. Since the cumulated transformation
of a specific instance into the top cell is available through the "path_trans" variable,
of a specific instance into the top cell is available through the "path_trans" (database units) or "path_dtrans" (micrometer units) variable,
it is possible to transform each shape into the top cell in the instance case. The following expression
combines a "with .. do" action with a shape query to flatten all shapes below "TOP":
</p>
@ -603,10 +603,20 @@ delete shapes on layer 6 of cell TOP
<td><class_ref href="Box"/></td>
<td>The cell's bounding box.</td>
</tr>
<tr>
<td>dbbox</td>
<td><class_ref href="DBox"/></td>
<td>The cell's bounding box in micrometer units.</td>
</tr>
<tr>
<td>cell_bbox</td>
<td><class_ref href="Box"/></td>
<td>Same as "bbox" (disambiguator for shape and instance bounding boxes).</td>
<td>Same as "bbox" (disambiguator from shape and instance bounding boxes).</td>
</tr>
<tr>
<td>cell_dbbox</td>
<td><class_ref href="DBox"/></td>
<td>Same as "dbbox" (disambiguator from shape and instance bounding boxes).</td>
</tr>
</table>
@ -631,16 +641,32 @@ delete shapes on layer 6 of cell TOP
<td>The transformation of that instance into the top cell.
For a plain cell that is a unit transformation.</td>
</tr>
<tr>
<td>path_dtrans</td>
<td><class_doc href="DCplxTrans"/></td>
<td>The transformation of that instance into the top cell in micrometer units.
For a plain cell that is a unit transformation.</td>
</tr>
<tr>
<td>trans</td>
<td><class_doc href="ICplxTrans"/></td>
<td>The transformation of that instance (first instance if an array).</td>
</tr>
<tr>
<td>dtrans</td>
<td><class_doc href="DCplxTrans"/></td>
<td>The transformation of that instance (first instance if an array) in micrometer units.</td>
</tr>
<tr>
<td>inst_bbox</td>
<td><class_doc href="Box"/></td>
<td>The instance bounding box in the initial cell.</td>
</tr>
<tr>
<td>inst_dbbox</td>
<td><class_doc href="DBox"/></td>
<td>The instance bounding box in the initial cell in micrometer units.</td>
</tr>
<tr>
<td>inst</td>
<td><class_doc href="Instance"/></td>
@ -648,9 +674,14 @@ delete shapes on layer 6 of cell TOP
</tr>
<tr>
<td>array_a</td>
<td><class_doc href="Point"/></td>
<td><class_doc href="Vector"/></td>
<td>The a vector for an array instance or nil if the instance is not an array.</td>
</tr>
<tr>
<td>array_da</td>
<td><class_doc href="DVector"/></td>
<td>The a vector for an array instance in micrometer units or nil if the instance is not an array.</td>
</tr>
<tr>
<td>array_na</td>
<td>Integer</td>
@ -658,9 +689,14 @@ delete shapes on layer 6 of cell TOP
</tr>
<tr>
<td>array_b</td>
<td><class_doc href="Point"/></td>
<td><class_doc href="Vector"/></td>
<td>The b vector for an array instance or nil if the instance is not an array.</td>
</tr>
<tr>
<td>array_db</td>
<td><class_doc href="DVector"/></td>
<td>The b vector for an array instance in micrometer units or nil if the instance is not an array.</td>
</tr>
<tr>
<td>array_nb</td>
<td>Integer</td>
@ -689,14 +725,24 @@ delete shapes on layer 6 of cell TOP
<tr><th>Name</th><th>Value type</th><th>Description</th></tr>
<tr>
<td>bbox</td>
<td><class_doc href="Box"/></td>
<td><class_doc href="DBox"/></td>
<td>The shape's bounding box</td>
</tr>
<tr>
<td>dbbox</td>
<td><class_doc href="DBox"/></td>
<td>The shape's bounding box in micrometer units</td>
</tr>
<tr>
<td>shape_bbox</td>
<td><class_doc href="Box"/></td>
<td>Same as "bbox" (disambiguator for cell or instance bounding boxes)</td>
</tr>
<tr>
<td>shape_dbbox</td>
<td><class_doc href="DBox"/></td>
<td>Same as "dbbox" (disambiguator for cell or instance bounding boxes)</td>
</tr>
<tr>
<td>shape</td>
<td><class_doc href="Shape"/></td>

View File

@ -1699,6 +1699,55 @@ SearchReplaceDialog::result_selection_changed ()
}
} else if (index < int (m_model.data ().size ())) {
db::DCplxTrans as_dbu = db::DCplxTrans (layout.dbu ()).inverted ();
const tl::Variant &dr = m_model.data () [index];
for (tl::Variant::const_iterator v = dr.begin (); v != dr.end (); ++v) {
lay::Marker *marker = new lay::Marker (view (), cv_index);
if (v->is_user<db::DBox> ()) {
marker->set (v->to_user<db::DBox> (), as_dbu, global_trans);
} else if (v->is_user<db::Box> ()) {
marker->set (v->to_user<db::Box> (), db::ICplxTrans (), global_trans);
} else if (v->is_user<db::DEdge> ()) {
marker->set (v->to_user<db::DEdge> (), as_dbu, global_trans);
} else if (v->is_user<db::Edge> ()) {
marker->set (v->to_user<db::Edge> (), db::ICplxTrans (), global_trans);
} else if (v->is_user<db::DPolygon> ()) {
marker->set (v->to_user<db::DPolygon> (), as_dbu, global_trans);
} else if (v->is_user<db::Polygon> ()) {
marker->set (v->to_user<db::Polygon> (), db::ICplxTrans (), global_trans);
} else if (v->is_user<db::DPath> ()) {
marker->set (v->to_user<db::DPath> (), as_dbu, global_trans);
} else if (v->is_user<db::Path> ()) {
marker->set (v->to_user<db::Path> (), db::ICplxTrans (), global_trans);
} else if (v->is_user<db::DPoint> ()) {
db::DPoint p = v->to_user<db::DPoint> ();
marker->set (db::DBox (p, p), as_dbu, global_trans);
} else if (v->is_user<db::Point> ()) {
db::Point p = v->to_user<db::Point> ();
marker->set (db::Box (p, p), db::ICplxTrans (), global_trans);
} else if (v->is_user<db::DVector> ()) {
db::DPoint p = db::DPoint () + v->to_user<db::DVector> ();
marker->set (db::DBox (p, p), as_dbu, global_trans);
} else if (v->is_user<db::Vector> ()) {
db::Point p = db::Point () + v->to_user<db::Vector> ();
marker->set (db::Box (p, p), db::ICplxTrans (), global_trans);
} else {
delete marker;
marker = 0;
}
if (marker) {
mp_markers.push_back (marker);
dbox += marker->bbox ();
}
}
}
}

View File

@ -106,6 +106,13 @@ class DBBox_TestClass < TestBase
a = RBA::DBox.new
assert_equal( a.empty?, true )
a = RBA::DBox::world
b = RBA::DBox::new(1, 2, 3, 4)
assert_equal( a.empty?, false )
assert_equal( a == RBA::DBox::world, true )
assert_equal( (a + b) == RBA::DBox::world, true )
assert_equal( (a & b) == b, true )
end
# DBox basics
@ -303,6 +310,13 @@ class DBBox_TestClass < TestBase
a = RBA::Box.new
assert_equal( a.empty?, true )
a = RBA::Box::world
b = RBA::Box::new(1, 2, 3, 4)
assert_equal( a.empty?, false )
assert_equal( a == RBA::Box::world, true )
assert_equal( (a + b) == RBA::Box::world, true )
assert_equal( (a & b) == b, true )
end
# Box basics

View File

@ -49,6 +49,11 @@ class DBCellInst_TestClass < TestBase
assert_equal(a.trans.to_s, "r90 0,0")
assert_equal(a.cplx_trans.to_s, "r90 *1 0,0")
a = RBA::CellInstArray::new(0, RBA::Vector::new(42, -17))
assert_equal(a.is_complex?, false)
assert_equal(a.trans.to_s, "r0 42,-17")
assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17")
a = RBA::CellInstArray::new(0, RBA::ICplxTrans::new(1.5))
assert_equal(a.is_complex?, true)
assert_equal(a.trans.to_s, "r0 0,0")
@ -106,6 +111,12 @@ class DBCellInst_TestClass < TestBase
assert_equal(a.cplx_trans.to_s, "r90 *1 0,0")
assert_equal(a.to_s, "#0 r90 0,0 [10,20*3;30,40*5]")
a = RBA::CellInstArray::new(0, RBA::Vector::new(42, -17), RBA::Vector::new(10, 20), RBA::Vector::new(30, 40), 3, 5)
assert_equal(a.is_complex?, false)
assert_equal(a.trans.to_s, "r0 42,-17")
assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17")
assert_equal(a.to_s, "#0 r0 42,-17 [10,20*3;30,40*5]")
a = RBA::CellInstArray::new(0, RBA::ICplxTrans::new(1.5), RBA::Vector::new(10, 20), RBA::Vector::new(30, 40), 3, 5)
assert_equal(a.is_complex?, true)
assert_equal(a.trans.to_s, "r0 0,0")
@ -178,6 +189,11 @@ class DBCellInst_TestClass < TestBase
assert_equal(a.trans.to_s, "r90 0,0")
assert_equal(a.cplx_trans.to_s, "r90 *1 0,0")
a = RBA::DCellInstArray::new(0, RBA::DVector::new(42, -17))
assert_equal(a.is_complex?, false)
assert_equal(a.trans.to_s, "r0 42,-17")
assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17")
a = RBA::DCellInstArray::new(0, RBA::DCplxTrans::new(1.5))
assert_equal(a.is_complex?, true)
assert_equal(a.trans.to_s, "r0 0,0")
@ -235,6 +251,12 @@ class DBCellInst_TestClass < TestBase
assert_equal(a.cplx_trans.to_s, "r90 *1 0,0")
assert_equal(a.to_s, "#0 r90 0,0 [10,20*3;30,40*5]")
a = RBA::DCellInstArray::new(0, RBA::DVector::new(42, -17), RBA::DVector::new(10, 20), RBA::DVector::new(30, 40), 3, 5)
assert_equal(a.is_complex?, false)
assert_equal(a.trans.to_s, "r0 42,-17")
assert_equal(a.cplx_trans.to_s, "r0 *1 42,-17")
assert_equal(a.to_s, "#0 r0 42,-17 [10,20*3;30,40*5]")
a = RBA::DCellInstArray::new(0, RBA::DCplxTrans::new(1.5), RBA::DVector::new(10, 20), RBA::DVector::new(30, 40), 3, 5)
assert_equal(a.is_complex?, true)
assert_equal(a.trans.to_s, "r0 0,0")

View File

@ -1043,10 +1043,31 @@ class DBLayout_TestClass < TestBase
ci = l.clip(c0.cell_index, RBA::Box.new(0, 0, 200, 200))
assert_equal(dump_layer_i(l, 0, ci), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
cic = l.clip(c0, RBA::Box.new(0, 0, 200, 200))
assert_equal(dump_layer_i(l, 0, cic.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
cid = l.clip(c0.cell_index, RBA::DBox.new(0, 0, 0.2, 0.2))
assert_equal(dump_layer_i(l, 0, cid), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
cicd = l.clip(c0, RBA::DBox.new(0, 0, 0.2, 0.2))
assert_equal(dump_layer_i(l, 0, cicd.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
ci = l.multi_clip(c0.cell_index, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)])
assert_equal(dump_layer_i(l, 0, ci[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(l, 0, ci[1]), "(1000,0;1100,200); (1200,0;1300,200)")
cic = l.multi_clip(c0, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)])
assert_equal(dump_layer_i(l, 0, cic[0].cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(l, 0, cic[1].cell_index), "(1000,0;1100,200); (1200,0;1300,200)")
cid = l.multi_clip(c0.cell_index, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)])
assert_equal(dump_layer_i(l, 0, cid[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(l, 0, cid[1]), "(1000,0;1100,200); (1200,0;1300,200)")
cidc = l.multi_clip(c0, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)])
assert_equal(dump_layer_i(l, 0, cidc[0].cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(l, 0, cidc[1].cell_index), "(1000,0;1100,200); (1200,0;1300,200)")
ll = RBA::Layout.new
ll.dbu = l.dbu
ll.insert_layer_at(0, RBA::LayerInfo.new(2, 0))
@ -1054,10 +1075,31 @@ class DBLayout_TestClass < TestBase
ci = l.clip_into(c0.cell_index, ll, RBA::Box.new(0, 0, 200, 200))
assert_equal(dump_layer_i(ll, 0, ci), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
cic = l.clip_into(c0, ll, RBA::Box.new(0, 0, 200, 200))
assert_equal(dump_layer_i(ll, 0, cic.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
cid = l.clip_into(c0.cell_index, ll, RBA::DBox.new(0, 0, 0.2, 0.2))
assert_equal(dump_layer_i(ll, 0, cid), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
cicd = l.clip_into(c0, ll, RBA::DBox.new(0, 0, 0.2, 0.2))
assert_equal(dump_layer_i(ll, 0, cicd.cell_index), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
ci = l.multi_clip_into(c0.cell_index, ll, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)])
assert_equal(dump_layer_i(ll, 0, ci[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(ll, 0, ci[1]), "(1000,0;1100,200); (1200,0;1300,200)")
cic = l.multi_clip_into(c0, ll, [RBA::Box.new(0, 0, 200, 200),RBA::Box.new(1000, 0, 1300, 200)])
assert_equal(dump_layer_i(ll, 0, cic[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(ll, 0, cic[1]), "(1000,0;1100,200); (1200,0;1300,200)")
cid = l.multi_clip_into(c0.cell_index, ll, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)])
assert_equal(dump_layer_i(ll, 0, cid[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(ll, 0, cid[1]), "(1000,0;1100,200); (1200,0;1300,200)")
cicd = l.multi_clip_into(c0, ll, [RBA::DBox.new(0, 0, 0.2, 0.2),RBA::DBox.new(1.0, 0, 1.3, 0.2)])
assert_equal(dump_layer_i(ll, 0, cicd[0]), "(0,100;200,200); (0,100;200,200); (100,0;200,200)")
assert_equal(dump_layer_i(ll, 0, cicd[1]), "(1000,0;1100,200); (1200,0;1300,200)")
end
def test_8

View File

@ -23,10 +23,10 @@ end
load("test_prologue.rb")
class DBLayout_TestClass < TestBase
class DBLayoutTest_TestClass < TestBase
# LayerInfo
def _test_1_Layout
def test_1_Layout
lp = RBA::LayerInfo::new
@ -62,7 +62,7 @@ class DBLayout_TestClass < TestBase
end
# Basics: cells and instances
def _test_2_Layout
def test_2_Layout
ly = RBA::Layout::new
@ -182,7 +182,7 @@ class DBLayout_TestClass < TestBase
end
# Instances and bboxes
def _test_5_Layout
def test_5_Layout
ly = RBA::Layout::new
@ -223,10 +223,13 @@ class DBLayout_TestClass < TestBase
assert_equal( c1.bbox_per_layer( lindex ).to_s, "()" )
assert_equal( c1.bbox_per_layer( ldummy ).to_s, "()" )
assert_equal( ly.unique_cell_name("c3"), "c3" )
assert_equal( ly.unique_cell_name("c1"), "c1$1" )
end
# Instances and bboxes
def _test_6_Layout
def test_6_Layout
ly = RBA::Layout::new
@ -398,7 +401,7 @@ class DBLayout_TestClass < TestBase
end
# Instances and editable mode
def _test_6_EditableLayout
def test_6_EditableLayout
ly = RBA::Layout::new( true )
assert_equal( ly.is_editable?, true )
@ -470,7 +473,7 @@ class DBLayout_TestClass < TestBase
end
# Instances and bboxes
def _test_6_Layout_props
def test_6_Layout_props
ly = RBA::Layout::new
pid = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a )
@ -648,7 +651,7 @@ class DBLayout_TestClass < TestBase
end
# Properties
def _test_6_Layout_props2
def test_6_Layout_props2
ly = RBA::Layout::new(true)
pid = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a )
@ -697,7 +700,7 @@ class DBLayout_TestClass < TestBase
end
# Instances and bboxes (editable mode)
def _test_6_Layout_new
def test_6_Layout_new
if( RBA::Application::instance.is_editable? )
@ -805,7 +808,7 @@ class DBLayout_TestClass < TestBase
end
# Copy/move between cells
def _test_7_cells_copy_move
def test_7_cells_copy_move
# because of set_property ...
if !RBA::Application::instance.is_editable?
@ -879,7 +882,7 @@ class DBLayout_TestClass < TestBase
end
# top cells
def _test_8
def test_8
l = RBA::Layout.new
tc = []
@ -916,7 +919,7 @@ class DBLayout_TestClass < TestBase
end
# under construction and update
def _test_9
def test_9
ly = RBA::Layout::new
l1 = ly.insert_layer(RBA::LayerInfo::new(1, 0))
@ -946,7 +949,7 @@ class DBLayout_TestClass < TestBase
end
# Instance editing
def _test_10
def test_10
ly = RBA::Layout::new
@ -1025,7 +1028,7 @@ class DBLayout_TestClass < TestBase
end
# User properties
def _test_11
def test_11
ly = RBA::Layout::new
@ -1049,7 +1052,7 @@ class DBLayout_TestClass < TestBase
end
# Meta information
def _test_12
def test_12
mi = RBA::LayoutMetaInfo::new("myinfo", "a")

View File

@ -277,8 +277,19 @@ class DBPolygon_TestClass < TestBase
a = RBA::Polygon::new( [ RBA::Point::new( 0, 1 ), RBA::Point::new( 1, 5 ), RBA::Point::new( 5, 5 ) ] )
assert_equal( a.to_s, "(0,1;1,5;5,5)" )
assert_equal( a.sized(2, 0, 2).to_s, "(-2,1;-1,5;7,5;2,1)" )
assert_equal( a.sized(RBA::Vector::new(2, 0), 2).to_s, "(-2,1;-1,5;7,5;2,1)" )
assert_equal( a.sized(RBA::Vector::new(2, 0)).to_s, "(-2,1;-1,5;7,5;2,1)" )
aa = a.dup
a.size(2, 0, 2);
assert_equal( a.to_s, "(-2,1;-1,5;7,5;2,1)" )
a = aa
aa = a.dup
a.size(RBA::Vector::new(2, 0), 2);
assert_equal( a.to_s, "(-2,1;-1,5;7,5;2,1)" )
a = aa
aa = a.dup
a.size(RBA::Vector::new(2, 0));
assert_equal( a.to_s, "(-2,1;-1,5;7,5;2,1)" )
a = RBA::Polygon::new
assert_equal( a.to_s, "()" )

View File

@ -27,7 +27,16 @@ class DBLayout_TestClass < TestBase
def collect(s, l)
# check native iteration here too ..
res2 = []
s.each do |s|
r = "[#{s.inst_cell.name}]"
r += (s.trans * s.inst_trans).to_s
res2.push(r)
end
res = []
s.reset
while !s.at_end?
r = "[#{s.inst_cell.name}]"
r += (s.trans * s.inst_trans).to_s
@ -35,6 +44,8 @@ class DBLayout_TestClass < TestBase
s.next
end
assert_equal(res, res2)
return res.join("/")
end

View File

@ -27,7 +27,21 @@ class DBRecursiveShapeIterator_TestClass < TestBase
def collect(s, l)
# check native iteration here too ..
res2 = []
s.each do |s|
r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box?
box = s.shape.box
r += box.transformed(s.trans).to_s
else
r += "X";
end
res2.push(r)
end
res = []
s.reset
while !s.at_end?
r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box?
@ -40,6 +54,8 @@ class DBRecursiveShapeIterator_TestClass < TestBase
res.push(r)
end
assert_equal(res, res2)
return res.join("/")
end

View File

@ -318,6 +318,16 @@ class DBRegion_TestClass < TestBase
rr.size(10, 20, 2)
assert_equal(rr.to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)")
assert_equal((r1 | r2).sized(RBA::Vector::new(10, 20)).to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)")
rr = (r1 | r2).dup
rr.size(10, 20, 2)
assert_equal(rr.to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)")
assert_equal((r1 | r2).sized(RBA::Vector::new(10, 20), 2).to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)")
rr = (r1 | r2).dup
rr.size(10, 20, 2)
assert_equal(rr.to_s, "(-20,-40;-20,180;0,180;0,220;110,220;110,0;90,0;90,-40)")
r1.merged_semantics = false
assert_equal((r1 | r2).sized(10, 2).to_s, "(-20,-30;-20,170;0,170;0,210;110,210;110,10;90,10;90,-30)")

View File

@ -69,12 +69,34 @@ class DBText_TestClass < TestBase
a = RBA::DText::new( "hallo", a.trans, 22.0, 7 )
assert_equal( a.string, "hallo" )
assert_equal( a.trans.to_s, "m45 5,7" )
assert_equal( a.position.to_s, "5,7" )
assert_equal( a.bbox.to_s, "(5,7;5,7)" )
assert_equal( a.font, 7 )
assert_equal( a.size, 22.0 )
a.font = 8
assert_equal( a.font, 8 )
a.halign = 1
assert_equal( a.halign.to_i, 1 )
assert_equal( a.halign, RBA::DText::HAlignCenter )
assert_equal( a.halign.to_s, "HAlignCenter" )
a.halign = RBA::DText::HAlignRight
assert_equal( a.halign.to_i, 2 )
assert_equal( a.halign, RBA::DText::HAlignRight )
assert_equal( a.halign.to_s, "HAlignRight" )
a.valign = 1
assert_equal( a.valign.to_i, 1 )
assert_equal( a.valign, RBA::DText::VAlignCenter )
assert_equal( a.valign.to_s, "VAlignCenter" )
a.valign = RBA::DText::VAlignBottom
assert_equal( a.valign.to_i, 2 )
assert_equal( a.valign, RBA::DText::VAlignBottom )
assert_equal( a.valign.to_s, "VAlignBottom" )
a.size = 23.0
assert_equal( a.size, 23.0 )
@ -141,12 +163,34 @@ class DBText_TestClass < TestBase
a = RBA::Text::new( "hallo", a.trans, 22, 7 )
assert_equal( a.string, "hallo" )
assert_equal( a.trans.to_s, "m45 5,7" )
assert_equal( a.position.to_s, "5,7" )
assert_equal( a.bbox.to_s, "(5,7;5,7)" )
assert_equal( a.font, 7 )
assert_equal( a.size, 22.0 )
a.font = 8
assert_equal( a.font, 8 )
a.halign = 1
assert_equal( a.halign.to_i, 1 )
assert_equal( a.halign, RBA::Text::HAlignCenter )
assert_equal( a.halign.to_s, "HAlignCenter" )
a.halign = RBA::Text::HAlignLeft
assert_equal( a.halign.to_i, 0 )
assert_equal( a.halign, RBA::Text::HAlignLeft )
assert_equal( a.halign.to_s, "HAlignLeft" )
a.valign = 1
assert_equal( a.valign.to_i, 1 )
assert_equal( a.valign, RBA::Text::VAlignCenter )
assert_equal( a.valign.to_s, "VAlignCenter" )
a.valign = RBA::Text::VAlignTop
assert_equal( a.valign.to_i, 0 )
assert_equal( a.valign, RBA::Text::VAlignTop )
assert_equal( a.valign.to_s, "VAlignTop" )
a.size = 23
assert_equal( a.size, 23 )

View File

@ -80,6 +80,8 @@ class DBTrans_TestClass < TestBase
assert_equal( RBA::Trans::new(RBA::Trans::R180, RBA::DVector::new(5,-7)).to_s, "r180 5,-7" )
assert_equal( RBA::Trans::new(RBA::Trans::R180).to_s, "r180 0,0" )
assert_equal( e.trans( 2.0 ).to_s, "2" )
assert_equal( (e * 2.0).to_s, "2" )
assert_equal( e.trans( RBA::Edge::new(0, 1, 2, 3) ).to_s, "(-3,-2;-1,0)" )
assert_equal( ( e * RBA::Edge::new(0, 1, 2, 3) ).to_s, "(-3,-2;-1,0)" )
assert_equal( e.trans( RBA::Box::new(0, 1, 2, 3) ).to_s, "(-3,-2;-1,0)" )
@ -140,7 +142,9 @@ class DBTrans_TestClass < TestBase
assert_equal( mb.trans( RBA::DPoint::new( 1, 0 )).to_s, "17,3" )
assert_equal( mb.ctrans(2).to_s, "4.0" )
assert_equal( (mb * 2).to_s, "4.0" )
assert_equal( i.ctrans(2).to_s, "1.0" )
assert_equal( (i * 2).to_s, "1.0" )
end
@ -199,6 +203,7 @@ class DBTrans_TestClass < TestBase
assert_equal( (c.angle - 45).abs < 1e-10, true )
assert_equal( c.ctrans( 5 ).to_s, "3.75" )
assert_equal( (c * 5).to_s, "3.75" )
assert_equal( c.trans( RBA::DPoint::new( 12, 16 ) ).to_s, "17.3492424049,-14.6213203436" )
assert_equal( RBA::DCplxTrans::new.to_s, "r0 *1 0,0" )
@ -306,7 +311,9 @@ class DBTrans_TestClass < TestBase
assert_equal( mb.trans( RBA::Point::new( 1, 0 )).to_s, "17,3" )
assert_equal( mb.ctrans(2).to_s, "4.0" )
assert_equal( (mb * 2).to_s, "4.0" )
assert_equal( i.ctrans(2).to_s, "1.0" )
assert_equal( (i * 2).to_s, "1.0" )
end
@ -353,6 +360,7 @@ class DBTrans_TestClass < TestBase
assert_equal( (c.angle - 45).abs < 1e-10, true )
assert_equal( c.ctrans( 5 ).to_s, "3.75" )
assert_equal( (c * 5).to_s, "3.75" )
assert_equal( c.trans( RBA::Point::new( 12, 16 ) ).to_s, "17.3492424049,-14.6213203436" )
assert_equal( RBA::CplxTrans::new.to_s, "r0 *1 0,0" )