WIP: DRC 'enclosing' feature

This commit is contained in:
Matthias Koefferlein 2020-12-07 22:48:03 +01:00
parent ca388150bb
commit 5934bd529f
14 changed files with 411 additions and 71 deletions

View File

@ -545,7 +545,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
return clone (); return clone ();
} else if (max_count < min_count || other.empty ()) { } else if (max_count < min_count || other.empty ()) {
// clear, if b is empty and // 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") // * mode is outside and inverse is true ("not outside")
if ((mode <= 0) != inverse) { if ((mode <= 0) != inverse) {
return new EmptyRegion (); return new EmptyRegion ();
@ -586,7 +586,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
if (mode < 0) { 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) { for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) { if (p->box ().touches (bbox ())) {
ep.insert (*p, nstart); 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 // with counting we need to separate the other polygons by different properties
// can only have min_count/max_count in interact mode // cannot only have min_count/max_count in outside mode
tl_assert (mode == 0); tl_assert (mode <= 0);
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) { for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) { 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; size_t n = nstart;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
if (mode > 0 || p->box ().touches (other.bbox ())) { 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); id.set_include_touching (touching);
db::EdgeSink es; db::EdgeSink es;
ep.process (es, id); ep.process (es, id);

View File

@ -188,6 +188,16 @@ public:
return selected_interacting_generic (other, -1, true, true); 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 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); 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); 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 virtual RegionDelegate *pull_inside (const Region &other) const

View File

@ -628,8 +628,8 @@ bool EdgePolygonOp::selects_edges () const
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
// InteractionDetector implementation // InteractionDetector implementation
InteractionDetector::InteractionDetector (int mode, property_type container_id) InteractionDetector::InteractionDetector (int mode, property_type primary_id)
: m_mode (mode), m_include_touching (true), m_container_id (container_id) : m_mode (mode), m_include_touching (true), m_last_primary_id (primary_id)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -675,39 +675,64 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
inside->erase (p); inside->erase (p);
if (m_mode != 0) { if (m_mode < -1) {
// in enclosing mode report primaries open after a secondary ended as non-interactions: these only partially
// the container objects are delivered last of all coincident edges // overlap and the outside part qualifies this secondary as non-closing (see "finish")
// (due to prefer_touch == true and the sorting of coincident edges by property id) if (p > m_last_primary_id) {
// hence every remaining parts count as non-interacting (outside)
if (p == m_container_id) {
for (std::set <property_type>::const_iterator i = inside->begin (); i != inside->end (); ++i) { for (std::set <property_type>::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 <property_type>::const_iterator i = inside->begin (); i != inside->end (); ++i) {
if (*i > m_last_primary_id) {
m_non_interactions.insert (*i); m_non_interactions.insert (*i);
} }
} }
} }
} }
} else if (inside_after > inside_before) { } else if (inside_after > inside_before) {
if (m_mode != 0) { if (m_mode != 0) {
// in inside/outside mode we are only interested in interactions with the container_id property // in enclosing/inside/outside mode we are only interested in interactions with a primary
if (p != m_container_id) { if (p > m_last_primary_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 if (m_mode < -1) {
// edges // enclosing mode: report primaries open when a secondary starts as non-interactions: these only partially
if (inside->find (m_container_id) != inside->end ()) { // overlap and the outside part qualifies this secondary as non-closing (see "finish")
m_interactions.insert (std::make_pair (m_container_id, p)); for (std::set <property_type>::const_iterator i = inside->begin (); i != inside->end (); ++i) {
} else { if (*i <= m_last_primary_id) {
m_non_interactions.insert (p); m_non_interactions.insert (*i);
}
} }
} else { } else {
// 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 <property_type>::const_iterator i = inside->begin (); i != inside->end (); ++i) { for (std::set <property_type>::const_iterator i = inside->begin (); i != inside->end (); ++i) {
if (*i != m_container_id) { if (*i <= m_last_primary_id) {
m_interactions.insert (std::make_pair (m_container_id, *i)); any = true;
m_interactions.insert (std::make_pair (*i, p));
}
}
if (! any) {
m_non_interactions.insert (p);
}
}
} else {
for (std::set <property_type>::const_iterator i = inside->begin (); i != inside->end (); ++i) {
if (*i > m_last_primary_id) {
m_interactions.insert (std::make_pair (p, *i));
} }
} }
} }
@ -750,14 +775,36 @@ InteractionDetector::compare_ns () const
void void
InteractionDetector::finish () 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 // In enclosing mode remove those objects which have an interaction with a primary having a non-interaction
for (std::set<property_type>::const_iterator p = m_non_interactions.begin (); p != m_non_interactions.end (); ++p) { std::set<property_type> secondaries_to_delete;
m_interactions.erase (std::make_pair (m_container_id, *p)); for (std::set<std::pair<property_type, property_type> >::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<std::pair<property_type, property_type> >::iterator i = m_interactions.begin (); i != m_interactions.end (); ) {
std::set<std::pair<property_type, property_type> >::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<std::pair<property_type, property_type> >::iterator i = m_interactions.begin (); i != m_interactions.end (); ) {
std::set<std::pair<property_type, property_type> >::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) { } else if (m_mode > 0) {
@ -768,13 +815,12 @@ InteractionDetector::finish ()
m_interactions.clear (); m_interactions.clear ();
for (std::set<property_type>::const_iterator p = m_non_interactions.begin (); p != m_non_interactions.end (); ++p) { for (std::set<property_type>::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 ();
}
} }
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------

View File

@ -234,6 +234,7 @@ public:
* The mode parameter selects the interaction check mode. * The mode parameter selects the interaction check mode.
* 0 is "overlapping". * 0 is "overlapping".
* -1 will select all polygons inside polygons from the other layer. * -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. * +1 will select all polygons outside polygons from the other layer.
* *
* In mode -1 and +1, finish () needs to be called before the interactions * 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 * input polygons (property != reference property). In mode +1 these are
* pseudo-interactions, because "outside" by definition means non-interacting. * pseudo-interactions, because "outside" by definition means non-interacting.
* *
* Mode -1 (inside) and +1 (outside) requires a single property value for the containing region. * Mode -1 (inside) and +1 (outside) requires a property value for the containing (primary) region.
* This property value must be specified in the container_id parameter. * Property IDs from 0 to the given last primary ID value are considered to belong to
* For correct operation, the container_id must be the lowest property ID and * the primary region.
* the interacting objects must have higher property id's. * This last property ID must be specified in the last_primary_id parameter.
* The reported interactions will be (container_id,polygon_id) even for outside mode. * 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. * 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 * @brief Sets the "touching" flag
@ -308,7 +312,7 @@ public:
private: private:
int m_mode; int m_mode;
bool m_include_touching; bool m_include_touching;
property_type m_container_id; property_type m_last_primary_id;
std::vector <int> m_wcv_n, m_wcv_s; std::vector <int> m_wcv_n, m_wcv_s;
std::set <property_type> m_inside_n, m_inside_s; std::set <property_type> m_inside_n, m_inside_s;
std::set<std::pair<property_type, property_type> > m_interactions; std::set<std::pair<property_type, property_type> > m_interactions;

View File

@ -110,14 +110,16 @@ public:
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_inside (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_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_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_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_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_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_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_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_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_overlapping (const Region &) 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_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *pull_interacting (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 (); } virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }

View File

@ -1178,6 +1178,52 @@ public:
return Region (mp_delegate->selected_not_inside (other)); 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<size_t>::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<size_t>::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<size_t>::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<size_t>::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 * @brief Selects all polygons of this region which overlap or touch polygons from the other region
* *
@ -1329,9 +1375,9 @@ public:
* *
* Merged semantics applies. * 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<size_t>::max ())
{ {
set_delegate (mp_delegate->selected_overlapping (other)); set_delegate (mp_delegate->selected_overlapping (other, min_count, max_count));
return *this; return *this;
} }
@ -1340,9 +1386,9 @@ public:
* *
* Merged semantics applies. * 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<size_t>::max ())
{ {
set_delegate (mp_delegate->selected_not_overlapping (other)); set_delegate (mp_delegate->selected_not_overlapping (other, min_count, max_count));
return *this; return *this;
} }
@ -1353,9 +1399,9 @@ public:
* *
* Merged semantics applies. * 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<size_t>::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. * 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<size_t>::max ()) const
{ {
return Region (mp_delegate->selected_not_overlapping (other)); return Region (mp_delegate->selected_not_overlapping (other, min_count, max_count));
} }
/** /**

View File

@ -351,14 +351,16 @@ public:
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;
virtual RegionDelegate *selected_inside (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_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_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_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_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_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_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_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_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_overlapping (const Region &other) 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_inside (const Region &other) const = 0;
virtual RegionDelegate *pull_interacting (const Region &other) const = 0; virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0; virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0;

View File

@ -466,7 +466,9 @@ void interacting_local_operation<TS, TI, TR>::compute_local (db::Layout * /*layo
ep.insert (subject, n); 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); id.set_include_touching (m_touching);
db::EdgeSink es; db::EdgeSink es;
ep.process (es, id); ep.process (es, id);

View File

@ -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) static db::CompoundRegionOperationNode *new_inside (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse)
{ {
// TODO: is this correct? // TODO: is this correct?
@ -281,6 +294,9 @@ Class<db::CompoundRegionOperationNode> 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<size_t>::max (), "unlimited"), 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<size_t>::max (), "unlimited"),
"@brief Creates a node representing an overlapping selection operation between the inputs.\n" "@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<size_t>::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), 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" "@brief Creates a node representing an inside selection operation between the inputs.\n"
) + ) +

View File

@ -1406,6 +1406,42 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This operator adds the polygons of the other region to self. " "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" "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<size_t>::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<size_t>::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<size_t>::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<size_t>::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"), 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" "@brief Returns the polygons of this region which are completely inside polygons from the other region\n"
"\n" "\n"
@ -1634,33 +1670,41 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"This method has been introduced in version 0.27\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<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which overlap polygons from the other region\n" "@brief Returns the polygons of this region which overlap polygons from the other region\n"
"\n" "\n"
"@return A new region containing the polygons overlapping polygons from the other region\n" "@return A new region containing the polygons overlapping polygons from the other region\n"
"\n" "\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\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<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which do not overlap polygons from the other region\n" "@brief Returns the polygons of this region which do not overlap polygons from the other region\n"
"\n" "\n"
"@return A new region containing the polygons not overlapping polygons from the other region\n" "@return A new region containing the polygons not overlapping polygons from the other region\n"
"\n" "\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\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 ("select_overlapping", &db::Region::select_overlapping, gsi::arg ("other"), 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<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which overlap polygons from the other region\n" "@brief Selects the polygons from this region which overlap polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\n" "\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\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 ("select_not_overlapping", &db::Region::select_not_overlapping, gsi::arg ("other"), 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<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which do not overlap polygons from the other region\n" "@brief Selects the polygons from this region which do not overlap polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\n" "\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\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"), method ("pull_inside", &db::Region::pull_inside, gsi::arg ("other"),
"@brief Returns all polygons of \"other\" which are inside polygons of this region\n" "@brief Returns all polygons of \"other\" which are inside polygons of this region\n"

View File

@ -1418,10 +1418,90 @@ CODE
# This method is available for polygon, edge and edge pair layers. An alias # This method is available for polygon, edge and edge pair layers. An alias
# is "\join". See there for a description of the function. # 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% # %DRC%
# @name overlapping # @name overlapping
# @brief Selects shapes or regions of self which overlap shapes from the other region # @brief Selects shapes or regions of self which overlap shapes from the other region
# @synopsis layer.overlapping(other) # @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 # 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, # 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.
@ -1438,17 +1518,25 @@ CODE
# @td @img(/images/drc_overlapping.png) @/td # @td @img(/images/drc_overlapping.png) @/td
# @/tr # @/tr
# @/table # @/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% # %DRC%
# @name not_overlapping # @name not_overlapping
# @brief Selects shapes or regions of self which do not overlap shapes from the other region # @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)
# @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 # 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, # 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 # The "not_overlapping" method is similar to the \outside method. However, "outside" does
# as an alias for consistency. # not provide the option to specify counts.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygon and edge layers. Edges can be selected
# with respect to other edges or polygons. # with respect to other edges or polygons.
@ -1459,6 +1547,9 @@ CODE
# @name select_overlapping # @name select_overlapping
# @brief Selects shapes or regions of self which overlap shapes from the other region # @brief Selects shapes or regions of self which overlap shapes from the other region
# @synopsis layer.select_overlapping(other) # @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 # 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, # 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.
@ -1472,6 +1563,9 @@ CODE
# @name select_not_overlapping # @name select_not_overlapping
# @brief Selects shapes or regions of self which do not overlap shapes from the other region # @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)
# @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 # 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, # 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.
@ -1902,7 +1996,7 @@ CODE
CODE CODE
end 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" eval <<"CODE"
def #{f}(other) def #{f}(other)
requires_same_type(other, "#{f}") requires_same_type(other, "#{f}")
@ -1974,7 +2068,34 @@ CODE
CODE CODE
end 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 f = "select_" + fi
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one. # In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
eval <<"CODE" eval <<"CODE"

View File

@ -16,6 +16,12 @@ l1.interacting(l2, 1..2).output(102, 0)
l1.interacting(l2, 2..).output(103, 0) l1.interacting(l2, 2..).output(103, 0)
l1.interacting(l2, 1, 2).output(104, 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 = l1.dup
l.select_interacting(l2, 1) l.select_interacting(l2, 1)
l.output(200, 0) l.output(200, 0)
@ -32,12 +38,34 @@ l = l1.dup
l.select_interacting(l2, 1, 2) l.select_interacting(l2, 1, 2)
l.output(204, 0) 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, 1).output(300, 0)
l1.not_interacting(l2, 2).output(301, 0) l1.not_interacting(l2, 2).output(301, 0)
l1.not_interacting(l2, 1..2).output(302, 0) l1.not_interacting(l2, 1..2).output(302, 0)
l1.not_interacting(l2, 2..).output(303, 0) l1.not_interacting(l2, 2..).output(303, 0)
l1.not_interacting(l2, 1, 2).output(304, 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 = l1.dup
l.select_not_interacting(l2, 1) l.select_not_interacting(l2, 1)
l.output(400, 0) l.output(400, 0)
@ -54,3 +82,19 @@ l = l1.dup
l.select_not_interacting(l2, 1, 2) l.select_not_interacting(l2, 1, 2)
l.output(404, 0) 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)

Binary file not shown.

Binary file not shown.