Fixed #651 (DRC "select" feature issues) (#654)

* WIP: added test case, fixed dup problem and '-' shortcut

* WIP: updated DRC doc and could not resist the temptation to fix 'it's' vs. 'its'

* Deep mode also working with select now. Updated tests.
This commit is contained in:
Matthias Köfferlein 2020-10-10 23:15:51 +02:00 committed by Matthias Koefferlein
parent 4b0e122a83
commit 9d3d3e8df6
35 changed files with 290 additions and 97 deletions

View File

@ -911,7 +911,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first;
// collects the cell mappings we skip because they are variants (variant building or box variants)
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > > cm_skipped_variants;
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {
@ -925,14 +925,14 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
HierarchyBuilder::cell_map_type::const_iterator mm = m;
++mm;
bool skip = original_builder.is_variant (m->second); // skip variant cells
while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) {
while (mm != original_builder.end_cell_map () && mm->first.original_cell == m->first.original_cell) {
// we have cell (box) variants and cannot simply map
++mm;
skip = true;
}
if (! skip) {
cm->second.map (m->second, m->first.first);
cm->second.map (m->second, m->first.original_cell);
} else {
for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) {
tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ());
@ -968,17 +968,19 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
db::cell_index_type var_org = original_builder.original_target_for_variant (np->first);
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > >::const_iterator icm = cm_skipped_variants.find (var_org);
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey>::const_iterator icm = cm_skipped_variants.find (var_org);
if (icm != cm_skipped_variants.end ()) {
// create the variant clone in the original layout too and delete this cell
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.first);
cells_to_delete.insert (icm->second.first);
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.original_cell);
cells_to_delete.insert (icm->second.original_cell);
// forget the original cell (now separated into variants) and map the variants back into the
// DSS layout
original_builder.unmap (icm->second);
original_builder.map (std::make_pair (np->second, icm->second.second), np->first);
db::HierarchyBuilder::CellMapKey k = icm->second;
k.original_cell = np->second;
original_builder.map (k, np->first);
// forget the variant as now it's a real cell in the source layout
original_builder.unregister_variant (np->first);

View File

@ -62,6 +62,14 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
return iter1.max_depth () < iter2.max_depth () ? -1 : 1;
}
// take potential selection of cells into account
if (iter1.disables () != iter2.disables ()) {
return iter1.disables () < iter2.disables () ? -1 : 1;
}
if (iter1.enables () != iter2.enables ()) {
return iter1.enables () < iter2.enables () ? -1 : 1;
}
// if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
@ -238,11 +246,11 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
return;
}
std::pair<db::cell_index_type, std::set<db::Box> > key (iter->top_cell ()->cell_index (), std::set<db::Box> ());
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> ());
m_cm_entry = m_cell_map.find (key);
if (m_cm_entry == m_cell_map.end ()) {
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first));
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.original_cell));
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first;
}
@ -300,27 +308,47 @@ HierarchyBuilder::leave_cell (const RecursiveShapeIterator * /*iter*/, const db:
m_cell_stack.pop_back ();
}
db::cell_index_type
HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name)
{
m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;
db::cell_index_type new_cell;
if (m_cm_entry == m_cell_map.end ()) {
std::string cn = cell_name;
if (! key.clip_region.empty ()) {
cn += "$CLIP_VAR";
}
if (key.inactive) {
cn += "$DIS";
}
new_cell = mp_target->add_cell (cn.c_str ());
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
m_cm_new_entry = true;
m_cells_to_be_filled.insert (new_cell);
} else {
new_cell = m_cm_entry->second;
}
return new_cell;
}
HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
if (all) {
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), std::set<db::Box> ());
m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;
if (m_cm_entry == m_cell_map.end ()) {
db::cell_index_type new_cell = mp_target->add_cell (iter->layout ()->cell_name (inst.object ().cell_index ()));
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
m_cm_new_entry = true;
m_cells_to_be_filled.insert (new_cell);
}
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set<db::Box> ());
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));
// for new cells, create this instance
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
new_inst.object () = db::CellInst (m_cm_entry->second);
new_inst.object () = db::CellInst (new_cell);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
@ -353,24 +381,12 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
return false;
}
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), clip_variant.second);
m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;
if (m_cm_entry == m_cell_map.end ()) {
std::string suffix;
if (! key.second.empty ()) {
suffix = "$CLIP_VAR";
}
db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ());
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
m_cm_new_entry = true;
m_cells_to_be_filled.insert (new_cell);
}
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), clip_variant.second);
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));
// for a new cell, create this instance
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans);
db::CellInstArray new_inst (db::CellInst (new_cell), trans);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);

View File

@ -208,8 +208,36 @@ class DB_PUBLIC HierarchyBuilder
: public db::RecursiveShapeReceiver
{
public:
struct CellMapKey
{
CellMapKey ()
: original_cell (0), inactive (false)
{ }
typedef std::map<std::pair<db::cell_index_type, std::set<db::Box> >, db::cell_index_type> cell_map_type;
CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set<db::Box> &_clip_region)
: original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region)
{ }
bool operator== (const CellMapKey &other) const
{
return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region;
}
bool operator< (const CellMapKey &other) const
{
if (original_cell != other.original_cell) { return original_cell < other.original_cell; }
if (inactive != other.inactive) { return inactive < other.inactive; }
if (clip_region != other.clip_region) { return clip_region < other.clip_region; }
return false;
}
db::cell_index_type original_cell;
bool inactive;
std::set<db::Box> clip_region;
};
typedef std::map<CellMapKey, db::cell_index_type> cell_map_type;
typedef std::map<db::cell_index_type, std::vector<db::cell_index_type> > original_target_to_variants_map_type;
typedef std::map<db::cell_index_type, db::cell_index_type> variant_to_original_target_map_type;
@ -329,6 +357,8 @@ public:
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;
private:
db::cell_index_type make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name);
tl::weak_ptr<db::Layout> mp_target;
HierarchyBuilderShapeReceiver *mp_pipe;
bool m_initial_pass;

View File

@ -864,10 +864,9 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
m_layer = m_layers.front ();
}
if (! m_start.empty () && m_start.find (cell_index ()) != m_start.end ()) {
set_inactive (false);
} else if (! m_stop.empty () && m_stop.find (cell_index ()) != m_stop.end ()) {
set_inactive (true);
bool new_cell_inactive = is_child_inactive (cell_index ());
if (is_inactive () != new_cell_inactive) {
set_inactive (new_cell_inactive);
}
new_layer ();
@ -975,6 +974,18 @@ RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
}
}
bool
RecursiveShapeIterator::is_child_inactive (db::cell_index_type new_child) const
{
bool inactive = is_inactive ();
if (! m_start.empty () && m_start.find (new_child) != m_start.end ()) {
inactive = false;
} else if (! m_stop.empty () && m_stop.find (new_child) != m_stop.end ()) {
inactive = true;
}
return inactive;
}
void
RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
{

View File

@ -704,6 +704,19 @@ public:
*/
void push (RecursiveShapeReceiver *receiver);
/**
* @brief Returns a value indicating whether the current cell is inactive (disabled)
*/
bool is_inactive () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
}
/**
* @brief Returns a value indicating whether a new child cell of the current cell will be inactive
*/
bool is_child_inactive (db::cell_index_type new_child) const;
private:
std::vector<unsigned int> m_layers;
bool m_has_layers;
@ -760,11 +773,6 @@ private:
bool is_outside_complex_region (const db::Box &box) const;
bool is_inactive () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
}
void set_inactive (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);

View File

@ -1233,7 +1233,7 @@ module DRC
# @/code
#
# (Technically, the cheat code block is a Ruby Proc and cannot create variables
# outside it's scope. Hence the results of this code block have to be passed
# outside its scope. Hence the results of this code block have to be passed
# through the "cheat" method).
#
# To apply cheats for device extraction, use the following scheme:
@ -1809,7 +1809,7 @@ CODE
sel.each do |s|
if s == "-"
iter.unselect_cells(cell.cell_index)
iter.unselect_cells([cell_index])
elsif s == "-*"
iter.unselect_all_cells
elsif s == "+*"

View File

@ -156,7 +156,7 @@ module DRC
# @li \global#capacitor_with_bulk - A capacitor with a separate bulk terminal @/li
# @/ul
#
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs it's own instance
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs its own instance
# of device extractor. The device extractor beside the algorithm and specific
# extraction settings defines the name of the device to be built.
#

View File

@ -22,14 +22,27 @@ module DRC
@layout_var = layout_var
@path = path
@cell = cell
@inside = nil
@box = nil
@layers = nil
@sel = []
@clip = false
@overlapping = false
@tmp_layers = []
end
# Conceptual deep copy (not including the temp layers)
def dup
d = DRCSource::new(@engine, @layout, @layout_var, @cell, @path)
d._init_internal(@box ? @box.dup : nil, @sel.dup, @clip, @overlapping)
d
end
# internal copy initialization
def _init_internal(box, sel, clip, overlapping)
@box = box
@sel = sel
@clip = clip
@overlapping = overlapping
end
# %DRC%
# @name layout
@ -139,19 +152,34 @@ module DRC
# code:
#
# @code
# layout_with_selection = layout.select("-TOP", "+B")
# l1 = layout_with_selection.input(1, 0)
# layout_with_selection = source.select("-TOP", "+B")
# l1 = source.input(1, 0)
# ...
# @/code
#
# Please note that the sample above will deliver the children of "B" because there is
# nothing said about how to proceed with cells other than "TOP" or "B".
# The following code will just select "B" without it's children, because in the
# nothing said about how to proceed with cells other than "TOP" or "B". Conceptually,
# the instantiation path of a cell will be matched against the different filters in the
# order they are given.
# A matching negative expression will disable the cell, a matching positive expression
# will enable the cell. Hence, every cell that has a "B" in the instantiation path
# is enabled.
#
# The following code will just select "B" without its children, because in the
# first "-*" selection, all cells including the children of "B" are disabled:
#
# @code
# layout_with_selection = layout.select("-*", "+B")
# l1 = layout_with_selection.input(1, 0)
# layout_with_selection = source.select("-*", "+B")
# l1 = source.input(1, 0)
# ...
# @/code
#
# The short form "-" will disable the top cell. This code is identical to the first example
# and will start with a disabled top cell regardless of its name:
#
# @code
# layout_with_selection = source.select("-", "+B")
# l1 = source.input(1, 0)
# ...
# @/code

View File

@ -714,3 +714,44 @@ TEST(15_issue548)
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
// Problems with Source#select
TEST(17_issue570)
{
std::string rs = tl::testsrc ();
rs += "/testdata/drc/drcSimpleTests_17.drc";
std::string input = tl::testsrc ();
input += "/testdata/drc/drcSimpleTests_17.gds";
std::string au = tl::testsrc ();
au += "/testdata/drc/drcSimpleTests_au17.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_test_source = '%s'\n"
"$drc_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}

View File

@ -104,7 +104,7 @@ cells T*
</pre>
<p>
A cell expression can already be used by it's own. The report of such a query will simply contain the cells
A cell expression can already be used by its own. The report of such a query will simply contain the cells
selected by that expression. If combined with an action, such expressions already provide useful manipulation
functionality.
</p>
@ -243,7 +243,7 @@ cells TOP..A
is used in (including top cells and all child contexts). Used after a cell, it will return the cell
plus all child cells in each possible context. Used before a cell it will deliver all contexts that cell
is used in every top cells.
The following query will deliver "TOP" plus all it's direct and indirect children:
The following query will deliver "TOP" plus all its direct and indirect children:
</p>
<pre>
@ -398,7 +398,7 @@ with shapes on layer 6 from instances of TOP.. do initial_cell.shapes(&lt;10/0&g
</pre>
<p>
That expression reads all shapes of cell "TOP" and it's children, inserts them into a new layer 10, datatype 0 and
That expression reads all shapes of cell "TOP" and its children, inserts them into a new layer 10, datatype 0 and
transforms the shape after it has been inserted. This expression makes use of the variables "initial_cell" (a Cell object
representing the root cell of the cell query), "shape" (a pointer to the currently selected shape and "path_trans"
(a Trans object representing the transformation of the current shape into the root cell of the query).

View File

@ -164,7 +164,7 @@ end
</pre>
</p><p>
(Technically, the cheat code block is a Ruby Proc and cannot create variables
outside it's scope. Hence the results of this code block have to be passed
outside its scope. Hence the results of this code block have to be passed
through the "cheat" method).
</p><p>
To apply cheats for device extraction, use the following scheme:

View File

@ -296,7 +296,7 @@ Predefined device extractors are:
<li><a href="/about/drc_ref_global.xml#capacitor_with_bulk">global#capacitor_with_bulk</a> - A capacitor with a separate bulk terminal </li>
</ul>
</p><p>
Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs it's own instance
Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs its own instance
of device extractor. The device extractor beside the algorithm and specific
extraction settings defines the name of the device to be built.
</p><p>

View File

@ -233,19 +233,34 @@ To disable the TOP cell but enabled a hypothetical cell B below the top cell, us
code:
</p><p>
<pre>
layout_with_selection = layout.select("-TOP", "+B")
l1 = layout_with_selection.input(1, 0)
layout_with_selection = source.select("-TOP", "+B")
l1 = source.input(1, 0)
...
</pre>
</p><p>
Please note that the sample above will deliver the children of "B" because there is
nothing said about how to proceed with cells other than "TOP" or "B".
The following code will just select "B" without it's children, because in the
nothing said about how to proceed with cells other than "TOP" or "B". Conceptually,
the instantiation path of a cell will be matched against the different filters in the
order they are given.
A matching negative expression will disable the cell, a matching positive expression
will enable the cell. Hence, every cell that has a "B" in the instantiation path
is enabled.
</p><p>
The following code will just select "B" without its children, because in the
first "-*" selection, all cells including the children of "B" are disabled:
</p><p>
<pre>
layout_with_selection = layout.select("-*", "+B")
l1 = layout_with_selection.input(1, 0)
layout_with_selection = source.select("-*", "+B")
l1 = source.input(1, 0)
...
</pre>
</p><p>
The short form "-" will disable the top cell. This code is identical to the first example
and will start with a disabled top cell regardless of its name:
</p><p>
<pre>
layout_with_selection = source.select("-", "+B")
l1 = source.input(1, 0)
...
</pre>
</p>

View File

@ -130,7 +130,7 @@
<p>
If the match expression includes a numerical range or wildcards
for the layer or datatype number, by default all these layers
will be combined into a single one, where it's layer or datatype number is derived
will be combined into a single one, where its layer or datatype number is derived
from the least permitted number.
</p>

View File

@ -37,7 +37,7 @@
edited. Instead, a library installed in the system comes with a technology
association itself.</li>
<li>File format options: technology specific file reader or writer options can be
given. When a layout is saved, it will use the writer options from it's technology.
given. When a layout is saved, it will use the writer options from its technology.
When loading a layout, the reader options from the active technology will be used.</li>
</ul>

View File

@ -28,7 +28,7 @@
cells with the same name will be used as child cells.
</li>
<li>
<b>Deep copy</b>: In deep copy mode, the cell plus it's child cells are copied. All cells will be carried
<b>Deep copy</b>: In deep copy mode, the cell plus its child cells are copied. All cells will be carried
along and when pasting the cell, copies of all children will be created as well.
</li>
</ul>

View File

@ -57,7 +57,7 @@
<p>
KLayout offers a unique feature for the PCell implementation: a PCell can employ "guiding shapes".
"Guiding shapes" are shapes that do not appear as layout themselves but are used by the PCell
to derive it's geometry from. For example the "rounded path" PCell of the "Basic" library
to derive its geometry from. For example the "rounded path" PCell of the "Basic" library
uses a path as a guiding shape. This path is manipulated to obtain the final shape.
</p>

View File

@ -13,13 +13,13 @@
</p>
<ul>
<li><b>Shallow delete:</b> Just the cell (it's shapes and instances) are deleted, not
<li><b>Shallow delete:</b> Just the cell (its shapes and instances) are deleted, not
any cells referenced by this cell. Since cells might no longer be referenced after
that, they may appear as new top cells in the layout.</li>
<li><b>Deep delete:</b> The cell and all it's subcells are deleted, unless the subcells are
<li><b>Deep delete:</b> The cell and all its subcells are deleted, unless the subcells are
referenced otherwise (by cells that are not deleted).
In this delete mode a complete hierarchy of cells can be removed without side effects.</li>
<li><b>Complete delete:</b> The cell and all it's subcells are deleted, even if other cells
<li><b>Complete delete:</b> The cell and all its subcells are deleted, even if other cells
would reference these subcells.</li>
</ul>

View File

@ -8,7 +8,7 @@
<keyword name="Editing"/>
<p>
The "flatten cell" operation flattens a cell into all of it's parents.
The "flatten cell" operation flattens a cell into all of its parents.
This basically removes a cell by promoting her shapes and instances up in the hierarchy.
</p>
@ -16,7 +16,7 @@
Cell flattening can be applied to single instances or cells as a whole.
When applied to an instance, the individual instance is resolved into shapes. The
instantiated cell will still exist afterwards. When applied to a cell, the cell
will disappear and replaced by it's contents in all places it is used.
will disappear and replaced by its contents in all places it is used.
</p>
<p>

View File

@ -23,7 +23,7 @@
are brought up to the current cell's level and removed from the original cell.<br/>
A non-destructive way of moving a shape up in the hierarchy is to copy and paste the shape. This does an
explicit flattening of the shapes selected when inserting them.<br/>
<b>Hint:</b> the current implementation removes the selected object from it's original cell. Since it only creates
<b>Hint:</b> the current implementation removes the selected object from its original cell. Since it only creates
new copies for the selected instances, the object ist lost for all other instances of the cell. This may create undesired
side effects and it is likely that this behaviour will change in future implementations.
</li>

View File

@ -101,7 +101,7 @@
act as a wrapper to something else. In layouts, devices are often implemented as PCells and
appear as specific cells for no other reason than being implemented in a subcell. The same
might happen for schematic subcircuits which wrap a device. "Flattening" means that a circuit
is removed and it's contents are integrated into the calling circuits.
is removed and its contents are integrated into the calling circuits.
</p>
<p>

View File

@ -10,7 +10,7 @@
The main window is divided into three parts: the left area is the hierarchy browser and navigator, the
center part of the canvas and the right part is the layer list with the layer toolbox.
The individual components can be rearranged, so the arrangement described is just the default
arrangement. You can move a component to a new place by dragging it with it's title bar to
arrangement. You can move a component to a new place by dragging it with its title bar to
some other place or detach it from the main window to form a floating separate window.
</p>

View File

@ -40,7 +40,7 @@
In the same way, "Move To" allows one to reposition the selection to a certain point. The point which
is positioned can be chosen relative to the bounding box of the selection. If first example,
the lower-left corner of the selection is picked as the reference point and a certain position
is given in the dialog, the selection is moved such that the lower left position of it's
is given in the dialog, the selection is moved such that the lower left position of its
bounding box will match the given coordinate.
</p>

View File

@ -30,7 +30,7 @@
<p>
Choose "Pull In Other Layout" to combine other layouts already loaded into the
current panel. Basically, KLayout allows viewsing a layout in multiple panels, either
on it's own in different configurations or together with other layouts. "Pull In Other Layout"
on its own in different configurations or together with other layouts. "Pull In Other Layout"
allows configuration of a panel to show another layout which has been loaded into another panel.
In that sense it's the reverse of closing one layout from a panel showing multiple layouts.
</p>

View File

@ -20,7 +20,7 @@
The Alignment of the labels can be specified too: whether the appear left or right-aligned
or centered.
</li>
<li><b>Style:</b> the style determines how the ruler or it's components are drawn. This can be
<li><b>Style:</b> the style determines how the ruler or its components are drawn. This can be
"ruler-like" (with ticks), arrow style, a plain line or with cross markers at the end.
</li>
<li><b>Outline:</b> the outline determines how the two points forming the ruler are connected
@ -31,7 +31,7 @@
</li>
<li><b>Angle constraint:</b> the orientation of the ruler can be restricted in several ways, i.e.
just being horizontal. By default, the ruler uses the global setting. It can however be configured
to provide it's own constraint.
to provide its own constraint.
</li>
<li><b>Object snapping:</b> each ruler can be configure to snap to the closest object edge or vertex.
By default, the rulers use the global setting. It may be disabled however for each ruler.

View File

@ -206,7 +206,7 @@ Application::instance.main_window.views</pre>
to a large degree, so different colors can be used for example. Markers are objects of class
Marker (<class_doc href="Marker"/>).
</li>
<li><b>Local configuration</b>: be default, the layout view pulls it's configuration from the global
<li><b>Local configuration</b>: be default, the layout view pulls its configuration from the global
configuration database. It is possible however to override certain configuration parameters for a
particular view. This allows for example to set the background color for a particular view without
affecting the other views.
@ -703,7 +703,7 @@ layout_view.insert_layer(lp, props)
Width is a "weak" property. That means that for computing the effective width, child nodes
can override the settings inherited from the parent nodes. A width of 0 is considered "not set" and does not
override parent defined widths. Other properties like visibility are "strong", i.e.
the parent can override the properties set for it's children. Another form of combination is "additive" where
the parent can override the properties set for its children. Another form of combination is "additive" where
the effective property value is the "sum" (or in general combination) of all local properties from parent
to child.
</p>

View File

@ -161,7 +161,7 @@ layout.write("my_layout.gds")</pre>
</p>
<p>
A layout can provide and import PCells. PCells are cells that provide it's geometry through program code
A layout can provide and import PCells. PCells are cells that provide its geometry through program code
(for example written in Ruby) and provide parameters which can be adjusted to change the appearance of the
cell. For each PCell a "declaration" must be provided which basically contains the code for the
PCell and some information about the parameters provided by the PCell. PCells are stored in the layout
@ -813,7 +813,7 @@ end</pre>
<keyword name="CellInstArray"/>
<p>
Despite it's name, a <class_doc href="CellInstArray"/> object holds a cell reference which is
Despite its name, a <class_doc href="CellInstArray"/> object holds a cell reference which is
not only an array, but also a single instances. The object represents a raw instance, in contrast to the
Instance object which is basically a pointer to an instance inside the database. CellInstArray objects as raw instances can be created,
copied, modified and stored in the usual containers, but once they are stored inside the Cell object, they can
@ -1060,7 +1060,7 @@ end</pre>
The <class_doc href="Shape"/> object provides a unified view to a geometrical primitive inside
a Shapes container. It also plays an important role for addressing geometrical primitives
inside a Shapes container. A Shape object has general methods and specific methods that apply
depending on it's identity.
depending on its identity.
</p>
<h3>General methods</h3>

View File

@ -108,7 +108,7 @@ end</pre>
<p>
Events are the callback variant which is the easiest one to use. Using an event it is possible
to directly attach a block of code to a callback. An event has a specific signature, i.e.
the parameters it provides. The block can obtain this parameters by listing them in it's argument list.
the parameters it provides. The block can obtain this parameters by listing them in its argument list.
</p>
<p>

View File

@ -36,7 +36,7 @@
The <class_doc href="Point"/> object represents an integer coordinate in the 2-dimensional layout space,
expressed in database units.
That object provides the x and y coordinates through the <class_doc href="Point#x"/> and <class_doc href="Point#y"/> attributes. Points can be added,
subtracted, the euclidian distance and it's square can be computed using the <class_doc href="Point#distance"/> and <class_doc href="Point#sq_distance"/>
subtracted, the euclidian distance and its square can be computed using the <class_doc href="Point#distance"/> and <class_doc href="Point#sq_distance"/>
methods. The <b>*</b> operator used with a factor as the second operand will scale both the x and y coordinates.
</p>
@ -113,7 +113,7 @@
<li><b>Box + Point</b>: computes the box that encloses the box and the point given
as the second operand. It basically enlarges the first box so it includes the second point as well.
</li>
<li><b>contains?(Point)</b>: returns true, if the point is inside the box or on it's edges.
<li><b>contains?(Point)</b>: returns true, if the point is inside the box or on its edges.
</li>
<li><b>enlarge(Point)</b>: will enlarge the box by the x and y coordinates of the Point. Basically the x value
of the point is subtracted from the left side and added to the right. The same way, the y coordinate is added
@ -272,7 +272,7 @@ box = RBA::Box::new(dbox)
<p>
A <class_doc href="Path"/> object represents a line with a certain width. The figure above depicts the basic properties
of a path. The basic geometry of a path is defined by it's spine - a sequence of points that the path follows.
of a path. The basic geometry of a path is defined by its spine - a sequence of points that the path follows.
By default, a path has rectangular end caps with variable length. The end caps can be round, in which case the extension
should be half the path width to avoid paths which are not compatible with the GDS2 format. Round-ended paths return
true on <class_doc href="Path#is_round?"/>. An example for such a path is depicted in the following figure:
@ -641,7 +641,7 @@ ly.top_cell.shapes(ly.layer(100, 0)).insert(r11 &amp; r21)
<class_doc href="EdgePairs"/> edge pair collections, not regions. Each edge pair marks a
violation of the given check.
</p>
<p><class_doc href="Region#extents"/> replaces each polygon with it's bounding box.</p>
<p><class_doc href="Region#extents"/> replaces each polygon with its bounding box.</p>
<p><class_doc href="Region#grid_check"/> performs an on-grid check returning edge pairs for off-grid markers.</p>
<p><class_doc href="Region#holes"/> identifies holes and delivers a new region with the holes as filled polygons.</p>
<p><class_doc href="Region#hulls"/> identifies holes and delivers a new region without the holes.</p>

View File

@ -165,7 +165,7 @@ end</pre>
</p>
<p>
When a Qt object is created in Ruby space with a parent, it's
When a Qt object is created in Ruby space with a parent, its
ownership is passed to the parent. It is safe however to keep a reference to that object, because
KLayout's Ruby binding employs a special Ruby class internally (a proxy) which keeps track of the lifetime
of the Qt object. If the parent is destroyed, the Qt object is destroyed as well. The internal Qt object will

View File

@ -119,7 +119,7 @@ cell.shapes(layer).insert(box)</pre>
An exception to the lifetime control rule given above are Qt objects: a common pattern is to create Qt objects
and add them to a container (i.e. widgets to a dialog). This implies a lifetime control transfer from
Ruby to C++. RBA handles that case by explicitly transferring control when a QObject or one of the
derived objects is created with a parent reference in Ruby code. Qt implements it's own mechanism of controlling
derived objects is created with a parent reference in Ruby code. Qt implements its own mechanism of controlling
the lifetime which includes monitoring of the lifetime of child objects. This feature makes transferring the
control feasible for these kind of objects. For some Qt methods which are know to transfer the ownership
of an object, the ownership is transferred explicitly.

View File

@ -310,7 +310,7 @@ end</pre>
is used for the cell tree and cell box labels. To avoid confusion, it should start with the name of the
PCell. The bracket notation is not mandatory, but it's always a good idea to follow some common style.
The information delivered by this method should be short but contain enough information so that a
PCell variant can be distinguished from it's sibling.
PCell variant can be distinguished from its sibling.
</p>
<p>

42
testdata/drc/drcSimpleTests_17.drc vendored Normal file
View File

@ -0,0 +1,42 @@
source($drc_test_source)
in_cell = source.select("-", "+S*")
not_in_cell = source.select("-SPECIAL")
in_cell_local = source.select("-*", "+SPECIAL")
not_in_cell_local = source.select("+*", "-SPECIAL")
target($drc_test_target)
deep
input(2,0).output(2, 0)
input(3,0).output(3, 0)
flat
in_cell.input(2, 0).output(102, 0)
in_cell.input(3, 0).output(103, 0)
not_in_cell.input(2, 0).output(202, 0)
not_in_cell.input(3, 0).output(203, 0)
in_cell_local.input(2, 0).output(302, 0)
in_cell_local.input(3, 0).output(303, 0)
not_in_cell_local.input(2, 0).output(402, 0)
not_in_cell_local.input(3, 0).output(403, 0)
deep
in_cell.input(2, 0).output(502, 0)
in_cell.input(3, 0).output(503, 0)
not_in_cell.input(2, 0).output(602, 0)
not_in_cell.input(3, 0).output(603, 0)
in_cell_local.input(2, 0).output(702, 0)
in_cell_local.input(3, 0).output(703, 0)
not_in_cell_local.input(2, 0).output(802, 0)
not_in_cell_local.input(3, 0).output(803, 0)

BIN
testdata/drc/drcSimpleTests_17.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au17.gds vendored Normal file

Binary file not shown.