mirror of https://github.com/KLayout/klayout.git
AND and NOT for texts vs. region, DRC generalization.
This commit is contained in:
parent
8a2742d436
commit
878a494abb
|
|
@ -404,12 +404,12 @@ Class<db::Texts> decl_Texts ("db", "Texts",
|
|||
"If \"inverse\" is false, this method returns the texts matching the pattern.\n"
|
||||
"If \"inverse\" is true, this method returns the texts not matching the pattern.\n"
|
||||
) +
|
||||
method ("interacting", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_interacting, gsi::arg ("other"),
|
||||
method ("interacting|&", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the texts from this text collection which are inside or on the edge of polygons from the given region\n"
|
||||
"\n"
|
||||
"@return A new text collection containing the texts inside or on the edge of polygons from the region\n"
|
||||
) +
|
||||
method ("not_interacting", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_not_interacting, gsi::arg ("other"),
|
||||
method ("not_interacting|-", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the texts from this text collection which are not inside or on the edge of polygons from the given region\n"
|
||||
"\n"
|
||||
"@return A new text collection containing the texts not inside or on the edge of polygons from the region\n"
|
||||
|
|
@ -500,10 +500,10 @@ Class<db::Texts> decl_Texts ("db", "Texts",
|
|||
"@brief Texts (a collection of texts)\n"
|
||||
"\n"
|
||||
"Text objects are useful as labels for net names, to identify certain regions and to specify specific locations in general. "
|
||||
"Text collections provide a way to store - also in a hierarchical fashion - and manipulate collection of text objects.\n"
|
||||
"Text collections provide a way to store - also in a hierarchical fashion - and manipulate a collection of text objects.\n"
|
||||
"\n"
|
||||
"Text objects can be turned into polygons by creating small boxes around the texts (\\polygons). Texts can also be turned into dot-like "
|
||||
"edges (\\edges). Texts can be filtered by string, either by matching against a fixed string (\\with_string) or a glob-style pattern (\\with_pattern).\n"
|
||||
"edges (\\edges). Texts can be filtered by string, either by matching against a fixed string (\\with_text) or a glob-style pattern (\\with_match).\n"
|
||||
"\n"
|
||||
"Text collections can be filtered geometrically against a polygon \\Region using \\interacting or \\non-interacting. "
|
||||
"Vice versa, texts can be used to select polygons from a \\Region using \\pull_interacting.\n"
|
||||
|
|
|
|||
|
|
@ -1083,13 +1083,33 @@ module DRC
|
|||
# %DRC%
|
||||
# @name labels
|
||||
# @brief Gets the labels (text) from an original layer
|
||||
# @synopsis labels
|
||||
# @synopsis labels(args)
|
||||
# See \Source#labels for a description of that function.
|
||||
|
||||
def labels(*args)
|
||||
layout.labels(*args)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name edges
|
||||
# @brief Gets the edges from an original layer
|
||||
# @synopsis edges(args)
|
||||
# See \Source#edges for a description of that function.
|
||||
|
||||
def edges(*args)
|
||||
layout.edges(*args)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name edge_pairs
|
||||
# @brief Gets the edges from an original layer
|
||||
# @synopsis edge_pairs(args)
|
||||
# See \Source#edge_pairs for a description of that function.
|
||||
|
||||
def edge_pairs(*args)
|
||||
layout.edge_pairs(*args)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name output
|
||||
# @brief Outputs a layer to the report database or output layout
|
||||
|
|
@ -1757,11 +1777,11 @@ CODE
|
|||
end
|
||||
end
|
||||
|
||||
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags)
|
||||
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, cls)
|
||||
|
||||
if layers.empty? && ! @deep
|
||||
|
||||
r = RBA::Region::new
|
||||
r = cls.new
|
||||
|
||||
else
|
||||
|
||||
|
|
@ -1795,13 +1815,13 @@ CODE
|
|||
# object which keeps the DSS.
|
||||
@dss.text_property_name = "LABEL"
|
||||
@dss.text_enlargement = 1
|
||||
r = RBA::Region::new(iter, @dss, RBA::ICplxTrans::new(sf.to_f))
|
||||
r = cls.new(iter, @dss, RBA::ICplxTrans::new(sf.to_f))
|
||||
else
|
||||
r = RBA::Region::new(iter, RBA::ICplxTrans::new(sf.to_f))
|
||||
r = cls.new(iter, RBA::ICplxTrans::new(sf.to_f))
|
||||
end
|
||||
|
||||
# clip if a box is specified
|
||||
if box && clip
|
||||
if box && clip && (cls == RBA::Region || cls == RBA::Edge)
|
||||
r &= RBA::Region::new(box)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -593,6 +593,10 @@ CODE
|
|||
# selected text. By using the "as_dots" option, degenerated point-like edges will be
|
||||
# produced.
|
||||
#
|
||||
# This method can also be applied to true text layers obtained with \labels.
|
||||
# In this case, without specifying "as_dots" or "as_boxes" retains the text
|
||||
# objects as such. Only text filtering is applied.
|
||||
#
|
||||
# Texts can be selected either by exact match string or a pattern match with a
|
||||
# glob-style pattern. By default, glob-style pattern are used.
|
||||
# The options available are:
|
||||
|
|
@ -615,14 +619,39 @@ CODE
|
|||
# # Selects all texts whose string is "A*"
|
||||
# t = input(1, 0).texts(text("A*"))
|
||||
# @/code
|
||||
#
|
||||
|
||||
def texts(*args)
|
||||
requires_texts_or_region("texts")
|
||||
self._texts_impl(false, *args)
|
||||
end
|
||||
|
||||
requires_region("texts")
|
||||
# %DRC%
|
||||
# @name texts_not
|
||||
# @brief Selects texts from an original layer not matching a specific selection
|
||||
# @synopsis layer.texts_not
|
||||
# @synopsis layer.texts_not(p)
|
||||
# @synopsis layer.texts_not([ options ])
|
||||
#
|
||||
# This method can be applied to true text layers obtained with \labels.
|
||||
# In this case, without specifying "as_dots" or "as_boxes" retains the text
|
||||
# objects as such. Only text filtering is applied.
|
||||
#
|
||||
# Beside that this method acts like \texts, but will select the text objects
|
||||
# not matching the filter.
|
||||
|
||||
def texts_not(*args)
|
||||
requires_texts("texts_not")
|
||||
self._texts_impl(true, *args)
|
||||
end
|
||||
|
||||
# Implementation of texts or texts_not
|
||||
|
||||
def _texts_impl(invert, *args)
|
||||
|
||||
as_pattern = true
|
||||
pattern = "*"
|
||||
as_dots = false
|
||||
as_dots = nil
|
||||
|
||||
args.each do |a|
|
||||
if a.is_a?(String)
|
||||
|
|
@ -637,15 +666,28 @@ CODE
|
|||
raise("Invalid argument for 'texts' method")
|
||||
end
|
||||
end
|
||||
|
||||
if as_dots
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern))
|
||||
|
||||
if @data.is_a?(RBA::Texts)
|
||||
if as_pattern
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Texts, :with_match, pattern, invert))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Texts, :with_text, pattern, invert))
|
||||
end
|
||||
if as_dots
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :edges))
|
||||
elsif as_dots == false
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :polygons))
|
||||
end
|
||||
else
|
||||
if as_dots
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
# %DRC%
|
||||
# @name corners
|
||||
# @brief Selects corners of polygons
|
||||
|
|
@ -1695,7 +1737,35 @@ CODE
|
|||
requires_region("#{f}")
|
||||
other.requires_region("#{f}")
|
||||
else
|
||||
requires_edges_or_region("#{f}")
|
||||
requires_edges_texts_or_region("#{f}")
|
||||
if @data.is_a?(RBA::Text)
|
||||
other.requires_region("#{f}")
|
||||
else
|
||||
other.requires_edges_or_region("#{f}")
|
||||
end
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, other.data.class, :#{f}, other.data))
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(| ^ overlapping not_overlapping inside not_inside outside not_outside in not_in).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
requires_same_type(other, "#{f}")
|
||||
requires_edges_or_region("#{f}")
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data))
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(& -).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
other.requires_edges_texts_or_region("#{f}")
|
||||
if @data.is_a?(RBA::Texts)
|
||||
other.requires_region("#{f}")
|
||||
else
|
||||
other.requires_edges_or_region("#{f}")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data))
|
||||
|
|
@ -1703,15 +1773,22 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
%w(& | ^ - + interacting not_interacting overlapping not_overlapping inside not_inside outside not_outside in not_in).each do |f|
|
||||
%w(+).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
if :#{f} != :interacting && :#{f} != :not_interacting && :#{f} != :& && :#{f} != :-
|
||||
requires_same_type(other, "#{f}")
|
||||
requires_same_type(other, "#{f}")
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data))
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(interacting not_interacting).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
other.requires_edges_texts_or_region("#{f}")
|
||||
if @data.is_a?(RBA::Texts)
|
||||
other.requires_region("#{f}")
|
||||
else
|
||||
other.requires_edges_or_region("#{f}")
|
||||
end
|
||||
if :#{f} != :+
|
||||
requires_edges_or_region("#{f}")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data))
|
||||
|
|
@ -2207,7 +2284,7 @@ CODE
|
|||
# If the layer already is a flat one, this method does nothing.
|
||||
# If the layer is a hierarchical layer (an original layer or
|
||||
# a derived layer in deep mode), this method will convert it
|
||||
# to a flat collection of polygons, edges or edge pairs.
|
||||
# to a flat collection of texts, polygons, edges or edge pairs.
|
||||
|
||||
def flatten
|
||||
DRC::DRCLayer::new(@engine, @engine._cmd(@data, :flatten))
|
||||
|
|
@ -2235,7 +2312,6 @@ CODE
|
|||
# @synopsis layer.is_empty?
|
||||
|
||||
def is_empty?
|
||||
requires_edges_or_region("is_empty?")
|
||||
@data.is_empty?
|
||||
end
|
||||
|
||||
|
|
@ -3006,6 +3082,10 @@ CODE
|
|||
@data.is_a?(RBA::Region) || raise("#{f}: Requires a polygon layer")
|
||||
end
|
||||
|
||||
def requires_texts_or_region(f)
|
||||
@data.is_a?(RBA::Region) || @data.is_a?(RBA::Texts) || raise("#{f}: Requires a polygon or text layer")
|
||||
end
|
||||
|
||||
def requires_edge_pairs(f)
|
||||
@data.is_a?(RBA::EdgePairs) || raise("#{f}: Requires a edge pair layer")
|
||||
end
|
||||
|
|
@ -3018,6 +3098,10 @@ CODE
|
|||
@data.is_a?(RBA::Edges) || @data.is_a?(RBA::Region) || raise("#{f}: Requires an edge or polygon layer")
|
||||
end
|
||||
|
||||
def requires_edges_texts_or_region(f)
|
||||
@data.is_a?(RBA::Edges) || @data.is_a?(RBA::Region) || @data.is_a?(RBA::Texts) || raise("#{f}: Requires an edge, text or polygon layer")
|
||||
end
|
||||
|
||||
def requires_same_type(other, f)
|
||||
@data.class == other.data.class || raise("#{f}: Requires input of the same kind")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ CODE
|
|||
# not have names)@/li
|
||||
# @/ul
|
||||
#
|
||||
# Layers created with "input" contain both texts and polygons. There is a subtle
|
||||
# Layers created with "input" may contain both texts (labels) and polygons. There is a subtle
|
||||
# difference between flat and deep mode: in flat mode, texts are not visible in polygon
|
||||
# operations. In deep mode, texts appear as small 2x2 DBU rectangles. In flat mode,
|
||||
# some operations such as clipping are not fully supported for texts. Also, texts will
|
||||
|
|
@ -273,11 +273,16 @@ CODE
|
|||
# If you don't want to see texts, use \polygons to create an input layer with polygon data
|
||||
# only. If you only want to see texts, use \labels to create an input layer with texts only.
|
||||
#
|
||||
# \labels also produces a true "text layer" which contains text objects. A variety of
|
||||
# operations is available for these objects, such as boolean "and" and "not" with a polygon layer.
|
||||
# True text layers should be preferred over mixed polygon/text layers if text object processing
|
||||
# is required.
|
||||
#
|
||||
# Use the global version of "input" without a source object to address the default source.
|
||||
|
||||
def input(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -288,16 +293,18 @@ CODE
|
|||
# @synopsis source.labels(layer_into)
|
||||
# @synopsis source.labels(filter, ...)
|
||||
#
|
||||
# Creates a layer with the labels from the given layer of the source.
|
||||
# Creates a true text layer with the labels from the given layer of the source.
|
||||
#
|
||||
# This method is identical to \input, but takes only texts from the given input
|
||||
# layer.
|
||||
# layer. Starting with version 0.27, the result is no longer a polygon layer that tries
|
||||
# to provide text support but a layer type which is provided for carrying text objects
|
||||
# explicitly.
|
||||
#
|
||||
# Use the global version of "labels" without a source object to address the default source.
|
||||
|
||||
def labels(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, RBA::Texts))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -318,7 +325,55 @@ CODE
|
|||
|
||||
def polygons(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, RBA::Region))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name edges
|
||||
# @brief Gets the edge shapes (or shapes that can be converted edges) from an input layer
|
||||
# @synopsis source.edges(layer)
|
||||
# @synopsis source.edges(layer, datatype)
|
||||
# @synopsis source.edges(layer_into)
|
||||
# @synopsis source.edges(filter, ...)
|
||||
#
|
||||
# Creates a layer with the edges from the given layer of the source.
|
||||
# Edge layers are formed from shapes by decomposing the shapes into edges: polygons
|
||||
# for example are decomposed into their outline edges. Some file formats support egdes
|
||||
# as native objects.
|
||||
#
|
||||
# This method is identical to \input with respect to the options supported.
|
||||
#
|
||||
# Use the global version of "edges" without a source object to address the default source.
|
||||
#
|
||||
# This method has been introduced in version 0.27.
|
||||
|
||||
def edges(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, RBA::Edges))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name edge_pairs
|
||||
# @brief Gets the edge pairs from an input layer
|
||||
# @synopsis source.edge_pairs(layer)
|
||||
# @synopsis source.edge_pairs(layer, datatype)
|
||||
# @synopsis source.edge_pairs(layer_into)
|
||||
# @synopsis source.edge_pairs(filter, ...)
|
||||
#
|
||||
# Creates a layer with the edge_pairs from the given layer of the source.
|
||||
# Edge pairs are not supported by layout formats so far. So except if the source is
|
||||
# a custom-built layout object, this method has little use. It is provided for future
|
||||
# extensions which may include edge pairs in file streams.
|
||||
#
|
||||
# This method is identical to \input with respect to the options supported.
|
||||
#
|
||||
# Use the global version of "edge_pairs" without a source object to address the default source.
|
||||
#
|
||||
# This method has been introduced in version 0.27.
|
||||
|
||||
def edge_pairs(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, RBA::EdgePairs))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -329,7 +384,7 @@ CODE
|
|||
|
||||
def make_layer
|
||||
layers = []
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
|
|||
Loading…
Reference in New Issue