mirror of https://github.com/KLayout/klayout.git
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:
commit
df022316b9
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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%
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
extent.output(2000)
|
||||
extent("PMOS*").output(2001)
|
||||
extent("NMOS*").output(2002)
|
||||
|
||||
deep
|
||||
|
||||
extent.output(2100)
|
||||
extent("PMOS*").output(2101)
|
||||
extent("NMOS*").output(2102)
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
clip(7.0, -1.0, 15.0, 10.0)
|
||||
|
||||
extent.output(2000)
|
||||
extent("PMOS*").output(2001)
|
||||
extent("NMOS*").output(2002)
|
||||
|
||||
deep
|
||||
|
||||
extent.output(2100)
|
||||
extent("PMOS*").output(2101)
|
||||
extent("NMOS*").output(2102)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -79,6 +79,7 @@ class DBLayout_TestClass < TestBase
|
|||
assert_equal( ly.cell_name(ci), "new_cell" )
|
||||
|
||||
assert_equal( ly.cell_by_name("new_cell"), ci )
|
||||
assert_equal( ly.cells("A*"), [] )
|
||||
assert_equal( ly.cell("new_cell").name, "new_cell" )
|
||||
assert_equal( ly.cell("x").inspect, "nil" )
|
||||
|
||||
|
|
@ -1175,6 +1176,23 @@ class DBLayout_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# Layout#cells
|
||||
def test_15
|
||||
|
||||
g = RBA::Layout::new
|
||||
c1 = g.create_cell("B1")
|
||||
c2 = g.create_cell("B2")
|
||||
c0 = g.create_cell("A")
|
||||
c0.insert(RBA::CellInstArray::new(c1.cell_index, RBA::Trans::new))
|
||||
c0.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new))
|
||||
|
||||
assert_equal(g.cells("B*").collect(&:name).join(","), "B1,B2")
|
||||
assert_equal(g.cells("*").collect(&:name).join(","), "A,B1,B2")
|
||||
assert_equal(g.cells("A").collect(&:name).join(","), "A")
|
||||
assert_equal(g.cells("X").collect(&:name).join(","), "")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue