mirror of https://github.com/KLayout/klayout.git
DRC: added collect*, select and each methods.
This commit is contained in:
parent
703a0ee85d
commit
7d31825b11
|
|
@ -220,6 +220,7 @@ HEAD
|
|||
doc += "<doc>\n"
|
||||
|
||||
doc += "<title>#{escape($title)}</title>\n"
|
||||
doc += "<keyword name=\"#{escape($title)}\"/>\n"
|
||||
|
||||
doc += "<topics>\n"
|
||||
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ module DRC
|
|||
def data
|
||||
@data
|
||||
end
|
||||
|
||||
|
||||
# %DRC%
|
||||
# @name insert
|
||||
# @brief Inserts one or many objects into the layer
|
||||
|
|
@ -908,7 +908,7 @@ CODE
|
|||
# @li @b as_dots @/b: with this option, point-like edges will be produced instead of small boxes @/li
|
||||
# @/ul
|
||||
#
|
||||
# The following image shows the effect of this method
|
||||
# The following images show the effect of this method:
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
|
|
@ -1135,6 +1135,136 @@ CODE
|
|||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name select
|
||||
# @brief Selects edges, edge pairs or polygons based on evaluation of a block
|
||||
# @synopsis layer.select { |object| ... }
|
||||
# This method evaluates the block and returns a new container with those objects for which
|
||||
# the block evaluates to true. It is available for edge, polygon and edge pair layers.
|
||||
# The corresponding objects are RBA::DPolygon, RBA::DEdge or RBA::DEdgePair.
|
||||
#
|
||||
# Because this method executes inside the interpreter, it's inherently slow. Tiling does not
|
||||
# apply to this method.
|
||||
#
|
||||
# Here is a (slow) equivalent of the area selection method:
|
||||
#
|
||||
# @code
|
||||
# new_layer = layer.select { |polygon| polygon.area >= 10.0 }
|
||||
# @/code
|
||||
|
||||
def select(&block)
|
||||
new_data = @data.class.new
|
||||
t = RBA::CplxTrans::new(@engine.dbu)
|
||||
@engine.run_timed("\"select\" in: #{@engine.src_line}", @data) do
|
||||
@data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
|
||||
block.call(object.transformed(t)) && new_data.insert(object)
|
||||
end
|
||||
end
|
||||
DRCLayer::new(@engine, new_data)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name each
|
||||
# @brief Iterates over the objects from the layer
|
||||
# @synopsis layer.each { |object| ... }
|
||||
# This method evaluates the block on each object of the layer. Depending on the
|
||||
# layer type, these objects are of RBA::DPolygon, RBA::DEdge or RBA::DEdgePair type.
|
||||
#
|
||||
# Because this method executes inside the interpreter, it's inherently slow. Tiling does not
|
||||
# apply to this method.
|
||||
|
||||
def each(&block)
|
||||
t = RBA::CplxTrans::new(@engine.dbu)
|
||||
@engine.run_timed("\"select\" in: #{@engine.src_line}", @data) do
|
||||
@data.send(@data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
|
||||
block.call(object.transformed(t))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name collect
|
||||
# @brief Transforms a layer
|
||||
# @synopsis layer.collect { |object| ... }
|
||||
# This method evaluates the block for each object in the layer and returns a new layer with the objects
|
||||
# returned from the block. It is available for edge, polygon and edge pair layers.
|
||||
# The corresponding objects are RBA::DPolygon, RBA::DEdge or RBA::DEdgePair.
|
||||
#
|
||||
# If the block evaluates to nil, no object is added to the output layer. If it returns an array, each of
|
||||
# the objects in the array is added.
|
||||
# The returned layer is of the original type and will only accept objects of the respective type. Hence,
|
||||
# for polygon layers, RBA::DPolygon objects need to be returned. For edge layers those need to be RBA::DEdge
|
||||
# and for edge pair layers, they need to be RBA::DEdgePair objects. For convenience, RBA::Polygon, RBA::Edge
|
||||
# and RBA::EdgePair objects are accepted too and are scaled by the database unit to render micrometer-unit
|
||||
# objects. RBA::Region, RBA::Edges and RBA::EdgePair objects are accepted as well and the corresponding
|
||||
# content of that collections is inserted into the output layer.
|
||||
#
|
||||
# Other versions are available that allow translation of objects into other types (\collect_to_polygons,
|
||||
# \collect_to_edges and \collect_to_edge_pairs).
|
||||
#
|
||||
# Because this method executes inside the interpreter, it's inherently slow. Tiling does not
|
||||
# apply to this method.
|
||||
#
|
||||
# Here is a slow equivalent of the rotated method
|
||||
#
|
||||
# @code
|
||||
# # Rotates by 45 degree
|
||||
# t = RBA::DCplxTrans(1.0, 45.0, false, RBA::DVector::new)
|
||||
# new_layer = layer.collect { |polygon| polygon.transformed(t) }
|
||||
# @/code
|
||||
|
||||
# %DRC%
|
||||
# @name collect_to_region
|
||||
# @brief Transforms a layer into polygon objects
|
||||
# @synopsis layer.collect { |object| ... }
|
||||
# This method is similar to \collect, but creates a polygon layer. It expects the block to
|
||||
# deliver objects that can be converted into polygons. Such objects are of class RBA::DPolygon,
|
||||
# RBA::DBox, RBA::DPath, RBA::Polygon, RBA::Path, RBA::Box and RBA::Region.
|
||||
|
||||
# %DRC%
|
||||
# @name collect_to_edges
|
||||
# @brief Transforms a layer into edge objects
|
||||
# @synopsis layer.collect { |object| ... }
|
||||
# This method is similar to \collect, but creates an edge layer. It expects the block to
|
||||
# deliver objects that can be converted into edges. If polygon-like objects are returned, their
|
||||
# contours will be turned into edge sequences.
|
||||
|
||||
# %DRC%
|
||||
# @name collect_to_edge_pairs
|
||||
# @brief Transforms a layer into edge pair objects
|
||||
# @synopsis layer.collect { |object| ... }
|
||||
# This method is similar to \collect, but creates an edge pair layer. It expects the block to
|
||||
# deliver RBA::EdgePair, RBA::DEdgePair or RBA::EdgePairs objects.
|
||||
|
||||
%w(collect collect_to_region collect_to_edges collect_to_edge_pairs).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(&block)
|
||||
|
||||
if :#{f} == :collect
|
||||
new_data = @data.class.new
|
||||
elsif :#{f} == :collect_to_region
|
||||
new_data = RBA::Region.new
|
||||
elsif :#{f} == :collect_to_edges
|
||||
new_data = RBA::Edges.new
|
||||
elsif :#{f} == :collect_to_edge_pairs
|
||||
new_data = RBA::EdgePairs.new
|
||||
end
|
||||
|
||||
t = RBA::CplxTrans::new(@engine.dbu)
|
||||
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
|
||||
|
||||
@engine.run_timed("\\"select\\" in: " + @engine.src_line, @data) do
|
||||
@data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
|
||||
insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans)
|
||||
end
|
||||
end
|
||||
|
||||
DRCLayer::new(@engine, new_data)
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name odd_polygons
|
||||
|
|
@ -3008,6 +3138,30 @@ CODE
|
|||
|
||||
private
|
||||
|
||||
def insert_object_into(container, object, dbu_trans)
|
||||
if object.is_a?(Array)
|
||||
object.each { |o| insert_object_into(container, o, dbu_trans) }
|
||||
elsif container.is_a?(RBA::Region)
|
||||
if object.is_a?(RBA::Region) || object.is_a?(RBA::Polygon) || object.is_a?(RBA::SimplePolygon) || object.is_a?(RBA::Box) || object.is_a?(RBA::Path)
|
||||
container.insert(object)
|
||||
elsif object.is_a?(RBA::DPolygon) || object.is_a?(RBA::DSimplePolygon) || object.is_a?(RBA::DBox) || object.is_a?(RBA::DPath)
|
||||
container.insert(object.transformed(dbu_trans))
|
||||
end
|
||||
elsif container.is_a?(RBA::Edges)
|
||||
if object.is_a?(RBA::Region) || object.is_a?(RBA::Edges) || object.is_a?(RBA::Edge) || object.is_a?(RBA::Polygon) || object.is_a?(RBA::SimplePolygon) || object.is_a?(RBA::Box) || object.is_a?(RBA::Path)
|
||||
container.insert(object)
|
||||
elsif object.is_a?(RBA::DPolygon) || object.is_a?(RBA::DSimplePolygon) || object.is_a?(RBA::DBox) || object.is_a?(RBA::DPath) || object.is_a?(RBA::DEdge)
|
||||
container.insert(object.transformed(dbu_trans))
|
||||
end
|
||||
elsif container.is_a?(RBA::EdgePairs)
|
||||
if object.is_a?(RBA::EdgePairs) || object.is_a?(RBA::EdgePair)
|
||||
container.insert(object)
|
||||
elsif object.is_a?(RBA::DEdgePair)
|
||||
container.insert(object.transformed(dbu_trans))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def prep_value(a)
|
||||
if a.is_a?(RBA::DPoint)
|
||||
RBA::Point::from_dpoint(a * (1.0 / @engine.dbu.to_f))
|
||||
|
|
@ -4252,6 +4406,7 @@ CODE
|
|||
|
||||
t = RBA::Timer::new
|
||||
t.start
|
||||
GC.start # force a garbage collection before the operation to free unused memory
|
||||
res = yield
|
||||
t.stop
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
<doc>
|
||||
<title>DRC Reference</title>
|
||||
<keyword name="DRC Reference"/>
|
||||
<topics>
|
||||
<topic href="/about/drc_ref_layer.xml"/>
|
||||
<topic href="/about/drc_ref_source.xml"/>
|
||||
|
|
|
|||
|
|
@ -148,6 +148,74 @@ Clean state is the default.
|
|||
See <a href="#raw">raw</a> for some remarks about how this state is
|
||||
propagated.
|
||||
</p>
|
||||
<h2>"collect" - Transforms a layer</h2>
|
||||
<keyword name="collect"/>
|
||||
<a name="collect"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.collect { |object| ... }</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method evaluates the block for each object in the layer and returns a new layer with the objects
|
||||
returned from the block. It is available for edge, polygon and edge pair layers.
|
||||
The corresponding objects are <class_doc href="DPolygon">DPolygon</class_doc>, <class_doc href="DEdge">DEdge</class_doc> or <class_doc href="DEdgePair">DEdgePair</class_doc>.
|
||||
</p><p>
|
||||
If the block evaluates to nil, no object is added to the output layer. If it returns an array, each of
|
||||
the objects in the array is added.
|
||||
The returned layer is of the original type and will only accept objects of the respective type. Hence,
|
||||
for polygon layers, <class_doc href="DPolygon">DPolygon</class_doc> objects need to be returned. For edge layers those need to be <class_doc href="DEdge">DEdge</class_doc>
|
||||
and for edge pair layers, they need to be <class_doc href="DEdgePair">DEdgePair</class_doc> objects. For convenience, <class_doc href="Polygon">Polygon</class_doc>, <class_doc href="Edge">Edge</class_doc>
|
||||
and <class_doc href="EdgePair">EdgePair</class_doc> objects are accepted too and are scaled by the database unit to render micrometer-unit
|
||||
objects. <class_doc href="Region">Region</class_doc>, <class_doc href="Edges">Edges</class_doc> and <class_doc href="EdgePair">EdgePair</class_doc> objects are accepted as well and the corresponding
|
||||
content of that collections is inserted into the output layer.
|
||||
</p><p>
|
||||
Other versions are available that allow translation of objects into other types (<a href="#collect_to_polygons">collect_to_polygons</a>,
|
||||
<a href="#collect_to_edges">collect_to_edges</a> and <a href="#collect_to_edge_pairs">collect_to_edge_pairs</a>).
|
||||
</p><p>
|
||||
Because this method executes inside the interpreter, it's inherently slow. Tiling does not
|
||||
apply to this method.
|
||||
</p><p>
|
||||
Here is a slow equivalent of the rotated method
|
||||
</p><p>
|
||||
<pre>
|
||||
# Rotates by 45 degree
|
||||
t = <class_doc href="DCplxTrans">DCplxTrans</class_doc>(1.0, 45.0, false, <class_doc href="DVector">DVector</class_doc>::new)
|
||||
new_layer = layer.collect do |polygon|
|
||||
polygon.transformed(t)
|
||||
end
|
||||
</pre>
|
||||
</p>
|
||||
<h2>"collect_to_edge_pairs" - Transforms a layer into edge pair objects</h2>
|
||||
<keyword name="collect_to_edge_pairs"/>
|
||||
<a name="collect_to_edge_pairs"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.collect { |object| ... }</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method is similar to <a href="#collect">collect</a>, but creates an edge pair layer. It expects the block to
|
||||
deliver <class_doc href="EdgePair">EdgePair</class_doc>, <class_doc href="DEdgePair">DEdgePair</class_doc> or <class_doc href="EdgePairs">EdgePairs</class_doc> objects.
|
||||
</p>
|
||||
<h2>"collect_to_edges" - Transforms a layer into edge objects</h2>
|
||||
<keyword name="collect_to_edges"/>
|
||||
<a name="collect_to_edges"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.collect { |object| ... }</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method is similar to <a href="#collect">collect</a>, but creates an edge layer. It expects the block to
|
||||
deliver objects that can be converted into edges. If polygon-like objects are returned, their
|
||||
contours will be turned into edge sequences.
|
||||
</p>
|
||||
<h2>"collect_to_region" - Transforms a layer into polygon objects</h2>
|
||||
<keyword name="collect_to_region"/>
|
||||
<a name="collect_to_region"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.collect { |object| ... }</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method is similar to <a href="#collect">collect</a>, but creates a polygon layer. It expects the block to
|
||||
deliver objects that can be converted into polygons. Such objects are of class <class_doc href="DPolygon">DPolygon</class_doc>,
|
||||
<class_doc href="DBox">DBox</class_doc>, <class_doc href="DPath">DPath</class_doc>, <class_doc href="Polygon">Polygon</class_doc>, <class_doc href="Path">Path</class_doc>, <class_doc href="Box">Box</class_doc> and <class_doc href="Region">Region</class_doc>.
|
||||
</p>
|
||||
<h2>"corners" - Selects corners of polygons</h2>
|
||||
<keyword name="corners"/>
|
||||
<a name="corners"/><p>Usage:</p>
|
||||
|
|
@ -177,6 +245,7 @@ The following image shows the effect of this method
|
|||
<tr>
|
||||
<td><img src="/images/drc_corners1.png"/></td>
|
||||
<td><img src="/images/drc_corners2.png"/></td>
|
||||
<td><img src="/images/drc_corners3.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
|
@ -209,6 +278,19 @@ layer. Using the dup method will avoid that.
|
|||
However, dup will double the memory required to hold the data
|
||||
and performing the deep copy may be expensive in terms of CPU time.
|
||||
</p>
|
||||
<h2>"each" - Iterates over the objects from the layer</h2>
|
||||
<keyword name="each"/>
|
||||
<a name="each"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.each { |object| ... }</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method evaluates the block on each object of the layer. Depending on the
|
||||
layer type, these objects are of <class_doc href="DPolygon">DPolygon</class_doc>, <class_doc href="DEdge">DEdge</class_doc> or <class_doc href="DEdgePair">DEdgePair</class_doc> type.
|
||||
</p><p>
|
||||
Because this method executes inside the interpreter, it's inherently slow. Tiling does not
|
||||
apply to this method.
|
||||
</p>
|
||||
<h2>"edge_pairs?" - Returns true, if the layer is an edge pair collection</h2>
|
||||
<keyword name="edge_pairs?"/>
|
||||
<a name="edge_pairs?"/><p>Usage:</p>
|
||||
|
|
@ -1419,6 +1501,28 @@ The following images shows the effect of the "scaled" method:
|
|||
Applies to edge pair collections only.
|
||||
Returns the second edges of the edge pairs in the collection.
|
||||
</p>
|
||||
<h2>"select" - Selects edges, edge pairs or polygons based on evaluation of a block</h2>
|
||||
<keyword name="select"/>
|
||||
<a name="select"/><p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select { |object| ... }</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method evaluates the block and returns a new container with those objects for which
|
||||
the block evaluates to true. It is available for edge, polygon and edge pair layers.
|
||||
The corresponding objects are <class_doc href="DPolygon">DPolygon</class_doc>, <class_doc href="DEdge">DEdge</class_doc> or <class_doc href="DEdgePair">DEdgePair</class_doc>.
|
||||
</p><p>
|
||||
Because this method executes inside the interpreter, it's inherently slow. Tiling does not
|
||||
apply to this method.
|
||||
</p><p>
|
||||
Here is a (slow) equivalent of the area selection method:
|
||||
</p><p>
|
||||
<pre>
|
||||
new_layer = layer.select do |polygon|
|
||||
polygon.area >= 10.0
|
||||
end
|
||||
</pre>
|
||||
</p>
|
||||
<h2>"select_inside" - Selects shapes or regions of self which are inside the other region</h2>
|
||||
<keyword name="select_inside"/>
|
||||
<a name="select_inside"/><p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -546,6 +546,37 @@ a1.corners.sized(0.05).output(1060, 0)
|
|||
a1.corners(-90.0, as_boxes).sized(0.05).output(1061, 0)
|
||||
a1.corners(-90.0, as_dots).extended(0.05, 0.05, 0.05, 0.05).output(1062, 0)
|
||||
|
||||
a1.select { |p| p.bbox.width < 0.8 }.output(1100, 0)
|
||||
a1.collect { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1101, 0)
|
||||
a1.collect_to_region { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1102, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1103, 0)
|
||||
a1.collect { |p| p.is_box? && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) }.output(1104, 0)
|
||||
a1.collect { |p| p.is_box? && [ p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(150, 150), p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) ] }.output(1105, 0)
|
||||
lx = polygon_layer
|
||||
a1.each { |p| p.is_box? && lx.insert(p) }
|
||||
lx.output(1106, 0)
|
||||
a1.collect { |p| p.is_box? && RBA::Region::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))).sized(120) }.output(1107, 0)
|
||||
a1.collect { |p| p.is_box? && RBA::Polygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1108, 0)
|
||||
a1.collect { |p| p.is_box? && RBA::DPolygon::new(p.bbox) }.output(1109, 0)
|
||||
a1.collect { |p| p.is_box? && RBA::SimplePolygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1110, 0)
|
||||
a1.collect { |p| p.is_box? && RBA::DSimplePolygon::new(p.bbox) }.output(1111, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) }.output(1112, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && [ p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(150, 150), p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(120, 120) ] }.output(1113, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && RBA::Region::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))).sized(120) }.output(1114, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && RBA::Polygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1115, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && RBA::DPolygon::new(p.bbox) }.output(1116, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && RBA::SimplePolygon::new(p.bbox.transformed(RBA::VCplxTrans::new(1000.0))) }.output(1117, 0)
|
||||
a1.collect_to_edges { |p| p.is_box? && RBA::DSimplePolygon::new(p.bbox) }.output(1118, 0)
|
||||
|
||||
a1.edges.select { |p| p.length < 0.8 }.output(1120, 0)
|
||||
a1.edges.collect { |p| p.length < 0.8 && p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1121, 0)
|
||||
a1.edges.collect_to_region { |p| p.length < 0.8 && p.bbox.enlarged(0.1, 0.1) }.output(1122, 0)
|
||||
a1.edges.collect_to_region { |p| p.length < 0.8 && p.bbox.transformed(RBA::VCplxTrans::new(1000.0)).enlarged(100, 100) }.output(1123, 0)
|
||||
|
||||
# edge pair collect
|
||||
a1.width(1.5).collect { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1120, 0)
|
||||
a1.width(1.5).collect_to_edge_pairs { |p| p.transformed(RBA::VCplxTrans::new(1000.0)) }.output(1121, 0)
|
||||
|
||||
puts "=== Single-cell testsuite ==="
|
||||
|
||||
run_testsuite(0, 1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue