Merge remote-tracking branch 'origin/master' into macos-build

This commit is contained in:
Kazunari Sekigawa 2018-02-22 06:50:18 +09:00
commit be08e1a714
32 changed files with 1355 additions and 1049 deletions

View File

@ -343,7 +343,6 @@ Object::class_name () const
void
Object::from_string (const char *s)
{
printf("@@@ %s\n", s); fflush(stdout);
tl::Extractor ex (s);
while (! ex.at_end ()) {

View File

@ -1035,7 +1035,7 @@ public:
value_type operator* () const
{
return value_type (*(dynamic_cast<const ant::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ());
return value_type (*(static_cast<const ant::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ());
}
private:

View File

@ -183,6 +183,13 @@ to create the \\LayerInfo object, i.e. like this:
The default implementation does nothing. All parameters not set in this method will receive their default value.
If you use a parameter called "layer" for example, the parameter getter will hide the
"layer" argument. Use "_layer" for the argument in this case (same for "layout", "shape" or "cell):
@code
set_layer layout.get_info(_layer)
@/code
@method transformation_from_shape_impl
@brief Gets the initial PCell instance transformation when creating from a shape
@ -230,6 +237,13 @@ module RBA
# provide accessors for the current layout and cell (for prod)
attr_reader :layout, :cell, :shape, :layer
# provide fallback accessors in case of a name clash with a
# parameter
def _layer; @layer; end
def _layout; @layout; end
def _cell; @cell; end
def _shape; @shape; end
# define a parameter
# name -&gt; the short name of the parameter
@ -246,6 +260,12 @@ module RBA
# set_{name} -&gt; write accessor ({name}= does not work because the
# Ruby confuses that method with variables)
# {name}_layer -&gt; read accessor for the layer index for TypeLayer parameters
# in addition, fallback accessors are defined which can be used if
# the parameter's name clashes with another name:
# param_{name}
# set_param_{name}
# param_{name}_layer
def param(name, type, description, args = {})
# create accessor methods for the parameters

View File

@ -26,7 +26,7 @@ class MyPCell(pya.PCellDeclarationHelper):
def __init__(self):
# Important: initialize the super class
super(Circle, self).__init__()
super(MyPCell, self).__init__()
# your initialization: add parameters with name, type, description and
# optional other values
@ -226,16 +226,27 @@ class _PCellDeclarationHelperLayerDescriptor(object):
class _PCellDeclarationHelperParameterDescriptor(object):
"""
A descriptor object which translates the PCell parameters into class attributes
In some cases (i.e. can_convert_from_shape), these placeholders are not
connected to real parameters (obj._param_values is None). In this case,
the descriptor acts as a value holder (self.value)
"""
def __init__(self, param_index):
self.param_index = param_index
self.value = None
def __get__(self, obj, type = None):
return obj._param_values[self.param_index]
if obj._param_values:
return obj._param_values[self.param_index]
else:
return self.value
def __set__(self, obj, value):
obj._param_values[self.param_index] = value
if obj._param_values:
obj._param_values[self.param_index] = value
else:
self.value = value
class _PCellDeclarationHelper(pya.PCellDeclaration):
"""
@ -321,7 +332,38 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
gets the parameters
"""
return self._param_decls
def get_values(self):
"""
gets the temporary parameter values
"""
v = self._param_values
self._param_values = None
return v
def init_values(self, values = None, layers = None):
"""
initializes the temporary parameter values
"values" are the original values. If "None" is given, the
default values will be used.
"layers" are the layer indexes corresponding to the layer
parameters.
"""
if not values:
self._param_values = []
for pd in self._param_decls:
self._param_values.append(pd.default)
else:
self._param_values = values
self._layers = layers
def finish(self):
"""
Needs to be called at the end of produce() after init_values was used
"""
self._param_values = None
self._layers = None
def get_layers(self, parameters):
"""
get the layer definitions
@ -335,25 +377,23 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
"""
coerce parameters (make consistent)
"""
self._param_values = parameters
self.init_values(parameters)
self.layout = layout
self.coerce_parameters_impl()
self.layout = None
return self._param_values
return self.get_values()
def produce(self, layout, layers, parameters, cell):
"""
coerce parameters (make consistent)
"""
self._layers = layers
self.init_values(parameters, layers)
self.cell = cell
self._param_values = parameters
self.layout = layout
self.produce_impl()
self._layers = None
self.cell = None
self._param_values = None
self.layout = None
self.finish()
def can_create_from_shape(self, layout, shape, layer):
"""
@ -386,17 +426,16 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
produce a helper for parameters_from_shape
with this helper, the implementation can use the parameter setters
"""
self._param_values = []
for pd in self._param_decls:
self._param_values.append(pd.default)
self.init_values()
self.layout = layout
self.shape = shape
self.layer = layer
self.parameters_from_shape_impl()
param = self.get_values()
self.layout = None
self.shape = None
self.layer = None
return self._param_values
return param
def display_text_impl(self):
"""
@ -432,7 +471,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
"""
default implementation
"""
return pya.Trans.new
return pya.Trans()
# import the Type... constants from PCellParameterDeclaration
for k in dir(pya.PCellParameterDeclaration):

View File

@ -110,6 +110,18 @@ OASISReader::OASISReader (tl::InputStream &s)
{
m_progress.set_format (tl::to_string (QObject::tr ("%.0f MB")));
m_progress.set_unit (1024 * 1024);
m_first_cellname = 0;
m_first_propname = 0;
m_first_propstring = 0;
m_first_textstring = 0;
m_first_layername = 0;
m_in_table = NotInTable;
m_table_cellname = 0;
m_table_propname = 0;
m_table_propstring = 0;
m_table_textstring = 0;
m_table_layername = 0;
m_table_start = 0;
}
OASISReader::~OASISReader ()
@ -197,6 +209,16 @@ OASISReader::get_long ()
}
}
inline unsigned long
OASISReader::get_ulong_for_divider ()
{
unsigned long l = get_ulong ();
if (l == 0) {
error (tl::to_string (QObject::tr ("Divider must not be zero")));
}
return l;
}
inline unsigned long
OASISReader::get_ulong ()
{
@ -295,21 +317,21 @@ OASISReader::get_real ()
} else if (t == 2) {
return 1.0 / double (get_ulong ());
return 1.0 / double (get_ulong_for_divider ());
} else if (t == 3) {
return -1.0 / double (get_ulong ());
return -1.0 / double (get_ulong_for_divider ());
} else if (t == 4) {
double d = double (get_ulong ());
return d / double (get_ulong ());
return d / double (get_ulong_for_divider ());
} else if (t == 5) {
double d = double (get_ulong ());
return -d / double (get_ulong ());
return -d / double (get_ulong_for_divider ());
} else if (t == 6) {

View File

@ -318,6 +318,7 @@ private:
unsigned long long get_ulong_long ();
long get_long ();
unsigned long get_ulong ();
unsigned long get_ulong_for_divider ();
int get_int ();
unsigned int get_uint ();

View File

@ -186,15 +186,28 @@ PCellVariant::update (ImportLayerMapping *layer_mapping)
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (m_parameters[i].to_user<db::DBox> () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Box> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(m_parameters[i].to_user<db::Box> (), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DEdge> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(db::Edge (m_parameters[i].to_user<db::DEdge> () * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Edge> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::EdgeWithProperties(m_parameters[i].to_user<db::Edge> (), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DPoint> ()) {
db::DPoint p = m_parameters[i].to_user<db::DPoint> ();
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (db::DBox (p, p) * (1.0 / layout ()->dbu ())), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Point> ()) {
db::Point p = m_parameters[i].to_user<db::Point> ();
shapes (layout ()->guiding_shape_layer ()).insert (db::BoxWithProperties(db::Box (p, p), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DPolygon> ()) {
db::complex_trans<db::DCoord, db::Coord> dbu_trans (1.0 / layout ()->dbu ());
@ -202,11 +215,21 @@ PCellVariant::update (ImportLayerMapping *layer_mapping)
// Hint: we don't compress the polygon since we don't want to loose information
shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Polygon> ()) {
db::Polygon poly = m_parameters[i].to_user<db::Polygon> ();
// Hint: we don't compress the polygon since we don't want to loose information
shapes (layout ()->guiding_shape_layer ()).insert (db::PolygonWithProperties(poly, layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::DPath> ()) {
db::complex_trans<db::DCoord, db::Coord> dbu_trans (1.0 / layout ()->dbu ());
shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(dbu_trans * m_parameters[i].to_user<db::DPath> (), layout ()->properties_repository ().properties_id (props)));
} else if (m_parameters[i].is_user<db::Path> ()) {
shapes (layout ()->guiding_shape_layer ()).insert (db::PathWithProperties(m_parameters[i].to_user<db::Path> (), layout ()->properties_repository ().properties_id (props)));
}
}

View File

@ -276,6 +276,8 @@ RecursiveShapeIterator::init ()
m_shape_inv_prop_sel = false;
m_inst_quad_id = 0;
m_shape_quad_id = 0;
mp_cell = 0;
m_current_layer = 0;
}
void

View File

@ -883,8 +883,6 @@ static bool cell_has_prop_id (const db::Cell *c)
static void delete_cell_property (db::Cell *c, const tl::Variant &key)
{
check_is_editable (c);
db::properties_id_type id = c->prop_id ();
if (id == 0) {
return;
@ -911,8 +909,6 @@ static void delete_cell_property (db::Cell *c, const tl::Variant &key)
static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Variant &value)
{
check_is_editable (c);
db::properties_id_type id = c->prop_id ();
db::Layout *layout = c->layout ();
@ -1110,13 +1106,11 @@ static void move_or_copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, un
static void move_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer)
{
check_is_editable (cell);
move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, true);
}
static void copy_from_other_cell (db::Cell *cell, db::Cell *src_cell, unsigned int src_layer, unsigned int dest_layer)
{
check_is_editable (cell);
move_or_copy_from_other_cell (cell, src_cell, src_layer, dest_layer, false);
}
@ -1158,7 +1152,6 @@ write_options (const db::Cell *cell, const std::string &filename, const db::Save
static void
clear_all (db::Cell *cell)
{
check_is_editable (cell);
cell->clear_shapes ();
cell->clear_insts ();
}
@ -1166,7 +1159,6 @@ clear_all (db::Cell *cell)
static void
delete_cell (db::Cell *cell)
{
check_is_editable (cell);
db::Layout *layout = cell->layout ();
if (layout) {
layout->delete_cell (cell->cell_index ());
@ -1176,7 +1168,6 @@ delete_cell (db::Cell *cell)
static void
prune_subcells (db::Cell *cell, int levels)
{
check_is_editable (cell);
db::Layout *layout = cell->layout ();
if (layout) {
layout->prune_subcells (cell->cell_index (), levels);
@ -1192,7 +1183,6 @@ prune_subcells0 (db::Cell *cell)
static void
prune_cell (db::Cell *cell, int levels)
{
check_is_editable (cell);
db::Layout *layout = cell->layout ();
if (layout) {
layout->prune_cell (cell->cell_index (), levels);
@ -1208,7 +1198,6 @@ prune_cell0 (db::Cell *cell)
static void
flatten (db::Cell *cell, int levels, bool prune)
{
check_is_editable (cell);
db::Layout *layout = cell->layout ();
if (layout) {
layout->flatten (*cell, levels, prune);
@ -1288,8 +1277,6 @@ begin_shapes_rec_overlapping_um (const db::Cell *cell, unsigned int layer, db::D
static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
}
@ -1318,8 +1305,6 @@ static void copy_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db:
static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
}
@ -1344,8 +1329,6 @@ static void copy_shapes1 (db::Cell *cell, const db::Cell &source_cell)
static void copy_instances (db::Cell *cell, const db::Cell &source_cell)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy instances within the same cell")));
}
@ -1360,8 +1343,6 @@ static void copy_instances (db::Cell *cell, const db::Cell &source_cell)
static std::vector<db::cell_index_type> copy_tree (db::Cell *cell, const db::Cell &source_cell)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
}
@ -1393,8 +1374,6 @@ static std::vector<db::cell_index_type> copy_tree (db::Cell *cell, const db::Cel
static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
}
@ -1421,8 +1400,6 @@ static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, cons
static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot copy shapes within the same cell")));
}
@ -1446,8 +1423,6 @@ static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, cons
static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
}
@ -1478,8 +1453,6 @@ static void move_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::Layer
static void move_shapes1 (db::Cell *cell, db::Cell &source_cell)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
}
@ -1505,8 +1478,6 @@ static void move_shapes1 (db::Cell *cell, db::Cell &source_cell)
static void move_instances (db::Cell *cell, db::Cell &source_cell)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move instances within the same cell")));
}
@ -1523,8 +1494,6 @@ static void move_instances (db::Cell *cell, db::Cell &source_cell)
static std::vector<db::cell_index_type> move_tree (db::Cell *cell, db::Cell &source_cell)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
}
@ -1558,8 +1527,6 @@ static std::vector<db::cell_index_type> move_tree (db::Cell *cell, db::Cell &sou
static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
}
@ -1586,8 +1553,6 @@ static void move_tree_shapes2 (db::Cell *cell, db::Cell &source_cell, const db::
static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm)
{
check_is_editable (cell);
if (cell == &source_cell) {
throw tl::Exception (tl::to_string (QObject::tr ("Cannot move shapes within the same cell")));
}
@ -1612,8 +1577,6 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::
static void
fill_region1 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin)
{
check_is_editable (cell);
if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)")));
}
@ -1624,8 +1587,6 @@ static void
fill_region2 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin,
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons)
{
check_is_editable (cell);
if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid fill cell footprint (empty or zero width/height)")));
}

View File

@ -58,6 +58,7 @@ struct A : public db::Object
void redo (db::Op *op) throw ()
{
AO *aop = dynamic_cast<AO *> (op);
tl_assert (aop != 0);
x += aop->d;
}
@ -162,6 +163,7 @@ struct B : public db::Object
void redo (db::Op *op) throw ()
{
BO *bop = dynamic_cast<BO *> (op);
tl_assert (bop != 0);
x += bop->d;
}

View File

@ -3922,9 +3922,9 @@ CODE
n = $1.to_i - 1
view = RBA::LayoutView::current
view || raise("No view open")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n}")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n + 1}")
cv = view.cellview(n)
cv.is_valid? || raise("Invalid layout @#{n}")
cv.is_valid? || raise("Invalid layout @#{n + 1}")
@def_source = make_source(cv.layout, cv.cell)
else
layout = RBA::Layout::new
@ -4016,9 +4016,9 @@ CODE
n = $1.to_i - 1
view = RBA::LayoutView::current
view || raise("No view open")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n}")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n + 1}")
cv = view.cellview(n)
cv.is_valid? || raise("Invalid layout @#{n}")
cv.is_valid? || raise("Invalid layout @#{n + 1}")
return make_source(cv.layout, cv.cell)
else
layout = RBA::Layout::new
@ -4173,9 +4173,9 @@ CODE
n = $1.to_i - 1
view = RBA::LayoutView::current
view || raise("No view open")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n}")
(n &gt;= 0 &amp;&amp; view.cellviews &gt; n) || raise("Invalid layout index @#{n + 1}")
cv = view.cellview(n)
cv.is_valid? || raise("Invalid layout @#{n}")
cv.is_valid? || raise("Invalid layout @#{n + 1}")
@output_layout = cv.layout
@output_cell = cellname ? (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)) : cv.cell
@output_layout_file = nil
@ -4694,11 +4694,20 @@ CODE
else
output = @output_layout || @def_layout
output || raise("No output layout specified")
output_cell = @output_cell || @def_cell
output_cell || raise("No output cell specified")
if @output_layout
output = @output_layout
if @output_cell
output_cell = @output_cell
elsif @def_cell
output_cell = @output_layout.cell(@def_cell.name) || @output_layout.create_cell(@def_cell.name)
end
output_cell || raise("No output cell specified (see 'target' instruction)")
else
output = @def_layout
output || raise("No output layout specified")
output_cell = @output_cell || @def_cell
output_cell || raise("No output cell specified")
end
info = nil
if args.size == 1

View File

@ -1084,23 +1084,29 @@ MainService::cm_convert_to_pcell ()
db::Library *lib = db::LibraryManager::instance ().lib (l->second);
for (db::Layout::pcell_iterator pc = lib->layout ().begin_pcells (); pc != lib->layout ().end_pcells (); ++pc) {
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second);
size_t n = 1000; // 1000 tries max.
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) {
const lay::CellView &cv = view ()->cellview (s->cv_index ());
if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) {
--n;
} else {
pc_decl = 0; // stop
try {
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pc->second);
size_t n = 1000; // 1000 tries max.
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); n > 0 && pc_decl && es != edt_services.end (); ++es) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); n > 0 && pc_decl && s != (*es)->selection ().end (); ++s) {
const lay::CellView &cv = view ()->cellview (s->cv_index ());
if (pc_decl->can_create_from_shape (cv->layout (), s->shape (), s->layer ())) {
--n;
} else {
pc_decl = 0; // stop
}
}
}
}
// We have positive hit
if (pc_decl) {
pcells.push_back (std::make_pair (lib, pc->second));
items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ()));
// We have positive hit
if (pc_decl) {
pcells.push_back (std::make_pair (lib, pc->second));
items.push_back (tl::to_qstring (lib->get_name () + "." + pc_decl->name ()));
}
} catch (...) {
// ignore errors in can_create_from_shape
}
}

View File

@ -1092,7 +1092,7 @@ Net::Net ()
}
Net::Net (const NetTracer &tracer, const db::ICplxTrans &trans, const db::Layout &layout, db::cell_index_type cell_index, const std::string &layout_filename, const std::string &layout_name, const NetTracerData &data)
: m_name (tracer.name ()), m_incomplete (tracer.incomplete ())
: m_name (tracer.name ()), m_incomplete (tracer.incomplete ()), m_trace_path (false)
{
m_dbu = layout.dbu ();
m_top_cell_name = layout.cell_name (cell_index);

View File

@ -607,11 +607,30 @@ RS274XMacroAperture::do_produce_flash ()
}
}
void
RS274XMacroAperture::read_exposure (tl::Extractor &ex, bool &clear, bool &clear_set)
{
int pol = int (floor (read_expr (ex) + 0.5));
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear_set || !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
clear_set = true;
}
void
RS274XMacroAperture::do_produce_flash_internal ()
{
tl::Extractor ex (m_def.c_str ());
bool clear = false;
bool clear_set = false;
while (! ex.at_end ()) {
@ -640,18 +659,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
if (code == 1) {
ex.expect (",");
int pol = (read_expr (ex) > 0.5);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
read_exposure (ex, clear, clear_set);
ex.expect (",");
double d = read_expr (ex, true);
ex.expect (",");
@ -670,18 +678,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 2 || code == 20) {
ex.expect (",");
int pol = (read_expr (ex) > 0.5);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
read_exposure (ex, clear, clear_set);
ex.expect (",");
double w = read_expr (ex, true);
ex.expect (",");
@ -723,18 +720,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 21 || code == 22) {
ex.expect (",");
int pol = (read_expr (ex) > 0.5);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
read_exposure (ex, clear, clear_set);
ex.expect (",");
double w = read_expr (ex, true);
ex.expect (",");
@ -766,18 +752,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 4) {
ex.expect (",");
int pol = (read_expr (ex) > 0.5);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
read_exposure (ex, clear, clear_set);
ex.expect (",");
int n = int (read_expr (ex) + 0.5);
if (n < 1) {
@ -854,18 +829,7 @@ RS274XMacroAperture::do_produce_flash_internal ()
} else if (code == 5) {
ex.expect (",");
int pol = (read_expr (ex) > 0.5);
if (pol == 0) {
clear = true;
} else if (pol == 1) {
clear = false;
} else if (pol == 2) {
clear = !clear;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid exposure code '%d'")), pol);
}
read_exposure (ex, clear, clear_set);
ex.expect (",");
int n = int (read_expr (ex) + 0.5);
if (n < 3) {

View File

@ -168,6 +168,7 @@ private:
double read_atom (tl::Extractor &ex);
double read_dot_expr (tl::Extractor &ex);
double read_expr (tl::Extractor &ex, bool length = false);
void read_exposure (tl::Extractor &ex, bool &clear, bool &clear_set);
void do_produce_flash_internal ();
};

View File

@ -524,7 +524,6 @@ private:
ArgType m_ret_type;
bool m_const : 1;
bool m_static : 1;
bool m_is_predicate : 1;
bool m_protected : 1;
unsigned int m_argsize;
std::vector<MethodSynonym> m_method_synonyms;

View File

@ -697,12 +697,14 @@ static size_t make_id ()
Object::Object ()
: m_trans (1.0), mp_data (0), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
{
m_updates_enabled = false;
mp_pixel_data = 0;
}
Object::Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color)
: m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
{
m_updates_enabled = false;
mp_pixel_data = 0;
mp_data = new DataHeader (w, h, color, false);

View File

@ -211,10 +211,12 @@ ProgressReporter::set_visible (bool vis)
// actual operation
tl::DeferredMethodScheduler::enable (!vis);
if (!vis) {
mp_pb->progress_remove_widget ();
} else if (mp_pb->progress_wants_widget () && mp_objects.front ()) {
mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ());
if (mp_pb) {
if (!vis) {
mp_pb->progress_remove_widget ();
} else if (mp_pb->progress_wants_widget () && mp_objects.front ()) {
mp_pb->progress_add_widget (mp_objects.front ()->progress_widget ());
}
}
m_pw_visible = vis;

View File

@ -259,7 +259,7 @@ SaltGrainPropertiesDialog::dependency_changed (QTreeWidgetItem *item, int column
m_update_enabled = false;
std::string name = tl::to_string (item->data (0, Qt::UserRole).toString ().simplified ());
SaltGrain *g = mp_salt->grain_by_name (name);
SaltGrain *g = mp_salt ? mp_salt->grain_by_name (name) : 0;
if (column == 0 && mp_salt) {

View File

@ -45,7 +45,7 @@ static lay::Technology *create_technology (const std::string &name)
{
lay::Technology *tech = new lay::Technology ();
tech->set_name (name);
lay::Technologies::instance ()->add (tech);
lay::Technologies::instance ()->add_new (tech);
return tech;
}

View File

@ -88,11 +88,13 @@ save_dialog_state (QWidget *w)
}
for (QList<QObject *>::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) {
if (dynamic_cast <QWidget *> (*c)) {
std::string cs = save_dialog_state (dynamic_cast <QWidget *> (*c));
if (! cs.empty ()) {
s += cs;
if (w) {
for (QList<QObject *>::const_iterator c = w->children ().begin (); c != w->children ().end (); ++c) {
if (dynamic_cast <QWidget *> (*c)) {
std::string cs = save_dialog_state (dynamic_cast <QWidget *> (*c));
if (! cs.empty ()) {
s += cs;
}
}
}
}

View File

@ -45,6 +45,8 @@ Technologies::Technologies ()
Technologies::Technologies (const Technologies &other)
: tl::Object ()
{
m_changed = false;
m_in_update = false;
operator= (other);
}
@ -115,19 +117,30 @@ Technologies::load_from_xml (const std::string &s)
}
void
Technologies::add (Technology *technology)
Technologies::add_tech (Technology *tech, bool replace_same)
{
for (tl::stable_vector<Technology>::iterator t = m_technologies.begin (); technology && t != m_technologies.end (); ++t) {
if (t->name () == technology->name ()) {
*t = *technology;
delete technology;
technology = 0;
if (! tech) {
return;
}
std::auto_ptr<Technology> tech_ptr (tech);
Technology *t = 0;
for (tl::stable_vector<Technology>::iterator i = m_technologies.begin (); !t && i != m_technologies.end (); ++i) {
if (i->name () == tech->name ()) {
t = i.operator-> ();
}
}
if (technology) {
m_technologies.push_back (technology);
technology->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
if (t) {
if (replace_same) {
*t = *tech;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("A technology with this name already exists: %1").arg (tl::to_qstring (tech->name ()))));
}
} else {
m_technologies.push_back (tech_ptr.release ());
tech->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
}
technologies_changed ();
@ -218,6 +231,7 @@ Technologies::technology_by_name (const std::string &name)
}
}
tl_assert (! m_technologies.empty ());
return &*m_technologies.begin ();
}

View File

@ -126,7 +126,22 @@ public:
* The container becomes owner of the technology object.
* Replaces a technology with the name of the given technology.
*/
void add (Technology *technology);
void add (Technology *technology)
{
add_tech (technology, true /*replace*/);
}
/**
* @brief Adds a technology with a new name
*
* Like \add, but throws an exception if a technology with this name
* already exists. Takes over ownership over the technology object.
* The technology object is discarded if an exception is thrown.
*/
void add_new (Technology *technology)
{
add_tech (technology, false /*throws exception on same name*/);
}
/**
* @brief Remove a technology with the given name from the setup
@ -233,6 +248,8 @@ private:
tl::stable_vector<Technology> m_technologies;
bool m_changed;
bool m_in_update;
void add_tech (Technology *technology, bool replace_same);
};
/**

View File

@ -915,26 +915,28 @@ void Macro::install_doc () const
if (cls == 0) {
tl::error << tl::to_string (QObject::tr ("Reading class doc from ")) << path () << ": " << tl::to_string (QObject::tr ("@method without preceeding @class"));
}
} else {
std::string n;
ex.read_word_or_quoted (n);
std::string n;
ex.read_word_or_quoted (n);
std::string doc;
while (++i < lines.size ()) {
std::string l = tl::trim (lines [i]);
if (l.find ("@method") == 0 || l.find ("@static_method") == 0) {
break;
std::string doc;
while (++i < lines.size ()) {
std::string l = tl::trim (lines [i]);
if (l.find ("@method") == 0 || l.find ("@static_method") == 0) {
break;
}
if (! doc.empty ()) {
doc += "\n";
}
doc += lines [i];
}
if (! doc.empty ()) {
doc += "\n";
}
doc += lines [i];
}
--i;
--i;
ExternalMethod *meth = new ExternalMethod (n, doc, false, st);
cls->add_method (meth);
ExternalMethod *meth = new ExternalMethod (n, doc, false, st);
cls->add_method (meth);
}
}

View File

@ -1945,7 +1945,11 @@ property_setter_impl (int mid, PyObject *self, PyObject *value)
if (meth->is_signal ()) {
if (PyObject_IsInstance (value, (PyObject *) PYASignal::cls)) {
if (!p) {
// TODO: Static signals?
} else if (PyObject_IsInstance (value, (PyObject *) PYASignal::cls)) {
// assigning a signal to a signal works if it applies to the same handler -
// this simplifies the implementation of += and -=.

View File

@ -495,7 +495,7 @@ public:
bool compare (const ValueBase *other) const
{
return m_value < dynamic_cast<const Value<C> *> (other)->m_value;
return m_value < static_cast<const Value<C> *> (other)->m_value;
}
std::string to_string () const;

View File

@ -213,7 +213,7 @@ public:
++lb0;
}
--lb;
if (lb != m_index_map.end () && i2 < lb->first.second) {
if (i2 < lb->first.second) {
// the last one is overlapping above i2: cut it
lb->first.first = i2;
} else {

View File

@ -424,17 +424,20 @@ JobBase::schedule (Task *task)
{
m_lock.lock ();
// Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition)
if (m_stopping) {
m_lock.unlock ();
throw TaskTerminatedException ();
}
// Add the task to the task queue
m_task_list.put (task);
// Don't allow tasks to be scheduled while stopping or exiting (waiting for m_queue_empty_condition)
delete task;
} else {
// Add the task to the task queue
m_task_list.put (task);
if (m_running) {
m_task_available_condition.wakeAll ();
}
if (m_running) {
m_task_available_condition.wakeAll ();
}
m_lock.unlock ();

View File

@ -1298,7 +1298,7 @@ Variant::can_convert_to_long () const
case t_double:
return m_var.m_double <= std::numeric_limits<long>::max () && m_var.m_double >= std::numeric_limits<long>::min ();
case t_float:
return m_var.m_float <= std::numeric_limits<long>::max () && m_var.m_float >= std::numeric_limits<long>::min ();
return m_var.m_float <= float (std::numeric_limits<long>::max ()) && m_var.m_float >= float (std::numeric_limits<long>::min ());
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<long>::min ());

View File

@ -52,20 +52,25 @@ class BoxPCell(pya.PCellDeclaration):
# create the shape
cell.shapes(layers[0]).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2))
def can_create_from_shape(self, layout, shape, layer):
return shape.is_box()
def transformation_from_shape(self, layout, shape, layer):
return pya.Trans(shape.box.center() - pya.Point())
def parameters_from_shape(self, layout, shape, layer):
return [ layout.get_info(layer), shape.box.width() * layout.dbu, shape.box.height() * layout.dbu ]
class PCellTestLib(pya.Library):
boxpcell = None
def __init__(self):
# set the description
self.description = "PCell test lib"
# create the PCell declarations
boxpcell = BoxPCell()
self.layout().register_pcell("Box", boxpcell)
self.layout().register_pcell("Box", BoxPCell())
sb_index = self.layout().add_cell("StaticBox")
l10 = self.layout().insert_layer(pya.LayerInfo(10, 0))
@ -75,6 +80,60 @@ class PCellTestLib(pya.Library):
# register us with the name "MyLib"
self.register("PCellTestLib")
# A PCell based on the declaration helper
class BoxPCell2(pya.PCellDeclarationHelper):
def __init__(self):
super(BoxPCell2, self).__init__()
self.param("layer", self.TypeLayer, "Layer", default = pya.LayerInfo(0, 0))
self.param("width", self.TypeDouble, "Width", default = 1.0)
self.param("height", self.TypeDouble, "Height", default = 1.0)
def display_text_impl(self):
# provide a descriptive text for the cell
return "Box2(L=" + str(self.layer) + ",W=" + ('%.3f' % self.width) + ",H=" + ('%.3f' % self.height) + ")"
def produce_impl(self):
dbu = self.layout.dbu
# fetch the parameters
l = self.layer_layer
w = self.width / self.layout.dbu
h = self.height / self.layout.dbu
# create the shape
self.cell.shapes(l).insert(pya.Box(-w / 2, -h / 2, w / 2, h / 2))
def can_create_from_shape_impl(self):
return self.shape.is_box()
def transformation_from_shape_impl(self):
return pya.Trans(self.shape.box.center() - pya.Point())
def parameters_from_shape_impl(self):
self.layer = self.layout.get_info(self.layer)
self.width = self.shape.box.width() * self.layout.dbu
self.height = self.shape.box.height() * self.layout.dbu
class PCellTestLib2(pya.Library):
def __init__(self):
# set the description
self.description = "PCell test lib2"
# create the PCell declarations
self.layout().register_pcell("Box2", BoxPCell2())
# register us with the name "MyLib"
self.register("PCellTestLib2")
def inspect_LayerInfo(self):
return "<" + str(self) + ">"
@ -233,6 +292,75 @@ class DBPCellTests(unittest.TestCase):
pcell_inst.cell_index = new_id
self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-500,-100;500,100)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(pya.Box(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(pya.Text("hello", pya.Trans()))
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False)
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True)
self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]")
self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110")
def test_1a(self):
# instantiate and register the library
tl = PCellTestLib2()
ly = pya.Layout(True)
ly.dbu = 0.01
li1 = find_layer(ly, "1/0")
self.assertEqual(li1 == None, True)
ci1 = ly.add_cell("c1")
c1 = ly.cell(ci1)
lib = pya.Library.library_by_name("PCellTestLib2")
self.assertEqual(lib != None, True)
pcell_decl = lib.layout().pcell_declaration("Box2")
param = [ pya.LayerInfo(1, 0) ] # rest is filled with defaults
pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param)
pcell_var = ly.cell(pcell_var_id)
pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans()))
self.assertEqual(pcell_var.basic_name(), "Box2")
self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]")
self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)")
self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(pcell_var.pcell_parameter("height").__repr__(), "1.0")
self.assertEqual(c1.pcell_parameters(pcell_inst).__repr__(), "[<1/0>, 1.0, 1.0]")
self.assertEqual(nh(c1.pcell_parameters_by_name(pcell_inst)), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(c1.pcell_parameter(pcell_inst, "height").__repr__(), "1.0")
self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(pcell_inst["height"].__repr__(), "1.0")
self.assertEqual(pcell_inst.pcell_parameter("height").__repr__(), "1.0")
self.assertEqual(pcell_var.pcell_declaration().__repr__(), pcell_decl.__repr__())
self.assertEqual(c1.pcell_declaration(pcell_inst).__repr__(), pcell_decl.__repr__())
self.assertEqual(pcell_inst.pcell_declaration().__repr__(), pcell_decl.__repr__())
li1 = find_layer(ly, "1/0")
self.assertEqual(li1 == None, False)
pcell_inst.change_pcell_parameter("height", 2.0)
self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 2.0, 'layer': <1/0>, 'width': 1.0}")
self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-50,-100;50,100)")
param = { "layer": pya.LayerInfo(2, 0), "width": 2, "height": 1 }
li2 = ly.layer(2, 0)
c1.change_pcell_parameters(pcell_inst, param)
self.assertEqual(ly.begin_shapes(c1.cell_index(), li2).shape().__str__(), "box (-100,-50;100,50)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(pya.Box(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(pya.Text("hello", pya.Trans()))
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False)
self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True)
self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]")
self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110")
def test_2(self):
# instantiate and register the library

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,18 @@ class BoxPCell < RBA::PCellDeclaration
end
def can_create_from_shape(layout, shape, layer)
return shape.is_box?
end
def transformation_from_shape(layout, shape, layer)
return RBA::Trans::new(shape.box.center - RBA::Point::new)
end
def parameters_from_shape(layout, shape, layer)
return [ layout.get_info(layer), shape.box.width * layout.dbu, shape.box.height * layout.dbu ]
end
end
class PCellTestLib < RBA::Library
@ -85,6 +97,72 @@ class PCellTestLib < RBA::Library
end
# A PCell based on the declaration helper
class BoxPCell2 < RBA::PCellDeclarationHelper
def initialize
super()
param("layer", BoxPCell2::TypeLayer, "Layer", :default => RBA::LayerInfo::new(0, 0))
param("width", BoxPCell2::TypeDouble, "Width", :default => 1.0)
param("height", BoxPCell2::TypeDouble, "Height", :default => 1.0)
end
def display_text_impl
# provide a descriptive text for the cell
return "Box2(L=" + layer.to_s + ",W=" + ('%.3f' % width) + ",H=" + ('%.3f' % height) + ")"
end
def produce_impl
# fetch the parameters
l = layer_layer
w = width / layout.dbu
h = height / layout.dbu
# create the shape
cell.shapes(l).insert(RBA::Box::new(-w / 2, -h / 2, w / 2, h / 2))
end
def can_create_from_shape_impl
return self.shape.is_box?
end
def transformation_from_shape_impl
return RBA::Trans::new(shape.box.center - RBA::Point::new)
end
def parameters_from_shape_impl
# NOTE: because there is one parameter called "layer" already, we need to use
# the "_layer" fallback to access the argument to this method
set_layer(_layout.get_info(_layer))
set_width(shape.box.width * _layout.dbu)
set_height(shape.box.height * _layout.dbu)
end
end
class PCellTestLib2 < RBA::Library
def initialize
# set the description
description = "PCell test lib2"
# create the PCell declarations
layout.register_pcell("Box2", BoxPCell2::new)
# register us with the name "MyLib"
self.register("PCellTestLib2")
end
end
# A helper for testing: provide an inspect method
class RBA::LayerInfo
def inspect
@ -115,8 +193,7 @@ class DBPCell_TestClass < TestBase
ly = RBA::Layout::new(true)
ly.dbu = 0.01
li1 = ly.layer_indices.find { |li| ly.get_info(li).to_s == "1/0" }
assert_equal(li1 == nil, true)
li1 = ly.layer(1, 0)
ci1 = ly.add_cell("c1")
c1 = ly.cell(ci1)
@ -241,10 +318,84 @@ class DBPCell_TestClass < TestBase
pcell_inst.cell_index = new_id
assert_equal(ly.begin_shapes(c1.cell_index, li1).shape.to_s, "box (-500,-100;500,100)")
#ly.destroy
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new))
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]")
assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110")
ly.destroy
ensure
#tl.delete
tl.delete
end
end
def test_1a
# instantiate and register the library
tl = PCellTestLib2::new
begin
ly = RBA::Layout::new(true)
ly.dbu = 0.01
ci1 = ly.add_cell("c1")
c1 = ly.cell(ci1)
lib = RBA::Library.library_by_name("PCellTestLib2")
assert_equal(lib != nil, true)
pcell_decl = lib.layout().pcell_declaration("Box2")
param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults
pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param)
pcell_var = ly.cell(pcell_var_id)
pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new))
assert_equal(pcell_var.basic_name, "Box2")
assert_equal(pcell_var.pcell_parameters().inspect, "[<1/0>, 1.0, 1.0]")
assert_equal(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)")
assert_equal(norm_hash(pcell_var.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(pcell_var.pcell_parameter("height").inspect(), "1.0")
assert_equal(c1.pcell_parameters(pcell_inst).inspect(), "[<1/0>, 1.0, 1.0]")
assert_equal(norm_hash(c1.pcell_parameters_by_name(pcell_inst)), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(c1.pcell_parameter(pcell_inst, "height").inspect(), "1.0")
assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(pcell_inst["height"].inspect(), "1.0")
assert_equal(pcell_inst.pcell_parameter("height").inspect(), "1.0")
assert_equal(pcell_var.pcell_declaration().inspect(), pcell_decl.inspect)
assert_equal(c1.pcell_declaration(pcell_inst).inspect(), pcell_decl.inspect)
assert_equal(pcell_inst.pcell_declaration().inspect(), pcell_decl.inspect)
li1 = ly.layer(1, 0)
assert_equal(li1 == nil, false)
pcell_inst.change_pcell_parameter("height", 2.0)
assert_equal(norm_hash(pcell_inst.pcell_parameters_by_name()), "{\"height\"=>2.0, \"layer\"=><1/0>, \"width\"=>1.0}")
assert_equal(ly.begin_shapes(c1.cell_index(), li1).shape().to_s, "box (-50,-100;50,100)")
param = { "layer" => RBA::LayerInfo::new(2, 0), "width" => 2, "height" => 1 }
li2 = ly.layer(2, 0)
c1.change_pcell_parameters(pcell_inst, param)
assert_equal(ly.begin_shapes(c1.cell_index(), li2).shape().to_s, "box (-100,-50;100,50)")
l10 = ly.layer(10, 0)
c1.shapes(l10).insert(RBA::Box::new(0, 10, 100, 210))
l11 = ly.layer(11, 0)
c1.shapes(l11).insert(RBA::Text::new("hello", RBA::Trans::new))
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), false)
assert_equal(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), true)
assert_equal(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).inspect, "[<10/0>, 1.0, 2.0]")
assert_equal(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10).to_s, "r0 50,110")
ly.destroy
ensure
tl.delete
end
end