Doc update, implemented != for DRC operations.

This commit is contained in:
Matthias Koefferlein 2021-01-10 21:36:58 +01:00
parent 2951bf424c
commit f3f196cfb3
5 changed files with 166 additions and 5 deletions

View File

@ -1055,12 +1055,16 @@ class DRCOpNodeWithCompare < DRCOpNode
attr_accessor :reverse
attr_accessor :original
attr_accessor :lt, :le, :gt, :ge, :arg
attr_accessor :ne_allowed
attr_accessor :mode_or
def initialize(engine, original = nil, reverse = false)
super(engine)
self.reverse = reverse
self.original = original
self.description = original ? original.description : "BasicWithCompare"
self.mode_or = false
self.ne_allowed = false
end
def _description_for_dump
@ -1076,12 +1080,12 @@ class DRCOpNodeWithCompare < DRCOpNode
self.le && (cmp << ("<=%.12g" % self.le))
self.gt && (cmp << (">%.12g" % self.gt))
self.ge && (cmp << (">=%.12g" % self.ge))
return indent + self.description + " " + cmp.join(" ")
return indent + self.description + " " + cmp.join(" ") + (self.mode_or ? " [or]" : "")
end
end
def _check_bounds
if (self.lt || self.le) && (self.gt || self.ge)
if ! self.mode_or && (self.lt || self.le) && (self.gt || self.ge)
epsilon = 1e-10
lower = self.ge ? self.ge - epsilon : self.gt + epsilon
upper = self.le ? self.le + epsilon : self.lt - epsilon
@ -1123,6 +1127,20 @@ class DRCOpNodeWithCompare < DRCOpNode
return (self.original || self).dup
end
def !=(other)
if !self.ne_allowed
raise("!= operator is not allowed for '" + self.description + "'")
end
if !(other.is_a?(Float) || other.is_a?(Integer))
raise("!= operator needs a numerical argument for '" + self.description + "' argument")
end
res = self._self_or_original
res.mode_or = true
res.set_lt(other)
res.set_gt(other)
return res
end
def ==(other)
if !(other.is_a?(Float) || other.is_a?(Integer))
raise("== operator needs a numerical argument for '" + self.description + "' argument")
@ -1477,6 +1495,7 @@ class DRCOpNodeCheck < DRCOpNodeWithCompare
self.other = other
self.args = args
self.description = check.to_s
self.ne_allowed = true
end
def _description_for_dump
@ -1516,12 +1535,16 @@ class DRCOpNodeCheck < DRCOpNodeWithCompare
if res
if self.check == :width || self.check == :notch
# Same polygon check - we need to take both edges of the result
and_with = RBA::CompoundRegionOperationNode::new_edges(res)
other = RBA::CompoundRegionOperationNode::new_edges(res)
else
and_with = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(res)
other = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(res)
end
res_max = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(max_check)
res = RBA::CompoundRegionOperationNode::new_geometrical_boolean(RBA::CompoundRegionOperationNode::GeometricalOp::And, and_with, res_max)
if self.mode_or
res = RBA::CompoundRegionOperationNode::new_join([ other, res_max ])
else
res = RBA::CompoundRegionOperationNode::new_geometrical_boolean(RBA::CompoundRegionOperationNode::GeometricalOp::And, other, res_max)
end
else
res = max_check
end

View File

@ -399,6 +399,9 @@ output(w, "width violations")</pre>
<a href="/about/drc_ref_layer.xml#enclosure">enclosure (enc)</a>,
<a href="/about/drc_ref_layer.xml#overlap">overlap</a>
</li>
<li>Universal DRC (see below):<br/>
<a href="/about/drc_ref_layer.xml#drc">drc</a>
</li>
<li>Boolean operations:<br/>
<a href="/about/drc_ref_layer.xml#&amp;">&amp; (and)</a>,
<a href="/about/drc_ref_layer.xml#|">| (or)</a>,
@ -767,6 +770,139 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
</table>
<h2>Universal DRC</h2>
<keyword name="DRC"/>
<keyword name="Universal DRC"/>
<p>
Starting with version 0.27, the DRC language got a new feature which is "universal DRC".
</p>
<p>
On one hand, this is a more convenient way to write DRC checks because it allows
specifications using natural compare operators. For example, the following plain width check
</p>
<pre>
...
drc_w = input(1, 0).width(0.2)
...
</pre>
<p>
can be written as:
</p>
<pre>
...
drc_w = input(1, 0).drc(width &lt; 0.2)
...
</pre>
<p>
The <a href="/about/drc_ref_layer.xml#drc">drc</a> method is the "universal DRC" method.
It takes an operator. In the simple case, this operator is a simple constraint of the
form "measurement &lt; value", but it supports a number of different variants:
</p>
<ul>
<li>
<tt>drc(</tt> measurement <tt> != </tt> value <tt>)</tt></li>:
renders markers where the dimension is not matching the value
</li>
<li>
<tt>drc(</tt> measurement <tt> == </tt> value <tt>)</tt></li>:
renders markers where the dimension is matching the given value
</li>
<li>
<tt>drc(</tt> measurement less_op value <tt>)</tt></li>:
("less_op" is <tt>&lt;</tt> or <tt>&lt;=</tt>)
renders markers where the dimension is less than or less or equal to the given value
</li>
<li>
<tt>drc(</tt> measurement greater_op value <tt>)</tt></li>:
("greater_op" is <tt>&gt;</tt> or <tt>&gt;=</tt>)
renders markers where the dimension is greater than or greater or equal to the given value
</li>
<li>
<tt>drc(</tt> lower_value less_op measurement greater_op upper_value <tt>)</tt></li>:
renders markers where the dimension is between the lower and upper value
</li>
</ul>
<p>
"measurement" is "width", "notch", "isolated" ("iso"), "separation" ("sep"), "overlap" or "enclosure" ("enc"). They have the
The last three checks are two-layer checks which require a second layer. The
second layer is specified together with the measurement like this:
</p>
<pre>
...
l1 = input(1, 0)
l2 = input(2, 0)
drc_sep = l1.drc(separation(l2) &lt;= 0.5)
...
</pre>
<p>
Options are also specified together with the measurement and follow the same notation
as the plain methods. For example to specify "projection" metrics, use:
</p>
<pre>
...
drc_w = input(1, 0).drc(width(projection) &lt; 0.2)
...
</pre>
<p>
However, the universal DRC is much more: it offers a number of options to further process
the results. The functionality behind the universal DRC function is basically a kind of
loop over all primary shapes (the ones from the layer the "drc" function is called on).
The operations in the drc function's brackets is executed on each of the primary shapes
where the neighborhood of that single shape is considered. This scheme is more efficient
and enables applications beyond the capabilities of the plain layer methods.
</p>
<p>
For example, the boolean "&amp;" operator implements a "local" boolean AND inside this
loop. This allows to efficiently check for both space and width violations:
</p>
<pre>
...
drc_ws = input(1, 0).drc((width &lt; 0.2) &amp; (space &lt; 0.3))
...
</pre>
<p>
The boolean AND is computed between the edges on the primary shape and returns these
parts where both space and width violations are flagged. The boolean operation is
more efficient than the plain alternative:
</p>
<pre>
...
drc_ws1 = input(1, 0).width(0.2).edges
drc_ws2 = input(1, 0).space(0.3).edges
drc_ws = drc_ws1 &amp; drc_ws2
...
</pre>
<p>
The reson is that performing the boolean computation in the local loop can be
shortcut if one input is empty and it does not need to store a (potentially big)
layer set with edges as produced by the plain-method implementation. Instead it
will work with a temporary and local edge set only and free the memory space as
soon as it moves on to the next primary shape.
</p>
<p>
The universal DRC function is a rich feature and offers filters based on
polygons or edge properties, polygon or edge manipulation, conditionals
and a lot more. For more details see the <a href="/about/drc_ref_layer.xml#drc">drc function documentation</a>.
</p>
<h2>Logging and verbosity</h2>
<keyword name="Logging"/>

View File

@ -27,4 +27,6 @@ l1.drc(1.5 <= wcheck).output(107, 0)
l1.drc(wcheck == 1.5).output(108, 0)
l1.drc(1.0 <= wcheck <= 1.5).output(109, 0)
l1.drc(1.0 < wcheck < 2.0).output(110, 0)
l1.drc(wcheck != 1.5).output(111, 0)
l1.drc(wcheck != 1.0).output(112, 0)

Binary file not shown.

Binary file not shown.