WIP: documentation, local merging of polygon for interact, covering ..

This commit is contained in:
Matthias Koefferlein 2021-01-12 01:08:12 +01:00
parent aefc3153fe
commit ae29c75326
15 changed files with 587 additions and 102 deletions

View File

@ -399,7 +399,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse,
db::RegionIterator polygons (begin_merged ());
db::interacting_with_edge_local_operation<db::Polygon, db::Edge, db::Polygon> op (inverse, min_count, max_count);
db::interacting_with_edge_local_operation<db::Polygon, db::Edge, db::Polygon> op (inverse, min_count, max_count, true);
db::local_processor<db::Polygon, db::Edge, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
@ -560,7 +560,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
db::RegionIterator polygons (begin_merged ());
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op (mode, touching, inverse, min_count, max_count);
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op (mode, touching, inverse, min_count, max_count, true);
db::local_processor<db::Polygon, db::Polygon, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());

View File

@ -61,6 +61,21 @@ CompoundRegionOperationNode::generated_description () const
return std::string ();
}
bool
CompoundRegionOperationNode::is_merged () const
{
std::vector<db::Region *> iv = inputs ();
// NOTE: the primary is supposed to be merged always (except in raw mode)
return iv.size () == 1 && (is_subject_regionptr (iv.front ()) || iv.front ()->is_merged ());
}
bool
CompoundRegionOperationNode::has_external_inputs () const
{
std::vector<db::Region *> iv = inputs ();
return iv.size () == 1 && ! is_subject_regionptr (iv.front ());
}
// ---------------------------------------------------------------------------------------------
static void translate (db::Layout *layout, const std::vector<std::unordered_set<db::Polygon> > &in, std::vector<std::unordered_set<db::PolygonRef> > &out)
@ -1052,6 +1067,75 @@ template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_lo
template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_local<db::Polygon, db::EdgePair> (db::Layout *, const shape_interactions<db::Polygon, db::Polygon> &, std::vector<std::unordered_set<db::EdgePair> > &, size_t, double) const;
template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_local<db::PolygonRef, db::EdgePair> (db::Layout *, const shape_interactions<db::PolygonRef, db::PolygonRef> &, std::vector<std::unordered_set<db::EdgePair> > &, size_t, double) const;
// ---------------------------------------------------------------------------------------------
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ())
{
// .. nothing yet ..
}
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ())
{
// .. nothing yet ..
}
std::string
CompoundRegionInteractOperationNode::generated_description () const
{
return std::string ("interact") + compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon>::generated_description ();
}
// ---------------------------------------------------------------------------------------------
CompoundRegionInteractWithEdgeOperationNode::CompoundRegionInteractWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count)
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon> (&m_op, a, b), m_op (inverse, min_count, max_count, b->is_merged ())
{
// .. nothing yet ..
}
std::string
CompoundRegionInteractWithEdgeOperationNode::generated_description () const
{
return std::string ("interact") + compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon>::generated_description ();
}
// ---------------------------------------------------------------------------------------------
CompoundRegionPullOperationNode::CompoundRegionPullOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching)
{
// .. nothing yet ..
}
CompoundRegionPullOperationNode::CompoundRegionPullOperationNode (db::Region *a, db::Region *b, int mode, bool touching)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching)
{
// .. nothing yet ..
}
std::string
CompoundRegionPullOperationNode::generated_description () const
{
return std::string ("pull") + compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon>::generated_description ();
}
// ---------------------------------------------------------------------------------------------
CompoundRegionPullWithEdgeOperationNode::CompoundRegionPullWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b)
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Edge> (&m_op, a, b), m_op ()
{
// .. nothing yet ..
}
std::string
CompoundRegionPullWithEdgeOperationNode::generated_description () const
{
return std::string ("pull") + compound_region_generic_operation_node<db::Polygon, db::Edge, db::Edge>::generated_description ();
}
// ---------------------------------------------------------------------------------------------
CompoundRegionJoinOperationNode::CompoundRegionJoinOperationNode (const std::vector<CompoundRegionOperationNode *> &inputs)
@ -1514,17 +1598,8 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode * /*input*/, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
: CompoundRegionMultiInputOperationNode (other), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options)
{
m_has_other = false;
std::vector<db::Region *> other_inputs = other->inputs ();
if (other_inputs.size () > 1) {
m_has_other = true;
m_is_other_merged = false; // or do we know better?
} else if (other_inputs.size () == 1) {
if (! is_subject_regionptr (other_inputs.front ())) {
m_has_other = true;
m_is_other_merged = other_inputs.front ()->is_merged ();
}
}
m_has_other = other->has_external_inputs ();
m_is_other_merged = other->is_merged ();
set_description ("check");

View File

@ -104,6 +104,18 @@ public:
*/
void set_description (const std::string &d);
/**
* @brief Gets a value indicating whether the result is definitely merged
* The default implementation is based on a heuristic analysis of the inputs.
*/
virtual bool is_merged () const;
/**
* @brief Returns a value indicating whether this node provides external inputs
* A node has external inputs if it has inputs and does not refer to the primary alone.
*/
virtual bool has_external_inputs () const;
/**
* @brief Returns a value giving a hint how to handle the case of empty intruders
*/
@ -676,22 +688,10 @@ class DB_PUBLIC CompoundRegionInteractOperationNode
: public compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon>
{
public:
CompoundRegionInteractOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching, bool inverse, size_t min_count = 0, size_t max_count = std::numeric_limits<size_t>::max ())
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count)
{
// .. nothing yet ..
}
CompoundRegionInteractOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching, bool inverse, size_t min_count = 0, size_t max_count = std::numeric_limits<size_t>::max ());
CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count = 0, size_t max_count = std::numeric_limits<size_t>::max ());
CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count = 0, size_t max_count = std::numeric_limits<size_t>::max ())
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count)
{
// .. nothing yet ..
}
std::string generated_description () const
{
return std::string ("interact") + compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon>::generated_description ();
}
std::string generated_description () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const
{
@ -711,16 +711,9 @@ class DB_PUBLIC CompoundRegionInteractWithEdgeOperationNode
: public compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon>
{
public:
CompoundRegionInteractWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, bool inverse, size_t min_count = 0, size_t max_count = std::numeric_limits<size_t>::max ())
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon> (&m_op, a, b), m_op (inverse, min_count, max_count)
{
// .. nothing yet ..
}
CompoundRegionInteractWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, bool inverse, size_t min_count = 0, size_t max_count = std::numeric_limits<size_t>::max ());
std::string generated_description () const
{
return std::string ("interact") + compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon>::generated_description ();
}
std::string generated_description () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const
{
@ -740,22 +733,10 @@ class DB_PUBLIC CompoundRegionPullOperationNode
: public compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon>
{
public:
CompoundRegionPullOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching)
{
// .. nothing yet ..
}
CompoundRegionPullOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching);
CompoundRegionPullOperationNode (db::Region *a, db::Region *b, int mode, bool touching);
CompoundRegionPullOperationNode (db::Region *a, db::Region *b, int mode, bool touching)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching)
{
// .. nothing yet ..
}
std::string generated_description () const
{
return std::string ("pull") + compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon>::generated_description ();
}
std::string generated_description () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const
{
@ -775,16 +756,9 @@ class DB_PUBLIC CompoundRegionPullWithEdgeOperationNode
: public compound_region_generic_operation_node<db::Polygon, db::Edge, db::Edge>
{
public:
CompoundRegionPullWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b)
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Edge> (&m_op, a, b), m_op ()
{
// .. nothing yet ..
}
CompoundRegionPullWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b);
std::string generated_description () const
{
return std::string ("pull") + compound_region_generic_operation_node<db::Polygon, db::Edge, db::Edge>::generated_description ();
}
std::string generated_description () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const
{

View File

@ -1534,7 +1534,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
DeepLayer dl_out (polygons.derived ());
db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count);
db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count, true);
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
@ -1573,7 +1573,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size
DeepLayer dl_out (polygons.derived ());
db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count);
db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count, true);
db::local_processor<db::PolygonRef, db::Edge, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());

View File

@ -233,6 +233,9 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
} else if (! m_other_is_merged && (ids.size () > 1 || ! interactions.intruder_shape (*ids.begin ()).second.is_box ())) {
// NOTE: this local merge is not necessarily giving the same results than a global merge before running
// the processor. Reason: the search range is limited, hence not all necessary components may have been
// captured.
db::EdgeProcessor ep;
ep.clear ();
@ -536,9 +539,31 @@ template class DB_PUBLIC check_local_operation<db::Polygon, db::Polygon>;
// ---------------------------------------------------------------------------------------------------------------
namespace {
class PolygonToEdgeProcessor
: public db::PolygonSink
{
public:
PolygonToEdgeProcessor (db::EdgeProcessor *target, size_t *id)
: mp_target (target), mp_id (id)
{ }
virtual void put (const db::Polygon &poly)
{
mp_target->insert (poly, (*mp_id)++);
}
private:
db::EdgeProcessor *mp_target;
size_t *mp_id;
};
}
template <class TS, class TI, class TR>
interacting_local_operation<TS, TI, TR>::interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
: m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
interacting_local_operation<TS, TI, TR>::interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged)
: m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
{
// .. nothing yet ..
}
@ -588,6 +613,24 @@ void interacting_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*l
}
n++;
} else if (! m_other_is_merged && ! (m_min_count == size_t (1) && m_max_count == std::numeric_limits<size_t>::max ())) {
// in counted mode we need to merge the shapes because they might overlap
db::EdgeProcessor ep_merge;
size_t i = 0;
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
for (typename TI::polygon_edge_iterator e = o->begin_edge (); ! e.at_end (); ++e) {
ep_merge.insert (*e, i);
}
i += 1;
}
PolygonToEdgeProcessor ps (&ep, &n);
db::PolygonGenerator pg (ps, false /*don't resolve holes*/, false);
db::SimpleMerge op (1 /*wc>0*/);
ep_merge.process (pg, op);
} else {
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
@ -743,8 +786,8 @@ template class DB_PUBLIC pull_local_operation<db::Polygon, db::Polygon, db::Poly
// ---------------------------------------------------------------------------------------------------------------
template <class TS, class TI, class TR>
interacting_with_edge_local_operation<TS, TI, TR>::interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count)
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
interacting_with_edge_local_operation<TS, TI, TR>::interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged)
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
{
// .. nothing yet ..
}
@ -774,8 +817,33 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
}
}
for (std::set<unsigned int>::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
// locally merge the intruder edges if required
std::unordered_set<TI> merged_heap;
if (! m_other_is_merged && counting) {
EdgeBooleanClusterCollector<std::unordered_set<TI> > cluster_collector (&merged_heap, EdgeOr);
db::box_scanner<TI, size_t> merge_scanner;
for (std::set<unsigned int>::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) {
const TI *e = &interactions.intruder_shape (*j).second;
if (! e->is_degenerate ()) {
merge_scanner.insert (e, 0);
}
}
merge_scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
for (typename std::unordered_set<TI>::const_iterator e = merged_heap.begin (); e != merged_heap.end (); ++e) {
scanner.insert2 (e.operator-> (), 0);
}
} else {
for (std::set<unsigned int>::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
}
}
std::list<TR> heap;

View File

@ -224,7 +224,7 @@ class interacting_local_operation
: public local_operation<TS, TI, TR>
{
public:
interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count);
interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
@ -236,6 +236,7 @@ private:
bool m_touching;
bool m_inverse;
size_t m_min_count, m_max_count;
bool m_other_is_merged;
};
typedef interacting_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef> InteractingLocalOperation;
@ -264,7 +265,7 @@ class interacting_with_edge_local_operation
: public local_operation<TS, TI, TR>
{
public:
interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count);
interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
@ -274,6 +275,7 @@ public:
private:
bool m_inverse;
size_t m_min_count, m_max_count;
bool m_other_is_merged;
};
typedef interacting_with_edge_local_operation<db::PolygonRef, db::Edge, db::PolygonRef> InteractingWithEdgeLocalOperation;

View File

@ -23,6 +23,52 @@ module DRC
# @code
# out = in.drc((width < 2.0).polygons)
# @/code
#
# The following global functions are relevant for the DRC expressions:
#
# @ul
# @li \global#angle @/li
# @li \global#area @/li
# @li \global#bbox_height @/li
# @li \global#bbox_max @/li
# @li \global#bbox_min @/li
# @li \global#bbox_width @/li
# @li \global#case @/li
# @li \global#corners @/li
# @li \global#covering @/li
# @li \global#enc @/li
# @li \global#enclosing @/li
# @li \global#extent_refs @/li
# @li \global#extents @/li
# @li \global#foreign @/li
# @li \global#holes @/li
# @li \global#hulls @/li
# @li \global#if_all @/li
# @li \global#if_any @/li
# @li \global#if_none @/li
# @li \global#inside @/li
# @li \global#interacting @/li
# @li \global#iso @/li
# @li \global#length @/li
# @li \global#middle @/li
# @li \global#notch @/li
# @li \global#odd_polygons @/li
# @li \global#outside @/li
# @li \global#overlap @/li
# @li \global#overlapping @/li
# @li \global#perimeter @/li
# @li \global#primary @/li
# @li \global#rectangles @/li
# @li \global#rectilinear @/li
# @li \global#rounded_corners @/li
# @li \global#secondary @/li
# @li \global#separation @/li
# @li \global#sep @/li
# @li \global#sized @/li
# @li \global#smoothed @/li
# @li \global#space @/li
# @li \global#width @/li
# @/ul
#
# The following documentation will list the methods available for DRC expression objects.
@ -939,6 +985,34 @@ CODE
end
end
%w(covering overlapping interacting).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
other = @engine._make_node(other)
if ! other.is_a?(DRCOpNode)
raise("Argument " + other.to_s + " to #{f} must be a DRC expression")
end
DRCOpNodeInteractingWithCount::new(@engine, self, other, :#{f})
end
end
CODE
end
%w(inside outside).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
other = @engine._make_node(other)
if ! other.is_a?(DRCOpNode)
raise("Argument " + other.to_s + " to #{f} must be a DRC expression")
end
DRCOpNodeInteracting::new(@engine, self, other, :#{f})
end
end
CODE
end
end
class DRCOpNodeLogicalBool < DRCOpNode
@ -1410,7 +1484,7 @@ class DRCOpNodeInteractingWithCount < DRCOpNodeWithCompare
args = [ self.a.create_node(cache), self.b.create_node(cache), self.inverse ]
args << (self.gt ? self.gt + 1 : (self.ge ? self.ge : 0))
if self.lt || self.le
args << (self.lt ? self.lt : self.le + 1)
args << (self.lt ? self.lt - 1 : self.le)
end
factory = { :covering => :new_enclosing,
:overlapping => :new_overlapping,

View File

@ -52,18 +52,143 @@ module DRC
# 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.
# check for less than 0.5.um on the primary shapes. It uses the \global#width operator:
#
# @code
# out = in.drc(width < 0.5.um)
# @/code
#
# Another example computes a boolean AND between two layers before selecting
# the result polygons with an area larger than 1 square micrometer:
# Other single or double-bounded conditions are available too, for example:
#
# @code
# other = ... another layer ..
# out = in.drc((primary & other).area > 1.0)
# out = in.drc(width <= 0.5.um)
# out = in.drc(width > 0.5.um)
# out = in.drc(width == 0.5.um)
# out = in.drc(width != 0.5.um)
# out = in.drc(0.2.um < width < 0.5.um)
# @/code
#
# To specify the second input for a two-layer check, specify the second input
# with the check function. Here a two-layer separation check is used (\global#separation):
#
# @code
# l1 = input(1, 0)
# l2 = input(2, 0)
# out = l1.drc(separation(l2) < 0.5.um)
# @/code
#
# The second input of this check function can be a computed expression. In this
# case the local loop will first evaluate the expression for the second input and
# then use it inside the check.
#
# Options for the checks are also specified inside the brackets. For example,
# to specify a projection metrics for width use:
#
# @code
# out = in.drc(width(projection) < 0.5.um)
# @/code
#
# The "drc" function supports filter operators. These select input or derived polygons
# based on their properties. These filters are:
#
# @ul
# @li "\global#area": select polygons based on their area @/li
# @li "\global#perimeter": select polygons based on their perimeter @/li
# @li "\global#bbox_min", "\global#bbox_max", "\global#bbox_width", "\global#bbox_height": select polygons based on their bounding box properties @/li
# @/ul
#
# For example, to select polygons with an area larger than one square micrometer, use:
#
# @code
# out = in.drc(area > 1.0)
# @/code
#
# For the condition, use the usual numerical bounds like:
#
# @code
# out = in.drc(area == 1.0)
# out = in.drc(area <= 1.0)
# out = in.drc(0.2 < area < 1.0)
# @/code
#
# The result of the area operation is the input polygon if the area condition is met.
#
# In the same fashion, "perimeter" applies to the perimeter of the polygon.
# "bbox_min" etc. will evaluate a particular dimensions of the polygon's bounding box and
# use the respective dimension for filtering the polygon.
#
# Note that it's basically possible to use the polygon filters on any kind of input.
# In fact, plain "area" for example is a shortcut for "\global#primary.area" indicating that
# the area of primary shapes are supposed to be computed.
# However, any input other than the primary is not necessarily complete or it may
# consist of multiple polygons. Hence the computed values may be too big or too small.
# It's recommended therefore to use the measurement functions on primary polygons
# only.
#
# The "drc" feature also supports some predicates. "predicates" are boolean values
# indicating a certain condition. A predicate filter works in a way that it only
# passes the polygons
# The predicates available currently are:
#
# @ul
# @li "\global#rectangles": Filters rectangles @/li
# @li "\global#rectilinear": Filters rectilinear ("Manhattan") polygons @/li
# @/ul
#
# For the same reason as explained above, it's recommended to use these predicates
# standalone, so they act on primary shapes. It's possible to use the predicates
# on computed shapes or secondary input, but that may not render the desired results.
#
# The "!" operator will evaluate the expression behind it and return the
# current primary shape if the input is empty and return an empty polygon set
# if not. Hence the following filter will deliver all polygons which are
# not rectangles:
#
# @code
# out = in.drc(! rectangles)
# @/code
#
# The logical "if_any" or "if_all" statements allow connecting multiple
# conditions and evaluate to "true" (means: a non-empty shape set) if either
# on input is a non-empty shape set ("if_any") or if all inputs are non-empty
# ("if_all"). For example, this will select all polygons which are rectangles
# and whose area is larger than 20 quare micrometers:
#
# @code
# out = in.drc(if_all(rectangles, area > 20.0))
# @/code
#
# In fact, "if_all" renders the result of the last expression, provided all
# previous ones are non-empty. So this operation will render rectangles
# sized by 100 nm and skip all other types of polygons:
#
# @code
# out = in.drc(if_all(rectangles, sized(100.nm)))
# @/code
#
# Contrary to this, the "if_any" operation will render the first non-empty
# expression result and skip the following ones. So this example will
# size all rectangles by 100 nm and leave all other types of polygons
# untouched:
#
# @code
# out = in.drc(if_any(rectangles.sized(100.nm), primary))
# @/code
#
#
# The "drc" operations feature polygon manipulations where the input is
# either the primary polygon or derived shapes.
# Manipulations include sizing ("\global#sized"), corner rounding ("\global#rounded_corners"), smoothing ("\global#smoothed")
# and boolean operations.
#
# This example computes a boolean AND between two layers before selecting
# the result polygons with an area larger than 1 square micrometer. Note that
# "primary" is a placeholder for the primary shape:
#
# @code
# l1 = input(1, 0)
# l2 = input(2, 0)
# out = l1.drc((primary & l2).area > 1.0)
# @/code
#
# This example demonstrates how the "drc" operation can improve performance: as the
@ -71,7 +196,64 @@ module DRC
# 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.
# Note that the precise form of the example above is
#
# @code
# out = l1.drc((primary & secondary(l2)).area > 1.0)
# @/code
#
# The "\global#secondar" operator indicates that "l2" is to be used as secondary input to the "drc" function. Only
# in this form, the operators of the boolean AND can be reversed:
#
# @code
# out = l1.drc((secondary(l2) & primary).area > 1.0)
# @/code
#
# The expression inside the "drc" function is a Ruby object and can be
# stored in variables. If you need the same expression multiple times, it can be
# more efficient to use the same Ruby object. In this example, the same expression
# is used two times. Hence it's computed two times:
#
# @code
# out = l1.drc(((primary & l2).area == 1.0) + ((primary & l2).area == 2.0))
# @/code
#
# A more efficient version is:
#
# @code
# overlap_area = (primary & l2).area
# out = l1.drc((overlap_area == 1.0) + (overlap_area == 2.0))
# @/code
#
# Note that the first line prepares the operation, but does not execute the area computation
# or the boolean operation. But when the "drc" function executes the operation it will
# only compute the area once as it is represented by the same Ruby object.
#
#
# The "drc" functionality also offers support for edge pairs and edges. Edge pairs
# are the results of check operations and can be turned into polygons using the
# "polygons" method:
#
# @code
# drc = in.drc((width < 0.5.um).polygons)
# @/code
#
# Similarly, polygons can be converted into edges:
#
# @code
# drc = in.drc(primary.edges)
# @/code
#
# The "drc" framework supports edge vs. edge and edge vs. polygon booleans, edge
# filters (\global#length, \global#angle), edge vs. polygon interactions (\global#interacting, \global#overlapping),
# edge sampling (\global#start_segments, \global#centers, \global#end_segments) and edge to polygon
# conversions (\global#extended, \global#extended_in, \global#extended_out). Edge pairs
# can be converted into polygons and edges and separated into first and second edges (\global#first_edges,
# \global#second_edges).
#
#
# The bottom line is: DRC expressions are quite rich and there is a lot more to be said and written.
# More formal details about the bits and pieces can be found in the \DRC# class documentation.
def drc(op)
@engine._context("drc") do
@ -564,12 +746,8 @@ CODE
# @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
# 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 \Layer#drc).
@ -593,32 +771,40 @@ CODE
# @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.
#
# When using this method with a count, the operation may not render
# the correct results if the other input is not merged. By nature of the
# generic DRC feature, only those shapes that interact with the primary shape
# will be selected. If the other input is split into multiple polygons,
# not all components may be captured and the computed interaction count
# may be incorrect.
# %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.
#
# When using this method with a count, the operation may not render
# the correct results if the other input is not merged. By nature of the
# generic DRC feature, only those shapes that interact with the primary shape
# will be selected. If the other input is split into multiple polygons,
# not all components may be captured and the computed interaction count
# may be incorrect.
# %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
# 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 \Layer#drc).
@ -626,12 +812,8 @@ CODE
# @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
# 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 \Layer#drc).
@ -642,9 +824,8 @@ CODE
outside
overlapping
).each do |f|
# NOTE: these methods are fallback for the respective global ones which route to DRCLayer or here.
eval <<"CODE"
def _cop_#{f}(other)
def #{f}(other)
primary.#{f}(other)
end
CODE
@ -674,6 +855,7 @@ 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(0.1.um <= enclosing(other) < 0.2.um)
# @/code
#
@ -728,6 +910,7 @@ 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(0.1.um <= width < 0.2.um)
# @/code
#

View File

@ -1579,7 +1579,6 @@ CODE
bbox
centers
corners
covering
end_segments
extended
extended_in
@ -1591,9 +1590,7 @@ CODE
holes
hulls
in
inside
inside_part
interacting
intersections
iso
isolated
@ -1619,9 +1616,7 @@ CODE
ongrid
or
output
outside
outside_part
overlapping
perimeter
pull_inside
pull_interacting

View File

@ -188,3 +188,13 @@ TEST(12d)
{
run_test (_this, "12", true);
}
TEST(13)
{
run_test (_this, "13", false);
}
TEST(13d)
{
run_test (_this, "13", true);
}

View File

@ -25,6 +25,52 @@ renders edge pairs. To obtain polygons from these edge pairs, use the "polygons"
out = in.drc((width &lt; 2.0).polygons)
</pre>
</p><p>
The following global functions are relevant for the DRC expressions:
</p><p>
<ul>
<li><a href="/about/drc_ref_global.xml#case">global#case</a> </li>
<li><a href="/about/drc_ref_global.xml#secondary">global#secondary</a> </li>
<li><a href="/about/drc_ref_global.xml#primary">global#primary</a> </li>
<li><a href="/about/drc_ref_global.xml#foreign">global#foreign</a> </li>
<li><a href="/about/drc_ref_global.xml#if_all">global#if_all</a> </li>
<li><a href="/about/drc_ref_global.xml#if_any">global#if_any</a> </li>
<li><a href="/about/drc_ref_global.xml#if_none">global#if_none</a> </li>
<li><a href="/about/drc_ref_global.xml#bbox_height">global#bbox_height</a> </li>
<li><a href="/about/drc_ref_global.xml#bbox_width">global#bbox_width</a> </li>
<li><a href="/about/drc_ref_global.xml#bbox_max">global#bbox_max</a> </li>
<li><a href="/about/drc_ref_global.xml#bbox_min">global#bbox_min</a> </li>
<li><a href="/about/drc_ref_global.xml#area">global#area</a> </li>
<li><a href="/about/drc_ref_global.xml#hulls">global#hulls</a> </li>
<li><a href="/about/drc_ref_global.xml#holes">global#holes</a> </li>
<li><a href="/about/drc_ref_global.xml#odd_polygons">global#odd_polygons</a> </li>
<li><a href="/about/drc_ref_global.xml#perimeter">global#perimeter</a> </li>
<li><a href="/about/drc_ref_global.xml#rectangles">global#rectangles</a> </li>
<li><a href="/about/drc_ref_global.xml#rectilinear">global#rectilinear</a> </li>
<li><a href="/about/drc_ref_global.xml#length">global#length</a> (in condition) </li>
<li><a href="/about/drc_ref_global.xml#angle">global#angle</a> (in condition) </li>
<li><a href="/about/drc_ref_global.xml#corners">global#corners</a> </li>
<li><a href="/about/drc_ref_global.xml#extent_refs">global#extent_refs</a> </li>
<li><a href="/about/drc_ref_global.xml#extents">global#extents</a> </li>
<li><a href="/about/drc_ref_global.xml#middle">global#middle</a> </li>
<li><a href="/about/drc_ref_global.xml#rounded_corners">global#rounded_corners</a> </li>
<li><a href="/about/drc_ref_global.xml#sized">global#sized</a> </li>
<li><a href="/about/drc_ref_global.xml#smoothed">global#smoothed</a> </li>
<li><a href="/about/drc_ref_global.xml#covering">global#covering</a> </li>
<li><a href="/about/drc_ref_global.xml#interacting">global#interacting</a> </li>
<li><a href="/about/drc_ref_global.xml#overlapping">global#overlapping</a> </li>
<li><a href="/about/drc_ref_global.xml#inside">global#inside</a> </li>
<li><a href="/about/drc_ref_global.xml#outside">global#outside</a> </li>
<li><a href="/about/drc_ref_global.xml#enclosing">global#enclosing</a> </li>
<li><a href="/about/drc_ref_global.xml#separation">global#separation</a> </li>
<li><a href="/about/drc_ref_global.xml#overlap">global#overlap</a> </li>
<li><a href="/about/drc_ref_global.xml#width">global#width</a> </li>
<li><a href="/about/drc_ref_global.xml#space">global#space</a> </li>
<li><a href="/about/drc_ref_global.xml#notch">global#notch</a> </li>
<li><a href="/about/drc_ref_global.xml#iso">global#iso</a> </li>
<li><a href="/about/drc_ref_global.xml#sep">global#sep</a> </li>
<li><a href="/about/drc_ref_global.xml#enc">global#enc</a> </li>
</ul>
</p><p>
The following documentation will list the methods available for DRC expression objects.
</p>
<h2-index/>

58
testdata/drc/drcGenericTests_13.drc vendored Normal file
View File

@ -0,0 +1,58 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
l2 = input(2, 0)
l3 = input(3, 0)
l1.output(1, 0)
l2.output(2, 0)
l3.output(3, 0)
l2.drc(covering(l1)).output(100, 0)
l2.drc(! covering(l1)).output(101, 0)
l1.drc(interacting(l2)).output(110, 0)
l1.drc(! interacting(l2)).output(111, 0)
l1.drc(interacting(l2) >= 2).output(112, 0)
l1.drc(interacting(l2) < 2).output(113, 0)
l1.drc(overlapping(l2)).output(120, 0)
l1.drc(! overlapping(l2)).output(121, 0)
l1.drc(overlapping(l2) >= 2).output(122, 0)
l1.drc(overlapping(l2) < 2).output(123, 0)
l1.drc(outside(l2)).output(130, 0)
l1.drc(! outside(l2)).output(131, 0)
l1.drc(inside(l2)).output(140, 0)
l1.drc(! inside(l2)).output(141, 0)
l2e = secondary(l2).edges
l1e = primary.edges
# Secondary edges are supported, but as secondaries are not merged
# internally, the result is not well defined for unmerged secondary:
l1.drc(interacting(l2e)).output(200, 0)
l1.drc(! interacting(l2e)).output(201, 0)
l1.drc(interacting(l2e) >= 4).output(202, 0)
l1.drc(interacting(l2e) < 4).output(203, 0)
# TODO: edge-to-polygon interactions and edge-to-edge interactions not supported yet
# l1.drc(l1e.interacting(l2)).output(210, 0)
# l1.drc(! l1e.interacting(l2)).output(211, 0)
# l1.drc(l1e.interacting(l2) >= 2).output(212, 0)
# l1.drc(l1e.interacting(l2) < 2).output(213, 0)
# l1.drc(l1e.interacting(l2e)).output(210, 0)
# l1.drc(! l1e.interacting(l2e)).output(211, 0)
# l1.drc(l1e.interacting(l2e) >= 2).output(212, 0)
# l1.drc(l1e.interacting(l2e) < 2).output(213, 0)

BIN
testdata/drc/drcGenericTests_13.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcGenericTests_au13.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcGenericTests_au13d.gds vendored Normal file

Binary file not shown.