diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 4f88ae245..c7927afcf 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -545,7 +545,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo return clone (); } else if (max_count < min_count || other.empty ()) { // clear, if b is empty and - // * mode is inside or interacting and inverse is false ("inside" or "interacting") + // * mode is inside, enclosing or interacting and inverse is false ("inside" or "interacting") // * mode is outside and inverse is true ("not outside") if ((mode <= 0) != inverse) { return new EmptyRegion (); @@ -586,7 +586,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo if (mode < 0) { - // NOTE: on "inside", the other region must be merged + // NOTE: on "inside" or "enclosing", the other region must be merged for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) { if (p->box ().touches (bbox ())) { ep.insert (*p, nstart); @@ -609,8 +609,8 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo // with counting we need to separate the other polygons by different properties - // can only have min_count/max_count in interact mode - tl_assert (mode == 0); + // cannot only have min_count/max_count in outside mode + tl_assert (mode <= 0); for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) { if (p->box ().touches (bbox ())) { @@ -621,6 +621,9 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo } + // there should be at least one element to look at for primary + tl_assert (nstart > 0); + size_t n = nstart; for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { if (mode > 0 || p->box ().touches (other.bbox ())) { @@ -628,7 +631,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo } } - db::InteractionDetector id (mode, 0); + db::InteractionDetector id (mode, nstart - 1); id.set_include_touching (touching); db::EdgeSink es; ep.process (es, id); diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index 2ec96546b..3d92b1b52 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -188,6 +188,16 @@ public: return selected_interacting_generic (other, -1, true, true); } + virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, -2, true, false, min_count, max_count); + } + + virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, -2, true, true, min_count, max_count); + } + virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const { return selected_interacting_generic (other, 0, true, false, min_count, max_count); @@ -218,14 +228,14 @@ public: return selected_interacting_generic (other, true, min_count, max_count); } - virtual RegionDelegate *selected_overlapping (const Region &other) const + virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, 0, false, false); + return selected_interacting_generic (other, 0, false, false, min_count, max_count); } - virtual RegionDelegate *selected_not_overlapping (const Region &other) const + virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, 0, false, true); + return selected_interacting_generic (other, 0, false, true, min_count, max_count); } virtual RegionDelegate *pull_inside (const Region &other) const diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index 8e5836351..25021a0e4 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -628,13 +628,13 @@ bool EdgePolygonOp::selects_edges () const // ------------------------------------------------------------------------------- // InteractionDetector implementation -InteractionDetector::InteractionDetector (int mode, property_type container_id) - : m_mode (mode), m_include_touching (true), m_container_id (container_id) +InteractionDetector::InteractionDetector (int mode, property_type primary_id) + : m_mode (mode), m_include_touching (true), m_last_primary_id (primary_id) { // .. nothing yet .. } -void +void InteractionDetector::reset () { m_wcv_n.clear (); @@ -675,39 +675,64 @@ InteractionDetector::edge (bool north, bool enter, property_type p) inside->erase (p); - if (m_mode != 0) { - - // the container objects are delivered last of all coincident edges - // (due to prefer_touch == true and the sorting of coincident edges by property id) - // hence every remaining parts count as non-interacting (outside) - if (p == m_container_id) { + if (m_mode < -1) { + // in enclosing mode report primaries open after a secondary ended as non-interactions: these only partially + // overlap and the outside part qualifies this secondary as non-closing (see "finish") + if (p > m_last_primary_id) { for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { - if (*i != m_container_id) { + if (*i <= m_last_primary_id) { + m_non_interactions.insert (*i); + } + } + } + } else if (m_mode != 0) { + // the primary objects are delivered last of all coincident edges + // (due to prefer_touch == true and the sorting of coincident edges by property id) + // hence every remaining parts count as non-interacting (outside) + if (p <= m_last_primary_id) { + for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { + if (*i > m_last_primary_id) { m_non_interactions.insert (*i); } } } - } } else if (inside_after > inside_before) { if (m_mode != 0) { - // in inside/outside mode we are only interested in interactions with the container_id property - if (p != m_container_id) { - // note that the container parts will be delivered first of all coincident - // edges hence we can check whether the container is present even for coincident - // edges - if (inside->find (m_container_id) != inside->end ()) { - m_interactions.insert (std::make_pair (m_container_id, p)); + // in enclosing/inside/outside mode we are only interested in interactions with a primary + if (p > m_last_primary_id) { + + if (m_mode < -1) { + // enclosing mode: report primaries open when a secondary starts as non-interactions: these only partially + // overlap and the outside part qualifies this secondary as non-closing (see "finish") + for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { + if (*i <= m_last_primary_id) { + m_non_interactions.insert (*i); + } + } } else { - m_non_interactions.insert (p); + // note that the primary parts will be delivered first of all coincident + // edges hence we can check whether the primary is present even for coincident + // edges + bool any = false; + for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { + if (*i <= m_last_primary_id) { + any = true; + m_interactions.insert (std::make_pair (*i, p)); + } + } + if (! any) { + m_non_interactions.insert (p); + } } + } else { for (std::set ::const_iterator i = inside->begin (); i != inside->end (); ++i) { - if (*i != m_container_id) { - m_interactions.insert (std::make_pair (m_container_id, *i)); + if (*i > m_last_primary_id) { + m_interactions.insert (std::make_pair (p, *i)); } } } @@ -750,14 +775,36 @@ InteractionDetector::compare_ns () const void InteractionDetector::finish () { - if (m_mode < 0) { + if (m_mode < -1) { - // In inside mode remove those objects which have a non-interaction with the container_id property - for (std::set::const_iterator p = m_non_interactions.begin (); p != m_non_interactions.end (); ++p) { - m_interactions.erase (std::make_pair (m_container_id, *p)); + // In enclosing mode remove those objects which have an interaction with a primary having a non-interaction + std::set secondaries_to_delete; + for (std::set >::iterator i = m_interactions.begin (); i != m_interactions.end (); ++i) { + if (i->first <= m_last_primary_id && m_non_interactions.find (i->first) != m_non_interactions.end ()) { + secondaries_to_delete.insert (i->second); + } } - m_non_interactions.clear (); + for (std::set >::iterator i = m_interactions.begin (); i != m_interactions.end (); ) { + std::set >::iterator ii = i; + ++ii; + if (i->first <= m_last_primary_id && secondaries_to_delete.find (i->second) != secondaries_to_delete.end ()) { + m_interactions.erase (i); + } + i = ii; + } + + } else if (m_mode == -1) { + + // In inside mode remove those objects which have a non-interaction with a primary + for (std::set >::iterator i = m_interactions.begin (); i != m_interactions.end (); ) { + std::set >::iterator ii = i; + ++ii; + if (i->first <= m_last_primary_id && m_non_interactions.find (i->second) != m_non_interactions.end ()) { + m_interactions.erase (i); + } + i = ii; + } } else if (m_mode > 0) { @@ -768,13 +815,12 @@ InteractionDetector::finish () m_interactions.clear (); for (std::set::const_iterator p = m_non_interactions.begin (); p != m_non_interactions.end (); ++p) { - m_interactions.insert (m_interactions.end (), std::make_pair (m_container_id, *p)); + m_interactions.insert (m_interactions.end (), std::make_pair (m_last_primary_id, *p)); } - m_non_interactions.clear (); - } + m_non_interactions.clear (); } // ------------------------------------------------------------------------------- diff --git a/src/db/db/dbEdgeProcessor.h b/src/db/db/dbEdgeProcessor.h index d1d000638..40ed4fcce 100644 --- a/src/db/db/dbEdgeProcessor.h +++ b/src/db/db/dbEdgeProcessor.h @@ -234,6 +234,7 @@ public: * The mode parameter selects the interaction check mode. * 0 is "overlapping". * -1 will select all polygons inside polygons from the other layer. + * -2 will select all polygons enclosing polygons from the other layer. * +1 will select all polygons outside polygons from the other layer. * * In mode -1 and +1, finish () needs to be called before the interactions @@ -242,16 +243,19 @@ public: * input polygons (property != reference property). In mode +1 these are * pseudo-interactions, because "outside" by definition means non-interacting. * - * Mode -1 (inside) and +1 (outside) requires a single property value for the containing region. - * This property value must be specified in the container_id parameter. - * For correct operation, the container_id must be the lowest property ID and - * the interacting objects must have higher property id's. - * The reported interactions will be (container_id,polygon_id) even for outside mode. + * Mode -1 (inside) and +1 (outside) requires a property value for the containing (primary) region. + * Property IDs from 0 to the given last primary ID value are considered to belong to + * the primary region. + * This last property ID must be specified in the last_primary_id parameter. + * For correct operation, the secondary input must use property IDs bigger than + * last_primary_id. + * The reported interactions will be (primary_id,polygon_id) even for outside mode. + * For outside mode, the primary_id is always last_primary_id. * - * For mode 0, property ids <= container_id are considered to belong to the first + * For mode 0, property ids <= last_primary_id are considered to belong to the first * container and property ids > container_id to the second container. */ - InteractionDetector (int mode = 0, property_type container_id = 0); + InteractionDetector (int mode = 0, property_type primary_id = 0); /** * @brief Sets the "touching" flag @@ -308,7 +312,7 @@ public: private: int m_mode; bool m_include_touching; - property_type m_container_id; + property_type m_last_primary_id; std::vector m_wcv_n, m_wcv_s; std::set m_inside_n, m_inside_s; std::set > m_interactions; diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index b868b95bb..373d3e7f2 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -110,14 +110,16 @@ public: virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_not_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_not_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); } virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); } diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 6bb510914..0cf15700f 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1178,6 +1178,52 @@ public: return Region (mp_delegate->selected_not_inside (other)); } + /** + * @brief Returns all polygons of this which are enclosing polygons from the other region + * + * Merged semantics applies. + */ + Region &select_enclosing (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) + { + set_delegate (mp_delegate->selected_enclosing (other, min_count, max_count)); + return *this; + } + + /** + * @brief Returns all polygons of this which are not enclosing polygons from the other region + * + * Merged semantics applies. + */ + Region &select_not_enclosing (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) + { + set_delegate (mp_delegate->selected_not_enclosing (other, min_count, max_count)); + return *this; + } + + /** + * @brief Returns all polygons of this which are enclosing polygons from the other region + * + * This method is an out-of-place version of select_enclosing. + * + * Merged semantics applies. + */ + Region selected_enclosing (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + return Region (mp_delegate->selected_enclosing (other, min_count, max_count)); + } + + /** + * @brief Returns all polygons of this which are not enclosing polygons from the other region + * + * This method is an out-of-place version of select_not_enclosing. + * + * Merged semantics applies. + */ + Region selected_not_enclosing (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + return Region (mp_delegate->selected_not_enclosing (other, min_count, max_count)); + } + /** * @brief Selects all polygons of this region which overlap or touch polygons from the other region * @@ -1329,9 +1375,9 @@ public: * * Merged semantics applies. */ - Region &select_overlapping (const Region &other) + Region &select_overlapping (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) { - set_delegate (mp_delegate->selected_overlapping (other)); + set_delegate (mp_delegate->selected_overlapping (other, min_count, max_count)); return *this; } @@ -1340,9 +1386,9 @@ public: * * Merged semantics applies. */ - Region &select_not_overlapping (const Region &other) + Region &select_not_overlapping (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) { - set_delegate (mp_delegate->selected_not_overlapping (other)); + set_delegate (mp_delegate->selected_not_overlapping (other, min_count, max_count)); return *this; } @@ -1353,9 +1399,9 @@ public: * * Merged semantics applies. */ - Region selected_overlapping (const Region &other) const + Region selected_overlapping (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const { - return Region (mp_delegate->selected_overlapping (other)); + return Region (mp_delegate->selected_overlapping (other, min_count, max_count)); } /** @@ -1365,9 +1411,9 @@ public: * * Merged semantics applies. */ - Region selected_not_overlapping (const Region &other) const + Region selected_not_overlapping (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const { - return Region (mp_delegate->selected_not_overlapping (other)); + return Region (mp_delegate->selected_not_overlapping (other, min_count, max_count)); } /** diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 87c9720da..4bcfcbd16 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -351,14 +351,16 @@ public: virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; virtual RegionDelegate *selected_inside (const Region &other) const = 0; virtual RegionDelegate *selected_not_inside (const Region &other) const = 0; + virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0; + virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0; - virtual RegionDelegate *selected_overlapping (const Region &other) const = 0; - virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0; + virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0; + virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *pull_inside (const Region &other) const = 0; virtual RegionDelegate *pull_interacting (const Region &other) const = 0; virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0; diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index e2998637e..fdef45336 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -466,7 +466,9 @@ void interacting_local_operation::compute_local (db::Layout * /*layo ep.insert (subject, n); } - db::InteractionDetector id (m_mode, 0); + tl_assert (nstart > 0); + + db::InteractionDetector id (m_mode, nstart - 1); id.set_include_touching (m_touching); db::EdgeSink es; ep.process (es, id); diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index cef6d37ba..7a162b28b 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -83,6 +83,19 @@ static db::CompoundRegionOperationNode *new_overlapping (db::CompoundRegionOpera } } +static db::CompoundRegionOperationNode *new_enclosing (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count) +{ + // TODO: is this correct? + if (a->result_type () != db::CompoundRegionOperationNode::Region) { + throw tl::Exception ("Primary input for interaction compound operation must be of Region type"); + } + if (b->result_type () == db::CompoundRegionOperationNode::Region) { + return new db::CompoundRegionInteractOperationNode (a, b, -2, false, inverse, min_count, max_count); + } else { + throw tl::Exception ("Secondary input for enclosing compound operation must be of Region type"); + } +} + static db::CompoundRegionOperationNode *new_inside (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse) { // TODO: is this correct? @@ -281,6 +294,9 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_overlapping", &new_overlapping, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits::max (), "unlimited"), "@brief Creates a node representing an overlapping selection operation between the inputs.\n" ) + + gsi::constructor ("new_enclosing", &new_enclosing, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits::max (), "unlimited"), + "@brief Creates a node representing an inside selection operation between the inputs.\n" + ) + gsi::constructor ("new_inside", &new_inside, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), "@brief Creates a node representing an inside selection operation between the inputs.\n" ) + diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 07eb2fd27..a71f871f9 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1406,6 +1406,42 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This operator adds the polygons of the other region to self. " "This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n" ) + + method ("enclosing", &db::Region::selected_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are completely enclosing polygons from the other region\n" + "\n" + "@return A new region containing the polygons which are enclosing polygons from the other region\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27." + ) + + method ("not_enclosing", &db::Region::selected_not_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are not completely enclosing polygons from the other region\n" + "\n" + "@return A new region containing the polygons which are not enclosing polygons from the other region\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27." + ) + + method ("select_enclosing", &db::Region::select_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Selects the polygons of this region which are completely enclosing polygons from the other region\n" + "\n" + "@return The region after the polygons have been selected (self)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27." + ) + + method ("select_not_enclosing", &db::Region::select_not_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Selects the polygons of this region which are not completely enclosing polygons from the other region\n" + "\n" + "@return The region after the polygons have been selected (self)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("inside", &db::Region::selected_inside, gsi::arg ("other"), "@brief Returns the polygons of this region which are completely inside polygons from the other region\n" "\n" @@ -1634,34 +1670,42 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method has been introduced in version 0.27\n" ) + - method ("overlapping", &db::Region::selected_overlapping, gsi::arg ("other"), + method ("overlapping", &db::Region::selected_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Returns the polygons of this region which overlap polygons from the other region\n" "\n" "@return A new region containing the polygons overlapping polygons from the other region\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "The count options have been introduced in version 0.27." ) + - method ("not_overlapping", &db::Region::selected_not_overlapping, gsi::arg ("other"), + method ("not_overlapping", &db::Region::selected_not_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Returns the polygons of this region which do not overlap polygons from the other region\n" "\n" "@return A new region containing the polygons not overlapping polygons from the other region\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" - ) + - method ("select_overlapping", &db::Region::select_overlapping, gsi::arg ("other"), + "\n" + "The count options have been introduced in version 0.27." + ) + + method ("select_overlapping", &db::Region::select_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons from this region which overlap polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" - ) + - method ("select_not_overlapping", &db::Region::select_not_overlapping, gsi::arg ("other"), + "\n" + "The count options have been introduced in version 0.27." + ) + + method ("select_not_overlapping", &db::Region::select_not_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons from this region which do not overlap polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" - ) + + "\n" + "The count options have been introduced in version 0.27." + ) + method ("pull_inside", &db::Region::pull_inside, gsi::arg ("other"), "@brief Returns all polygons of \"other\" which are inside polygons of this region\n" "The \"pull_...\" methods are similar to \"select_...\" but work the opposite way: they " diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index b54ef5689..14ca2ce0b 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -1418,10 +1418,90 @@ CODE # This method is available for polygon, edge and edge pair layers. An alias # is "\join". See there for a description of the function. + # %DRC% + # @name enclosing + # @brief Selects shapes or regions of self which completely enclose one or more shapes from the other region + # @synopsis layer.enclosing(other) + # @synopsis layer.enclosing(other, min_count) + # @synopsis layer.enclosing(other, min_count, max_count) + # @synopsis layer.enclosing(other, min_count .. max_count) + # This method selects all shapes or regions from self which enclose shapes from the other + # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, + # otherwise individual shapes are selected. + # It returns a new layer containing the selected shapes. A version which modifies self + # is \select_enclosing. + # + # This method is available for polygon and edge layers. Edges can be selected + # with respect to other edges or polygons. + # + # The following image shows the effect of the "enclosing" method: + # + # @table + # @tr + # @td @img(/images/drc_enclosing.png) @/td + # @/tr + # @/table + # + # A range of counts can be specified. If so, the shape from the primary layer is + # only selected when enclosing a given number of shapes from the other layer. + # For the interpretation of the count see \interacting. + + # %DRC% + # @name not_enclosing + # @brief Selects shapes or regions of self which do not enclose one or more shapes from the other region + # @synopsis layer.not_enclosing(other) + # @synopsis layer.not_enclosing(other, min_count) + # @synopsis layer.not_enclosing(other, min_count, max_count) + # @synopsis layer.not_enclosing(other, min_count .. max_count) + # This method selects all shapes or regions from self which do not enclose shapes from the other + # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, + # otherwise individual shapes are selected. This method returns the inverse of \enclosing + # and provides the same options. + # + # This method is available for polygon and edge layers. Edges can be selected + # with respect to other edges or polygons. + # It returns a new layer containing the selected shapes. A version which modifies self + # is \select_not_enclosing. + + # %DRC% + # @name select_enclosing + # @brief Selects shapes or regions of self which completely enclose one or more shapes from the other region + # @synopsis layer.select_enclosing(other) + # @synopsis layer.select_enclosing(other, min_count) + # @synopsis layer.select_enclosing(other, min_count, max_count) + # @synopsis layer.select_enclosing(other, min_count .. max_count) + # This method selects all shapes or regions from self which overlap shapes from the other + # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, + # otherwise individual shapes are selected. + # It modifies self to contain the selected shapes. A version which does not modify self + # is \enclosing. + # + # This method is available for polygon and edge layers. Edges can be selected + # with respect to other edges or polygons. + + # %DRC% + # @name select_not_enclosing + # @brief Selects shapes or regions of self which do not enclose one or more shapes from the other region + # @synopsis layer.select_not_enclosing(other) + # @synopsis layer.select_not_enclosing(other, min_count) + # @synopsis layer.select_not_enclosing(other, min_count, max_count) + # @synopsis layer.select_not_enclosing(other, min_count .. max_count) + # This method selects all shapes or regions from self which do not enclose shapes from the other + # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, + # otherwise individual shapes are selected. + # It modifies self to contain the selected shapes. A version which does not modify self + # is \not_enclosing. + # + # This method is available for polygon and edge layers. Edges can be selected + # with respect to other edges or polygons. + # %DRC% # @name overlapping # @brief Selects shapes or regions of self which overlap shapes from the other region # @synopsis layer.overlapping(other) + # @synopsis layer.overlapping(other, min_count) + # @synopsis layer.overlapping(other, min_count, max_count) + # @synopsis layer.overlapping(other, min_count .. max_count) # This method selects all shapes or regions from self which overlap shapes from the other # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, # otherwise individual shapes are selected. @@ -1438,17 +1518,25 @@ CODE # @td @img(/images/drc_overlapping.png) @/td # @/tr # @/table + # + # A range of counts can be specified. If so, the shape from the primary layer is + # only selected when overlapping a given number of shapes from the other layer. + # For the interpretation of the count see \interacting. # %DRC% # @name not_overlapping # @brief Selects shapes or regions of self which do not overlap shapes from the other region # @synopsis layer.not_overlapping(other) + # @synopsis layer.not_overlapping(other, min_count) + # @synopsis layer.not_overlapping(other, min_count, max_count) + # @synopsis layer.not_overlapping(other, min_count .. max_count) # This method selects all shapes or regions from self which do not overlap shapes from the other # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, - # otherwise individual shapes are selected. + # otherwise individual shapes are selected. This method will return the inverse of \overlapping + # and provides the same options. # - # The "not_overlapping" method is equivalent to the \outside method. It is provided - # as an alias for consistency. + # The "not_overlapping" method is similar to the \outside method. However, "outside" does + # not provide the option to specify counts. # # This method is available for polygon and edge layers. Edges can be selected # with respect to other edges or polygons. @@ -1459,6 +1547,9 @@ CODE # @name select_overlapping # @brief Selects shapes or regions of self which overlap shapes from the other region # @synopsis layer.select_overlapping(other) + # @synopsis layer.select_overlapping(other, min_count) + # @synopsis layer.select_overlapping(other, min_count, max_count) + # @synopsis layer.select_overlapping(other, min_count .. max_count) # This method selects all shapes or regions from self which overlap shapes from the other # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, # otherwise individual shapes are selected. @@ -1472,6 +1563,9 @@ CODE # @name select_not_overlapping # @brief Selects shapes or regions of self which do not overlap shapes from the other region # @synopsis layer.select_not_overlapping(other) + # @synopsis layer.select_not_overlapping(other, min_count) + # @synopsis layer.select_not_overlapping(other, min_count, max_count) + # @synopsis layer.select_not_overlapping(other, min_count .. max_count) # This method selects all shapes or regions from self which do not overlap shapes from the other # region. Unless self is in raw mode (see \raw), coherent regions are selected from self, # otherwise individual shapes are selected. @@ -1902,7 +1996,7 @@ CODE CODE end - %w(| ^ overlapping not_overlapping inside not_inside outside not_outside in not_in).each do |f| + %w(| ^ inside not_inside outside not_outside in not_in).each do |f| eval <<"CODE" def #{f}(other) requires_same_type(other, "#{f}") @@ -1974,7 +2068,34 @@ CODE CODE end - %w(overlapping not_overlapping inside not_inside outside not_outside).each do |fi| + %w(overlapping not_overlapping enclosing not_enclosing).each do |f| + eval <<"CODE" + def #{f}(other, *args) + requires_same_type(other, "#{f}") + requires_edges_or_region("#{f}") + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(:#{f}, *args))) + end +CODE + end + + %w(overlapping not_overlapping enclosing not_enclosing).each do |fi| + f = "select_" + fi + # In tiled mode, there are no modifying versions. Emulate using the non-modifying one. + eval <<"CODE" + def #{f}(other, *args) + requires_edges_or_region("#{f}") + requires_same_type(other, "#{f}") + if @engine.is_tiled? + self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(:#{fi}, *args)) + DRCLayer::new(@engine, self.data) + else + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(:#{f}, *args))) + end + end +CODE + end + + %w(inside not_inside outside not_outside).each do |fi| f = "select_" + fi # In tiled mode, there are no modifying versions. Emulate using the non-modifying one. eval <<"CODE" diff --git a/testdata/drc/drcSimpleTests_20.drc b/testdata/drc/drcSimpleTests_20.drc index c5c803995..7d96f6d6e 100644 --- a/testdata/drc/drcSimpleTests_20.drc +++ b/testdata/drc/drcSimpleTests_20.drc @@ -16,6 +16,12 @@ l1.interacting(l2, 1..2).output(102, 0) l1.interacting(l2, 2..).output(103, 0) l1.interacting(l2, 1, 2).output(104, 0) +l1.overlapping(l2, 1).output(110, 0) +l1.overlapping(l2, 2).output(111, 0) +l1.overlapping(l2, 1..2).output(112, 0) +l1.overlapping(l2, 2..).output(113, 0) +l1.overlapping(l2, 1, 2).output(114, 0) + l = l1.dup l.select_interacting(l2, 1) l.output(200, 0) @@ -32,12 +38,34 @@ l = l1.dup l.select_interacting(l2, 1, 2) l.output(204, 0) +l = l1.dup +l.select_overlapping(l2, 1) +l.output(210, 0) +l = l1.dup +l.select_overlapping(l2, 2) +l.output(211, 0) +l = l1.dup +l.select_overlapping(l2, 1..2) +l.output(212, 0) +l = l1.dup +l.select_overlapping(l2, 2..) +l.output(213, 0) +l = l1.dup +l.select_overlapping(l2, 1, 2) +l.output(214, 0) + l1.not_interacting(l2, 1).output(300, 0) l1.not_interacting(l2, 2).output(301, 0) l1.not_interacting(l2, 1..2).output(302, 0) l1.not_interacting(l2, 2..).output(303, 0) l1.not_interacting(l2, 1, 2).output(304, 0) +l1.not_overlapping(l2, 1).output(310, 0) +l1.not_overlapping(l2, 2).output(311, 0) +l1.not_overlapping(l2, 1..2).output(312, 0) +l1.not_overlapping(l2, 2..).output(313, 0) +l1.not_overlapping(l2, 1, 2).output(314, 0) + l = l1.dup l.select_not_interacting(l2, 1) l.output(400, 0) @@ -54,3 +82,19 @@ l = l1.dup l.select_not_interacting(l2, 1, 2) l.output(404, 0) +l = l1.dup +l.select_not_overlapping(l2, 1) +l.output(410, 0) +l = l1.dup +l.select_not_overlapping(l2, 2) +l.output(411, 0) +l = l1.dup +l.select_not_overlapping(l2, 1..2) +l.output(412, 0) +l = l1.dup +l.select_not_overlapping(l2, 2..) +l.output(413, 0) +l = l1.dup +l.select_not_overlapping(l2, 1, 2) +l.output(414, 0) + diff --git a/testdata/drc/drcSimpleTests_20.gds b/testdata/drc/drcSimpleTests_20.gds index 08618beb2..aab1a575c 100644 Binary files a/testdata/drc/drcSimpleTests_20.gds and b/testdata/drc/drcSimpleTests_20.gds differ diff --git a/testdata/drc/drcSimpleTests_au20.gds b/testdata/drc/drcSimpleTests_au20.gds index 77c6d5bfc..7607a2253 100644 Binary files a/testdata/drc/drcSimpleTests_au20.gds and b/testdata/drc/drcSimpleTests_au20.gds differ