WIP: More documentation for complex DRC ops

This commit is contained in:
Matthias Koefferlein 2021-01-06 01:27:02 +01:00
parent 7d4310d343
commit 37d62f97e1
3 changed files with 676 additions and 44 deletions

View File

@ -55,6 +55,7 @@ class DRCOpNode
end
def _build_geo_bool_node(other, op)
other = @engine._make_node(other)
if ! other.is_a?(DRCOpNode)
raise("Second argument to #{op.to_s} must be a DRC expression")
end
@ -70,7 +71,7 @@ class DRCOpNode
# %DRC%
# @name &
# @brief Boolean AND between the results of two expressions
# @synopsis expr & expr
# @synopsis expression & expression
#
# The & operator will compute the boolean AND between the results
# of two expressions. The expression types need to be edge or polygon.
@ -85,7 +86,7 @@ class DRCOpNode
# %DRC%
# @name |
# @brief Boolean OR between the results of two expressions
# @synopsis expr | expr
# @synopsis expression | expression
#
# The | operator will compute the boolean OR between the results of
# two expressions. '+' is basically a synonym. Both expressions
@ -94,14 +95,14 @@ class DRCOpNode
# %DRC%
# @name +
# @brief Boolean OR between the results of two expressions
# @synopsis expr + expr
# @synopsis expression + expression
#
# The + operator will join the results of two expressions.
# %DRC%
# @name -
# @brief Boolean NOT between the results of two expressions
# @synopsis expr - expr
# @synopsis expression - expression
#
# The - operator will compute the difference between the results
# of two expressions. The NOT operation is defined for polygons,
@ -119,7 +120,7 @@ class DRCOpNode
# %DRC%
# @name ^
# @brief Boolean XOR between the results of two expressions
# @synopsis expr - expr
# @synopsis expression - expression
#
# The ^ operator will compute the XOR (symmetric difference) between the results
# of two expressions. The XOR operation is defined for polygons and edges.
@ -138,7 +139,7 @@ CODE
# %DRC%
# @name !
# @brief Logical not
# @synopsis ! expr
# @synopsis ! expression
#
# This operator will evaluate the expression after. If this expression renders
# an empty result, the operator will return the primary shape. Otherwise it will
@ -168,7 +169,7 @@ CODE
# %DRC%
# @name area
# @brief Selects the primary shape if the area is meeting the condition
# @synopsis area (in condition)
# @synopsis expression.area (in condition)
#
# This operation is used in conditions to select shapes based on their area.
# It is applicable on polygon expressions. The result will be the input
@ -182,6 +183,9 @@ CODE
# out = in.drc(area < 2.0)
# out = in.drc(primary.area < 2.0) # equivalent
# @/code
#
# The area method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.area".
def area
DRCOpNodeAreaFilter::new(@engine, self)
@ -190,7 +194,7 @@ CODE
# %DRC%
# @name count
# @brief Selects a expression result based on the number of (local) shapes
# @synopsis count (in condition)
# @synopsis expression.count (in condition)
#
# This operation is used in conditions to select expression results based on their
# count. "count" is used as a method on a expression. It will evaluate the expression locally
@ -219,7 +223,7 @@ CODE
# %DRC%
# @name perimeter
# @brief Selects the primary shape if the perimeter is meeting the condition
# @synopsis perimeter (in condition)
# @synopsis expression.perimeter (in condition)
#
# This operation is used in conditions to select shapes based on their perimeter.
# It is applicable on polygon expressions. The result will be the input
@ -233,6 +237,9 @@ CODE
# out = in.drc(perimeter < 10.0)
# out = in.drc(primary.perimeter < 10.0) # equivalent
# @/code
#
# The perimeter method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.perimeter".
def perimeter
DRCOpNodePerimeterFilter::new(@engine, self)
@ -241,7 +248,7 @@ CODE
# %DRC%
# @name bbox_min
# @brief Selects the primary shape if its bounding box smaller dimension is meeting the condition
# @synopsis bbox_min (in condition)
# @synopsis expression.bbox_min (in condition)
#
# This operation is used in conditions to select shapes based on smaller dimension of their bounding boxes.
# It is applicable on polygon expressions. The result will be the input
@ -256,6 +263,9 @@ CODE
# out = in.drc(bbox_min > 200.nm)
# out = in.drc(primary.bbox_min > 200.nm) # equivalent
# @/code
#
# The "bbox_min" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.bbox_min".
def bbox_min
DRCOpNodeBBoxParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::BoxMinDim, self)
@ -264,10 +274,13 @@ CODE
# %DRC%
# @name bbox_max
# @brief Selects the primary shape if its bounding box larger dimension is meeting the condition
# @synopsis bbox_max (in condition)
# @synopsis expression.bbox_max (in condition)
#
# This operation acts similar to \DRC#bbox_min, but takes the larger dimension of the shape's
# bounding box.
#
# The "bbox_max" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.bbox_max".
def bbox_max
DRCOpNodeBBoxParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::BoxMaxDim, self)
@ -276,13 +289,16 @@ CODE
# %DRC%
# @name bbox_width
# @brief Selects the primary shape if its bounding box width is meeting the condition
# @synopsis bbox_width (in condition)
# @synopsis expression.bbox_width (in condition)
#
# This operation acts similar to \DRC#bbox_min, but takes the width of the shape's
# bounding box. In general, it's more advisable to use \DRC#bbox_min or \DRC#bbox_max
# because bbox_width implies a certain orientation. This can imply variant formation in
# hierarchical contexts: cells rotated by 90 degree have to be treated differently from
# ones not rotated. This usually results in a larger computation effort and larger result files.
#
# The "bbox_width" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.bbox_width".
def bbox_width
DRCOpNodeBBoxParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::BoxWidth, self)
@ -291,13 +307,16 @@ CODE
# %DRC%
# @name bbox_height
# @brief Selects the primary shape if its bounding box height is meeting the condition
# @synopsis bbox_height (in condition)
# @synopsis expression.bbox_height (in condition)
#
# This operation acts similar to \DRC#bbox_min, but takes the height of the shape's
# bounding box. In general, it's more advisable to use \DRC#bbox_min or \DRC#bbox_max
# because bbox_height implies a certain orientation. This can imply variant formation in
# hierarchical contexts: cells rotated by 90 degree have to be treated differently from
# ones not rotated. This usually results in a larger computation effort and larger result files.
#
# The "bbox_height" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.bbox_height".
def bbox_height
DRCOpNodeBBoxParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::BoxHeight, self)
@ -306,7 +325,7 @@ CODE
# %DRC%
# @name length
# @brief Selects edges based on their length
# @synopsis length (in condition)
# @synopsis expression.length (in condition)
#
# This operation will select those edges which are meeting the length
# criterion. Non-edge shapes (polygons, edge pairs) will be converted to edges before.
@ -318,6 +337,9 @@ CODE
# out = in.drc(length >= 1.um)
# out = in.drc(primary.length >= 1.um) # equivalent
# @/code
#
# The "length" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.length".
def length
DRCOpNodeEdgeLengthFilter::new(@engine, self)
@ -326,7 +348,7 @@ CODE
# %DRC%
# @name angle
# @brief Selects edges based on their angle
# @synopsis angle (in condition)
# @synopsis expression.angle (in condition)
#
# This operation selects edges by their angle, measured against the horizontal
# axis in the mathematical sense.
@ -350,6 +372,9 @@ CODE
# are placed unrotated and rotated by 90 degree cannot be considered identical. This imposes
# a performance penalty in hierarchical mode. If possible, consider using \DRC#rectilinear for
# example to detect shapes with non-manhattan geometry instead of using angle checks.
#
# The "angle" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.angle".
def angle
DRCOpNodeEdgeOrientationFilter::new(@engine, self)
@ -358,10 +383,13 @@ CODE
# %DRC%
# @name rounded_corners
# @brief Applies corner rounding
# @synopsis rounded_corners(inner, outer, n)
# @synopsis expression.rounded_corners(inner, outer, n)
#
# This operation acts on polygons and applies corner rounding the the given inner
# and outer corner radius and the number of points n per full circle.
# and outer corner radius and the number of points n per full circle. See \Layer#rounded_corners for more details.
#
# The "rounded_corners" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.rounded_corners".
def rounded_corners(inner, outer, n)
@engine._context("rounded_corners") do
@ -373,9 +401,12 @@ CODE
# %DRC%
# @name smoothed
# @brief Applies smoothing
# @synopsis smoothed(d)
# @synopsis expression.smoothed(d)
#
# This operation acts on polygons and applies polygon smoothing with the tolerance d.
# This operation acts on polygons and applies polygon smoothing with the tolerance d. See \Layer#smoothed for more details.
#
# The "smoothed" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.smoothed".
def smoothed(d)
@engine._context("smoothed") do
@ -386,9 +417,9 @@ CODE
# %DRC%
# @name corners (in condition)
# @brief Applies smoothing
# @synopsis corners
# @synopsis corners(as_dots)
# @synopsis corners(as_boxes)
# @synopsis expression.corners
# @synopsis expression.corners(as_dots)
# @synopsis expression.corners(as_boxes)
#
# This operation acts on polygons and selects the corners of the polygons.
# It can be put into a condition to select corners by their angles. The angle of
@ -412,6 +443,9 @@ CODE
# out = in.drc(corners < 0)
# out = in.drc(primary.corners < 0) # equivalent
# @/code
#
# The "corners" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.corners".
def corners(as_dots = DRCAsDots::new(false))
@engine._context("corners") do
@ -427,7 +461,7 @@ CODE
# %DRC%
# @name middle
# @brief Returns the centers of polygon bounding boxes
# @synopsis middle([ options ])
# @synopsis expression.middle([ options ])
#
# The middle operation acts on polygons and has the same effect than \Layer#middle.
# It takes the same arguments. It is available as a method on \DRC expressions or
@ -436,7 +470,7 @@ CODE
# %DRC%
# @name extent_refs
# @brief Returns partial references to the boundings boxes of the polygons
# @synopsis extent_refs([ options ])
# @synopsis expression.extent_refs([ options ])
#
# The extent_refs operation acts on polygons and has the same effect than \Layer#extent_refs.
# It takes the same arguments. It is available as a method on \DRC expressions or
@ -518,7 +552,7 @@ CODE
# %DRC%
# @name odd_polygons
# @brief Selects all polygons which are non-orientable
# @synopsis odd_polygons
# @synopsis expression.odd_polygons
#
# Non-orientable polygons are for example "8"-shape polygons. Such polygons are
# usually considered harmful as their definition of covered area is depending on the
@ -534,7 +568,7 @@ CODE
# %DRC%
# @name rectangles
# @brief Selects all polygons which are rectangles
# @synopsis rectangles
# @synopsis expression.rectangles
#
# This operation can be used as a plain function in which case it acts on primary
# shapes or can be used as method on another DRC expression.
@ -552,7 +586,7 @@ CODE
# %DRC%
# @name rectilinear
# @brief Selects all polygons which are rectilinear
# @synopsis rectilinear
# @synopsis expression.rectilinear
#
# Rectilinear polygons only have vertical and horizontal edges. Such polygons are also
# called manhattan polygons.
@ -573,7 +607,7 @@ CODE
# %DRC%
# @name holes
# @brief Selects all holes from the input polygons
# @synopsis holes
# @synopsis expression.holes
#
# This operation can be used as a plain function in which case it acts on primary
# shapes or can be used as method on another DRC expression.
@ -591,7 +625,7 @@ CODE
# %DRC%
# @name hulls
# @brief Selects all hulls from the input polygons
# @synopsis hulls
# @synopsis expression.hulls
#
# The hulls are the outer contours of the input polygons. By selecting hulls only,
# all holes will be closed.
@ -612,7 +646,7 @@ CODE
# %DRC%
# @name edges
# @brief Converts the input shapes into edges
# @synopsis edges
# @synopsis expression.edges
#
# Polygons will be separated into edges forming their contours. Edge pairs will be
# decomposed into individual edges.
@ -633,8 +667,8 @@ CODE
# %DRC%
# @name merged
# @brief Returns the merged input polygons, optionally selecting multi-overlap
# @synopsis merged
# @synopsis merged(min_count)
# @synopsis expression.merged
# @synopsis expression.merged(min_count)
#
# This operation will act on polygons. Without a min_count argument, the merged
# polygons will be returned.
@ -642,6 +676,9 @@ CODE
# With a min_count argument, the result will include only those parts where more
# than the given number of polygons overlap. As the primary input is merged already,
# it will always contribute as one.
#
# The "merged" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.merged".
def merged(*args)
@ -664,7 +701,17 @@ CODE
end
# ....
# %DRC%
# @name sized
# @brief Returns the sized version of the input
# @synopsis expression.sized(d [, mode])
# @synopsis expression.sized(dx, dy [, mode]))
#
# This method provides the same functionality as \Layer#sized and takes the same
# arguments. It acts on polygon expressions.
#
# The "sized" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.sized".
def sized(*args)
@ -701,12 +748,40 @@ CODE
end
# %DRC%
# @name extents
# @brief Returns the bounding box of each input object
# @synopsis expression.extents([ enlargement ])
#
# This method provides the same functionality as \Layer#extents and takes the same
# arguments. It returns the bounding boxes of the input objects. It acts on edge
# edge pair and polygon expressions.
#
# The "extents" method is available as a plain function or as a method on \DRC expressions.
# The plain function is equivalent to "primary.extents".
def extents(e = 0)
@engine._context("extents") do
DRCOpNodeFilter::new(@engine, self, :new_extents, "extents", @engine._make_value(e))
end
end
# %DRC%
# @name first_edges
# @brief Returns the first edges of edge pairs
# @synopsis expression.extents([ enlargement ])
#
# This method acts on edge pair expressions and returns the first edges of the
# edge pairs delivered by the expression.
# %DRC%
# @name second_edges
# @brief Returns the second edges of edge pairs
# @synopsis expression.extents([ enlargement ])
#
# This method acts on edge pair expressions and returns the second edges of the
# edge pairs delivered by the expression.
def first_edges
DRCOpNodeFilter::new(@engine, self, :new_edge_pair_to_first_edges, "first_edges")
end
@ -715,6 +790,33 @@ CODE
DRCOpNodeFilter::new(@engine, self, :new_edge_pair_to_second_edges, "second_edges")
end
# %DRC%
# @name end_segments
# @brief Returns the part at the end of each edge of the input
# @synopsis expression.end_segments(length)
# @synopsis expression.end_segments(length, fraction)
#
# This method acts on edge expressions and delivers a specific part of each edge.
# See \layer#end_segments for details about this functionality.
# %DRC%
# @name start_segments
# @brief Returns the part at the beginning of each edge of the input
# @synopsis expression.start_segments(length)
# @synopsis expression.start_segments(length, fraction)
#
# This method acts on edge expressions and delivers a specific part of each edge.
# See \layer#start_segments for details about this functionality.
# %DRC%
# @name centers
# @brief Returns the part at the center of each edge of the input
# @synopsis expression.centers(length)
# @synopsis expression.end_segments(length, fraction)
#
# This method acts on edge expressions and delivers a specific part of each edge.
# See \layer#centers for details about this functionality.
def end_segments(length, fraction = 0.0)
@engine._context("end_segments") do
@engine._check_numeric(fraction)
@ -735,6 +837,18 @@ CODE
DRCOpNodeFilter::new(@engine, self, :new_centers, "centers", @engine._make_value(length), fraction)
end
end
# %DRC%
# @name extended
# @brief Returns polygons describing an area along the edges of the input
# @synopsis expression.extended([:begin => b,] [:end => e,] [:out => o,] [:in => i], [:joined => true])
# @synopsis expression.extended(b, e, o, i)
#
# This method acts on edge expressions.
# It will create a polygon for each edge
# tracing the edge with certain offsets to the edge. "o" is the offset applied to the
# outer side of the edge, "i" is the offset applied to the inner side of the edge.
# "b" is the offset applied at the beginning and "e" is the offset applied at the end.
def extended(*args)
@ -761,6 +875,30 @@ CODE
end
# %DRC%
# @name extended_in
# @brief Returns polygons describing an area along the edges of the input
# @synopsis expression.extended_in(d)
#
# This method acts on edge expressions. Polygons are generated for
# each edge describing the edge drawn with a certain width extending into
# the "inside" (the right side when looking from start to end).
# This method is basically equivalent to the \extended method:
# "extended(0, 0, 0, dist)".
# A version extending to the outside is \extended_out.
# %DRC%
# @name extended_out
# @brief Returns polygons describing an area along the edges of the input
# @synopsis expression.extended_out(d)
#
# This method acts on edge expressions. Polygons are generated for
# each edge describing the edge drawn with a certain width extending into
# the "outside" (the left side when looking from start to end).
# This method is basically equivalent to the \extended method:
# "extended(0, 0, dist, 0)".
# A version extending to the inside is \extended_in.
def extended_in(e)
@engine._context("extended_in") do
DRCOpNodeFilter::new(@engine, self, :new_extended_in, "extended_in", self._make_value(e))
@ -773,9 +911,30 @@ CODE
end
end
def polygons
# %DRC%
# @name polygons
# @brief Converts the input shapes into polygons
# @synopsis expression.polygons([ enlargement ])
#
# Generates polygons from the input shapes. Polygons stay polygons. Edges and edge pairs
# are converted to polygons. For this, the enlargement parameter will specify the
# edge thickness or augmentation applied to edge pairs. With the default enlargement
# of zero edges will not be converted to valid polygons and degenerated edge pairs
# will not become valid polygons as well.
#
# Contrary most other operations, "polygons" does not have a plain function equivalent
# as this is reserved for the function generating a polygon layer.
#
# This method is useful for generating polygons from DRC violation markers as shown in
# the following example:
#
# @code
# out = in.drc((width < 0.5.um).polygons)
# @/code
def polygons(e = 0)
@engine._context("polygons") do
DRCOpNodeFilter::new(@engine, self, :new_polygons, "polygons")
DRCOpNodeFilter::new(@engine, self, :new_polygons, "polygons", self._make_value(e))
end
end

View File

@ -6,14 +6,73 @@ module DRC
# %DRC%
# @name drc
# @brief Universal DRC function
# @synopsis drc(...)
# @brief Provides a generic DRC function for use with \DRC expressions
# @synopsis layer.drc(expression)
#
# TODO: add doc
# This method implement the universal DRC which offers enhanced abilities,
# improved performance in some applications and better readability.
#
# The key concept for this method are DRC expressions. DRC expressions
# are formed by using predefined keywords like "width", operators like "&"
# and method to build an abstract definition of the operations to perform
# within the DRC.
#
# When the DRC function is executed, it will basically visit all shapes
# from the input layer (the one, the "drc" method is called on), collect
# the neighbor shapes from all involved other inputs and run the requested
# operations on each cluster. Currently, "drc" is only available for polygon
# layers.
#
# The nature of the "drc" operation is that of the loop over all (merged) input
# polygons. Within the operation executed on each shape, it's possible to make
# decisions such as "if the shape has an area larger than something, apply this
# operation" etc. This can be achieved with conventional DRC functions too,
# but involves potentially complex and heavy operations such as booleans, interact
# etc. For this reason, the "drc" function may provide a performance benefit.
#
# In addition, within the loop, a single shape from the input layer is presented to
# execution engine which runs the operations.
# This allows using operations such as "size" without having to consider
# neigbor polygons growing into the area of the initial shape. In this sense,
# the "drc" function allows seeing the layer as individual polygons rather than
# a global "sea of polygons". This enables new applications which are otherwise
# difficult to implement.
#
# An important concept in the context of "drc" expressions is the "primary".
# This expression represents a single primary shape. "Secondaries" are shapes
# from other inputs. Primary shapes guide the operation - secondaries without
# primaries are not seen. The "drc" operation will look for secondaries within
# a certain distance which is determined from the operations within the
# expression to execute. The secondaries collected in this step will not be
# merged, so the secondary polygons may be partial. This is important when
# using measurement operations like "area" on secondary polygons.
#
# Here is an example for a generic DRC operation which performs a width
# check for less than 0.5.um on the primary shapes.
#
# @code
# out = in.drc(width < 0.5.um)
# @/code
#
# Another example computes a boolean AND between two layers before selecting
# the ones with an area larger than 1 square micrometer:
#
# @code
# other = ... another layer ..
# out = in.drc((primary & other).area > 1.0)
# @/code
#
# The last example shows how the "drc" operation can improve performance: as the
# boolean operation is computed locally and the result is discarded when no longer required,
# less shapes need to be stored hence reducing the memory overhead and CPU time required
# to manage these shapes.
#
# For more details about the expression see the \DRC class documentation.
def drc(op)
@engine._context("drc") do
requires_region
expr.is_a?(DRCOpNode) || raise("A DRC expression is required for the argument (got #{expr.inspect})")
return DRCLayer::new(@engine, self.data.complex_op(op.create_node({})))
end
end
@ -52,6 +111,8 @@ module DRC
anum = 1
args = args.collect { |a| self._make_node(a) }
types = []
args.each do |a|
if !a.is_a?(DRCOpNode)
@ -116,6 +177,33 @@ module DRC
return res
end
# %DRC%
# @name foreign
# @brief Represents all other polygons from primary except the current one
# @synopsis foreign
#
# The primary input of the universal DRC function is the layer the \drc function
# is called on. This operation represents all "other" primary polygons while
# \primary represents the current polygon.
#
# This feature opens new options for processing layouts beyond the
# abilities of the classical DRC concept. For classic DRC, intra-layer interactions
# are always symmetric: a polygon cannot be considered separated from it's neighbors
# on the same layer.
#
# The following example computes every part of the input which is closer than
# 0.5 micrometers to other (disconnected) polygons on the same layer:
#
# @code
# out = in.drc(primary & foreign.sized(0.5.um))
# @/code
def primary
res = DRCOpNode::new(self, RBA::CompoundRegionOperationNode::new_primary)
res.description = "primary"
return res
end
# %DRC%
# @name if_all
# @brief Evaluates to the primary shape when all condition expression results are non-empty
@ -160,6 +248,8 @@ module DRC
self._context("#{f}") do
args = args.collect { |a| self._make_node(a) }
args.each_with_index do |a,ia|
if ! a.is_a?(DRCOpNode)
raise("Argument #" + (ia + 1).to_s + " to #{f} must be a DRC expression")
@ -223,6 +313,83 @@ CODE
CODE
end
# %DRC%
# @name area
# @brief Selects the primary shape if the area is meeting the condition
# @synopsis area (in condition)
# @synopsis area(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.area" (see \Layer#area). Without a layer
# argument, "area" represents an area filter for primary shapes in
# \DRC expressions (see \drc and \DRC#area for more details).
# %DRC%
# @name hulls
# @brief Selects all hulls from the input polygons
# @synopsis hulls
# @synopsis hulls(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.hulls" (see \Layer#hulls). Without a layer
# argument, "hulls" represents a hull contour extractor for primary shapes in
# \DRC expressions (see \drc and \DRC#hulls for more details).
# %DRC%
# @name holes
# @brief Selects all holes from the input polygons
# @synopsis holes
# @synopsis holes(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.holes" (see \Layer#hulls). Without a layer
# argument, "holes" represents a hole extractor for primary shapes in
# \DRC expressions (see \drc and \DRC#hulls for more details).
# %DRC%
# @name odd_polygons
# @brief Selects all polygons which are non-orientable
# @synopsis odd_polygons
# @synopsis odd_polygons(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.odd_polygons" (see \Layer#odd_polygons). Without a layer
# argument, "odd_polygons" represents an odd polygon filter for primary shapes in
# \DRC expressions (see \drc and \DRC#odd_polygons for more details).
# %DRC%
# @name perimeter
# @brief Selects the primary shape if the perimeter is meeting the condition
# @synopsis perimeter (in condition)
# @synopsis perimeter(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.perimeter" (see \Layer#perimeter). Without a layer
# argument, "perimeter" represents a perimeter filter for primary shapes in
# \DRC expressions (see \drc and \DRC#perimeter for more details).
# %DRC%
# @name rectangles
# @brief Selects all polygons which are rectangles
# @synopsis rectangles
# @synopsis rectangles(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.rectangles" (see \Layer#rectangles). Without a layer
# argument, "rectangles" represents the rectangles filter for primary shapes in
# \DRC expressions (see \drc and \DRC#rectangles for more details).
# %DRC%
# @name rectilinear
# @brief Selects all polygons which are rectilinear
# @synopsis rectilinear
# @synopsis rectilinear(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.rectilinear" (see \Layer#rectilinear). Without a layer
# argument, "rectilinear" represents the rectilinear polygons filter for primary shapes in
# \DRC expressions (see \drc and \DRC#rectilinear for more details).
%w(
area
holes
@ -240,11 +407,90 @@ CODE
CODE
end
# %DRC%
# @name corners
# @brief Selects all polygons which are rectilinear
# @synopsis corners (in condition)
# @synopsis corners(layer)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.corners" (see \Layer#corners). Without a layer
# argument, "corners" represents the corner generator/filter in primary shapes for
# \DRC expressions (see \drc and \DRC#corners for more details).
def _cop_corners(as_dots = DRCAsDots::new(false))
# NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here.
return primary.corners(as_dots)
end
# %DRC%
# @name extent_refs
# @brief Returns partial references to the boundings boxes of the polygons
# @synopsis extent_refs([ options ])
# @synopsis extent_refs(layer, [ options ])
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.extent_refs" (see \Layer#extent_refs). Without a layer
# argument, "extent_refs" represents the partial extents extractor on primary shapes within
# \DRC expressions (see \drc and \DRC#extent_refs for more details).
# %DRC%
# @name extents
# @brief Returns the bounding box of each input object
# @synopsis extents([ enlargement ])
# @synopsis extents(layer, [ enlargement ])
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.extents" (see \Layer#extents). Without a layer
# argument, "extents" represents the extents generator on primary shapes within
# \DRC expressions (see \drc and \DRC#extents for more details).
# %DRC%
# @name middle
# @brief Returns the centers of polygon bounding boxes
# @synopsis middle([ options ])
# @synopsis middle(layer, [ options ])
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.middle" (see \Layer#middle). Without a layer
# argument, "middle" represents the bounding box center marker generator on primary shapes within
# \DRC expressions (see \drc and \DRC#middle for more details).
# %DRC%
# @name rounded_corners
# @brief Applies corner rounding
# @synopsis rounded_corners(inner, outer, n)
# @synopsis rounded_corners(layer, inner, outer, n)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.rounded_corners" (see \Layer#rounded_corners). Without a layer
# argument, "rounded_corners" represents the corner rounding algorithm on primary shapes within
# \DRC expressions (see \drc and \DRC#rounded_corners for more details).
# %DRC%
# @name sized
# @brief Returns the sized version of the input
# @synopsis sized(d [, mode])
# @synopsis sized(dx, dy [, mode]))
# @synopsis sized(layer, d [, mode])
# @synopsis sized(layer, dx, dy [, mode]))
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.sized" (see \Layer#sized). Without a layer
# argument, "sized" represents the polygon sizer on primary shapes within
# \DRC expressions (see \drc and \DRC#sized for more details).
# %DRC%
# @name smoothed
# @brief Applies smoothing
# @synopsis smoothed(d)
# @synopsis smoothed(layer, d)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.smoothed" (see \Layer#smoothed). Without a layer
# argument, "smoothed" represents the polygon smoother on primary shapes within
# \DRC expressions (see \drc and \DRC#smoothed for more details).
%w(
extent_refs
extents
@ -261,6 +507,81 @@ CODE
CODE
end
# %DRC%
# @name covering
# @brief Selects shapes entirely covering other shapes
# @synopsis covering(other) (in conditions)
# @synopsis covering(layer, other [, options ])
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.covering" (see \Layer#covering).
#
# Without a layer argument, this method represents the selector of primary shapes
# which entirely cover shapes from the other layer. This version can be put into
# a condition indicating how many shapes of the other layer need to be covered.
# Use this variant within \DRC expressions (also see \drc).
#
# For example, the following statement selects all input shapes which entirely
# cover shapes from the "other" layer:
#
# @code
# out = in.drc(covering(other))
# @/code
#
# This example selects all input shapes which entire cover shapes from
# the other layer and there are more than two shapes from "other" inside
# primary shapes:
#
# @code
# out = in.drc(covering(other) > 2)
# @/code
# %DRC%
# @name interacting
# @brief Selects shapes interacting with other shapes
# @synopsis interacting(other) (in conditions)
# @synopsis interacting(layer, other [, options ])
#
# See \covering for a description of the use cases for this function.
# When using "interacting", shapes are selected when the interact (overlap, touch)
# shapes from the other layer.
# %DRC%
# @name overlapping
# @brief Selects shapes overlapping with other shapes
# @synopsis overlapping(other) (in conditions)
# @synopsis overlapping(layer, other [, options ])
#
# See \covering for a description of the use cases for this function.
# When using "overlapping", shapes are selected when the overlap
# shapes from the other layer.
# %DRC%
# @name inside
# @brief Selects shapes entirely inside other shapes
# @synopsis inside(other)
# @synopsis inside(layer, other)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.inside" (see \Layer#inside).
#
# Without a layer argument, this method represents the selector of primary shapes
# which are entirely inside shapes from the other layer.
# Use this variant within \DRC expressions (also see \drc).
# %DRC%
# @name outside
# @brief Selects shapes entirely outside other shapes
# @synopsis outside(other)
# @synopsis outside(layer, other)
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.outside" (see \Layer#outside).
#
# Without a layer argument, this method represents the selector of primary shapes
# which are entirely outside shapes from the other layer.
# Use this variant within \DRC expressions (also see \drc).
%w(
covering
inside
@ -276,6 +597,106 @@ CODE
CODE
end
# %DRC%
# @name enclosing
# @brief Performs an enclosing check
# @synopsis enclosing(other [, options ]) (in conditions)
# @synopsis enclosing(layer, other [, options ])
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.enclosing" (see \Layer#enclosing).
#
# The version without the first layer is intended for use within \DRC expressions
# together with the \drc method. In this case, this function needs to be
# put into a condition to specify the check constraints. The other options
# of \Layer#enclosing (e.g. metrics, projection constraints, angle limits etc.)
# apply to this version too.
#
# The conditions can involve an upper and lower limit. The following examples
# illustrate the use of this function with conditions:
#
# @code
# out = in.drc(enclosing(other) < 0.2.um)
# out = in.drc(enclosing(other) <= 0.2.um)
# out = in.drc(enclosing(other) > 0.2.um)
# out = in.drc(enclosing(other) >= 0.2.um)
# out = in.drc(enclosing(other) == 0.2.um)
# out = in.drc(0.1.um <= enclosing(other) < 0.2.um)
# @/code
#
# The result of the enclosing check are edge pairs forming the violation
# markers. With a lower limit, these markers are formed by two, identical but opposite edges attached to
# the primary shape. Without a lower limit, the first edge of the marker is attached to the
# primary shape while the second edge is attached to the shape of the "other" layer.
# %DRC%
# @name separation
# @brief Performs a separation check
# @synopsis separation(other [, options ]) (in conditions)
# @synopsis separation(layer, other [, options ])
#
# Provides a separation check (primary layer vs. another layer). Like \enclosing this
# function provides a two-layer check. See there for details how to use this function.
# %DRC%
# @name overlap
# @brief Performs an overlap check
# @synopsis overlap(other [, options ]) (in conditions)
# @synopsis overlap(layer, other [, options ])
#
# Provides an overlap check (primary layer vs. another layer). Like \enclosing this
# function provides a two-layer check. See there for details how to use this function.
# %DRC%
# @name width
# @brief Performs a width check
# @synopsis width([ options ]) (in conditions)
# @synopsis width(layer [, options ])
#
# This function can be used with a layer argument in which case it
# is equivalent to "layer.width" (see \Layer#width).
#
# The version without a layer it intended for use within \DRC expressions
# together with the \drc method. In this case, this function needs to be
# put into a condition to specify the check constraints. The other options
# of \Layer#width (e.g. metrics, projection constraints, angle limits etc.)
# apply to this version too.
#
# The conditions can involve an upper and lower limit. The following examples
# illustrate the use of this function with conditions:
#
# @code
# out = in.drc(width < 0.2.um)
# out = in.drc(width <= 0.2.um)
# out = in.drc(width > 0.2.um)
# out = in.drc(width >= 0.2.um)
# out = in.drc(width == 0.2.um)
# out = in.drc(0.1.um <= width < 0.2.um)
# @/code
#
# The result of the width check are edge pairs forming the violation
# markers. With a lower limit, these markers are formed by two, identical but opposite edges attached to
# the primary shape. Without a lower limit, both edges are attached to different sides of the primary
# shape.
# %DRC%
# @name space
# @brief Performs a space check
# @synopsis space([ options ]) (in conditions)
# @synopsis space(layer [, options ])
#
# Provides a space check on the primary layer. Like \width this
# function provides a single-layer check. See there for details how to use this function.
# %DRC%
# @name notch
# @brief Performs a notch (intra-polygon space) check
# @synopsis notch([ options ]) (in conditions)
# @synopsis notch(layer [, options ])
#
# Provides a intra-polygon space check for polygons from the primary layer. Like \width this
# function provides a single-layer check. See there for details how to use this function.
%w(
enclosing
isolated
@ -313,6 +734,8 @@ CODE
alim = a.value
elsif a.is_a?(DRCOpNode)
other = a
elsif a.is_a?(DRCLayer)
other = self._make_node(a)
elsif a.is_a?(DRCProjectionLimits)
minp = self._make_value(a.min)
maxp = self._make_value(a.max)
@ -352,6 +775,27 @@ CODE
CODE
end
# %DRC%
# @name iso
# @brief Synonym for "isolated"
# @synopsis iso(...)
#
# "iso" is the short form for \isolated.
# %DRC%
# @name sep
# @brief Synonym for "separation"
# @synopsis sep(...)
#
# "sep" is the short form for \separation.
# %DRC%
# @name enc
# @brief Synonym for "enclosing"
# @synopsis enc(...)
#
# "enc" is the short form for \enclosing.
def _cop_iso(*args)
# NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here.
_cop_isolated(*args)
@ -364,7 +808,15 @@ CODE
def _cop_enc(*args)
# NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here.
_cop_separation(*args)
_cop_enclosing(*args)
end
def _make_node(arg)
if arg.is_a?(DRCLayer)
arg = DRCOpNode::new(self, RBA::CompoundRegionOperationNode::new_secondary(arg.data))
arg.description = "secondary"
end
arg
end
end

View File

@ -1518,6 +1518,32 @@ CODE
end
end
# make some DRCLayer methods available as functions
# for the engine
%w(
enc
enclosing
overlapping
sep
separation
).each do |f|
eval <<"CODE"
def #{f}(*args)
self._context("#{f}") do
if args[0].is_a?(DRCLayer) && args[1].is_a?(DRCLayer)
obj = args.shift
return obj.#{f}(*args)
elsif self.respond_to?(:_cop_#{f})
# forward to _cop_ implementation for complex DRC operations
return self._cop_#{f}(*args)
else
raise("Function requires at a layer expression for the first two arguments")
end
end
end
CODE
end
# make some DRCLayer methods available as functions
# for the engine
%w(
@ -1528,8 +1554,6 @@ CODE
centers
corners
covering
enc
enclosing
end_segments
extended
extended_in
@ -1572,7 +1596,6 @@ CODE
outside
outside_part
overlap
overlapping
perimeter
pull_inside
pull_interacting
@ -1596,8 +1619,6 @@ CODE
select_outside
select_overlapping
select_touching
sep
separation
size
sized
smoothed