Merge pull request #877 from KLayout/drc-extent-of-cells

Implemented extent(cell_filter) for DRC, added Layout#cells with name…
This commit is contained in:
Matthias Köfferlein
2021-07-21 23:37:10 +02:00
committed by GitHub
14 changed files with 164 additions and 24 deletions
+6
View File
@@ -379,6 +379,12 @@ OriginalLayerRegion::init ()
void
OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
{
// explicitly update the layout if the source is equal to the target
// (needed because we lock the layout below and no update would happen)
if (layout == m_iter.layout ()) {
layout->update ();
}
db::Shapes &sh = layout->cell (into_cell).shapes (into_layer);
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
+25
View File
@@ -41,6 +41,7 @@
#include "dbCellMapping.h"
#include "dbTechnology.h"
#include "tlStream.h"
#include "tlGlobPattern.h"
namespace gsi
{
@@ -708,6 +709,22 @@ static db::Cell *cell_from_name (db::Layout *ly, const std::string &name)
}
}
static std::vector<db::Cell *> cells_from_name (db::Layout *layout, const std::string &filter)
{
tl::GlobPattern gp (filter);
std::vector<db::Cell *> result;
db::Layout::top_down_iterator td = layout->begin_top_down ();
while (td != layout->end_top_down ()) {
if (gp.match (layout->cell_name (*td))) {
result.push_back (&layout->cell (*td));
}
++td;
}
return result;
}
static std::vector<db::Cell *> top_cells (db::Layout *layout)
{
std::vector<db::Cell *> tc;
@@ -1488,6 +1505,14 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"@return The number of cells (the maximum cell index)\n"
) +
gsi::method_ext ("cells", &cells_from_name, gsi::arg ("name_filter"),
"@brief Gets the cell objects for a given name filter\n"
"\n"
"@param name_filter The cell name filter (glob pattern)\n"
"@return A list of \\Cell object of the cells matching the pattern\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("cell", &cell_from_name, gsi::arg ("name"),
"@brief Gets a cell object from the cell name\n"
"\n"
+16 -13
View File
@@ -1484,13 +1484,14 @@ module DRC
# %DRC%
# @name extent
# @brief Creates a new layer with the bounding box of the default source
# @brief Creates a new layer with the bounding box of the default source or cell bounding boxes
# @synopsis extent
# @synopsis extent(cell_filter)
# See \Source#extent for a description of that function.
def extent
def extent(cell_filter = nil)
self._context("extent") do
layout.extent
layout.extent(cell_filter)
end
end
@@ -1615,6 +1616,8 @@ CODE
# # shapes now will be taken from the given rectangle and clipped to it
# l1 = input(1, 0)
# @/code
#
# To remove the clip condition, call "clip" without any arguments.
def clip(*args)
self._context("clip") do
@@ -2638,16 +2641,6 @@ CODE
end
end
private
def _make_string(v)
if v.class.respond_to?(:from_s)
v.class.to_s + "::from_s(" + v.to_s.inspect + ")"
else
v.inspect
end
end
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, global_trans, cls)
if layers.empty? && ! @deep
@@ -2714,6 +2707,16 @@ CODE
end
private
def _make_string(v)
if v.class.respond_to?(:from_s)
v.class.to_s + "::from_s(" + v.to_s.inspect + ")"
else
v.inspect
end
end
def _layout(name)
@layout_sources[name].layout
end
+42 -9
View File
@@ -101,7 +101,9 @@ module DRC
@engine._context(method) do
box = nil
if args.size == 1
if args.size == 0
# unclip
elsif args.size == 1
box = args[0]
box.is_a?(RBA::DBox) || raise("Method requires a box specification")
elsif args.size == 2
@@ -112,7 +114,7 @@ module DRC
else
raise("Invalid number of arguments (1, 2 or 4 expected)")
end
@box = RBA::Box::from_dbox(box * (1.0 / @layout.dbu))
@box = box && RBA::Box::from_dbox(box * (1.0 / @layout.dbu))
self
@@ -311,24 +313,55 @@ CODE
# %DRC%
# @name extent
# @brief Returns a layer with the bounding box of the selected layout
# @brief Returns a layer with the bounding box of the selected layout or cells
# @synopsis source.extent
# @synopsis source.extent(cell_filter)
#
# Without an argument, the extent method returns a layer with the bounding box
# of the top cell. With a cell filter argument, the method returns a layer
# with the bounding boxes of the selected cells. The cell filter is a glob
# pattern.
#
# The extent function is useful to invert a layer:
#
# @code
# inverse_1 = extent.sized(100.0) - input(1, 0)
# @/code
#
# The following example returns the bounding boxes of all cells whose
# names start with "A":
#
# @code
# a_cells = extent("A*")
# @/code
def extent
def extent(cell_filter = nil)
@engine._context("extent") do
layer = input
if @box
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
else
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
if cell_filter
cell_filter.is_a?(String) || raise("Invalid cell filter argument - must be a string")
end
if cell_filter
tmp = @layout_var.insert_layer(RBA::LayerInfo::new)
@tmp_layers << tmp
@layout_var.cells(cell_filter).each do |cell|
cell.shapes(tmp).insert(cell.bbox)
end
layer = DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, [tmp], @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
else
layer = input
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
if @box
layer.data &= RBA::Region::new(@box)
end
end
layer
end
end
# %DRC%
+9
View File
@@ -1303,3 +1303,12 @@ TEST(51_epInternalAngle)
run_test (_this, "51", false);
}
TEST(52_cellWiseExtent)
{
run_test (_this, "52", false);
}
TEST(53_cellWiseExtentWithClip)
{
run_test (_this, "53", false);
}
+4 -1
View File
@@ -306,6 +306,8 @@ clip(0.mm, 0.mm, 0.5.mm, 0.6.mm)
# shapes now will be taken from the given rectangle and clipped to it
l1 = input(1, 0)
</pre>
</p><p>
To remove the clip condition, call "clip" without any arguments.
</p>
<a name="connect"/><h2>"connect" - Specifies a connection between two layers</h2>
<keyword name="connect"/>
@@ -619,11 +621,12 @@ actual edges from the first input (see <a href="#separation">separation</a> for
<p>
Similar to <a href="#log">log</a>, but the message is printed formatted as an error
</p>
<a name="extent"/><h2>"extent" - Creates a new layer with the bounding box of the default source</h2>
<a name="extent"/><h2>"extent" - Creates a new layer with the bounding box of the default source or cell bounding boxes</h2>
<keyword name="extent"/>
<p>Usage:</p>
<ul>
<li><tt>extent</tt></li>
<li><tt>extent(cell_filter)</tt></li>
</ul>
<p>
See <a href="/about/drc_ref_source.xml#extent">Source#extent</a> for a description of that function.
+14 -1
View File
@@ -96,18 +96,31 @@ Use the global version of "edges" without a source object to address the default
</p><p>
This method has been introduced in version 0.27.
</p>
<a name="extent"/><h2>"extent" - Returns a layer with the bounding box of the selected layout</h2>
<a name="extent"/><h2>"extent" - Returns a layer with the bounding box of the selected layout or cells</h2>
<keyword name="extent"/>
<p>Usage:</p>
<ul>
<li><tt>source.extent</tt></li>
<li><tt>source.extent(cell_filter)</tt></li>
</ul>
<p>
Without an argument, the extent method returns a layer with the bounding box
of the top cell. With a cell filter argument, the method returns a layer
with the bounding boxes of the selected cells. The cell filter is a glob
pattern.
</p><p>
The extent function is useful to invert a layer:
</p><p>
<pre>
inverse_1 = extent.sized(100.0) - input(1, 0)
</pre>
</p><p>
The following example returns the bounding boxes of all cells whose
names start with "A":
</p><p>
<pre>
a_cells = extent("A*")
</pre>
</p>
<a name="global_transform"/><h2>"global_transform" - Gets or sets a global transformation</h2>
<keyword name="global_transform"/>