mirror of https://github.com/KLayout/klayout.git
WIP: DRC 'enclosing' feature
This commit is contained in:
parent
ca388150bb
commit
5934bd529f
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -628,8 +628,8 @@ 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 ..
|
||||
}
|
||||
|
|
@ -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 <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} 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 <property_type>::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 <property_type>::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 <property_type>::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<property_type>::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<property_type> secondaries_to_delete;
|
||||
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) {
|
||||
|
||||
|
|
@ -768,13 +815,12 @@ InteractionDetector::finish ()
|
|||
|
||||
m_interactions.clear ();
|
||||
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 ();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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 <int> m_wcv_n, m_wcv_s;
|
||||
std::set <property_type> m_inside_n, m_inside_s;
|
||||
std::set<std::pair<property_type, property_type> > m_interactions;
|
||||
|
|
|
|||
|
|
@ -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 (); }
|
||||
|
|
|
|||
|
|
@ -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<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
|
||||
*
|
||||
|
|
@ -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<size_t>::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<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;
|
||||
}
|
||||
|
||||
|
|
@ -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<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.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -466,7 +466,9 @@ void interacting_local_operation<TS, TI, TR>::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);
|
||||
|
|
|
|||
|
|
@ -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<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"),
|
||||
"@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),
|
||||
"@brief Creates a node representing an inside selection operation between the inputs.\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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 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"),
|
||||
"@brief Returns the polygons of this region which are completely inside polygons from the other region\n"
|
||||
"\n"
|
||||
|
|
@ -1634,33 +1670,41 @@ Class<db::Region> 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<size_t>::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<size_t>::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"
|
||||
"\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"
|
||||
"\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 ("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"
|
||||
"\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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue