mirror of https://github.com/KLayout/klayout.git
Fixed enclosing feature, added tests + DRC impl., DRC doc.
This commit is contained in:
parent
1b26f48b13
commit
57a7671640
|
|
@ -545,6 +545,29 @@ run_demo gen, "input1.edges.not(input2)", "drc_not3.png"
|
|||
run_demo gen, "input1.edges.inside_part(input2)", "drc_inside_part.png"
|
||||
run_demo gen, "input1.edges.outside_part(input2)", "drc_outside_part.png"
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Box::new(-1000, 0, 1000, 2000))
|
||||
s1.insert(RBA::Box::new(2000, 0, 4000, 2000))
|
||||
s1.insert(RBA::Box::new(5000, 0, 7000, 2000))
|
||||
s1.insert(RBA::Box::new(-1000, 3000, 1000, 5000))
|
||||
s1.insert(RBA::Box::new(2000, 3000, 4000, 5000))
|
||||
s1.insert(RBA::Box::new(5000, 3000, 7000, 5000))
|
||||
s2.insert(RBA::Box::new(0, 500, 1000, 1500))
|
||||
s2.insert(RBA::Box::new(2500, 500, 3500, 1500))
|
||||
s2.insert(RBA::Box::new(4000, 500, 5000, 1500))
|
||||
s2.insert(RBA::Box::new(6250, 500, 7250, 1500))
|
||||
s2.insert(RBA::Box::new(-500, 5000, 500, 6000))
|
||||
s2.insert(RBA::Box::new(2500, 3500, 3500, 4500))
|
||||
s2.insert(RBA::Box::new(6250, 4750, 7250, 5750))
|
||||
end
|
||||
end
|
||||
|
||||
gen = Gen::new
|
||||
|
||||
run_demo gen, "input1.covering(input2)", "drc_covering.png"
|
||||
run_demo gen, "input1.not_covering(input2)", "drc_not_covering.png"
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Box::new(0, 5000, 2000, 7000))
|
||||
|
|
|
|||
|
|
@ -580,8 +580,24 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
|
|||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
|
||||
size_t n = 0;
|
||||
size_t nstart = 0;
|
||||
|
||||
if (mode < -1) {
|
||||
|
||||
// in enclosing mode self must be primary and other the secondary. For other
|
||||
// modes it's the other way round
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
|
||||
if (mode > 0 || p->box ().touches (other.bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
nstart = n;
|
||||
|
||||
}
|
||||
|
||||
if (min_count == size_t (1) && max_count == std::numeric_limits<size_t>::max ()) {
|
||||
|
||||
if (mode < 0) {
|
||||
|
|
@ -589,7 +605,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
|
|||
// 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);
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -597,13 +613,13 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
|
|||
|
||||
for (RegionIterator p = other.begin (); ! p.at_end (); ++p) {
|
||||
if (p->box ().touches (bbox ())) {
|
||||
ep.insert (*p, nstart);
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++nstart;
|
||||
++n;
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -614,9 +630,21 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
|
|||
|
||||
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
|
||||
if (p->box ().touches (bbox ())) {
|
||||
ep.insert (*p, nstart);
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
++n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mode >= -1) {
|
||||
|
||||
nstart = n;
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
|
||||
if (mode > 0 || p->box ().touches (other.bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
++nstart;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -624,13 +652,6 @@ 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 ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
db::InteractionDetector id (mode, nstart - 1);
|
||||
id.set_include_touching (touching);
|
||||
db::EdgeSink es;
|
||||
|
|
@ -640,17 +661,15 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
|
|||
std::auto_ptr<FlatRegion> output (new FlatRegion (false));
|
||||
|
||||
std::map <size_t, size_t> interaction_counts;
|
||||
n = 0;
|
||||
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) {
|
||||
++n;
|
||||
if (i->first < nstart && i->second >= nstart) {
|
||||
interaction_counts [i->second] += 1;
|
||||
interaction_counts [mode < -1 ? i->first : i->second] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
output->reserve (n);
|
||||
|
||||
n = nstart;
|
||||
n = (mode < -1 ? 0 : nstart);
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
|
||||
size_t count = 0;
|
||||
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);
|
||||
|
|
|
|||
|
|
@ -190,12 +190,12 @@ public:
|
|||
|
||||
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);
|
||||
return selected_interacting_generic (other, -2, false, 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);
|
||||
return selected_interacting_generic (other, -2, false, true, min_count, max_count);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const
|
||||
|
|
|
|||
|
|
@ -665,9 +665,9 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
|
|||
*wcv += (enter ? 1 : -1);
|
||||
bool inside_after = (*wcv != 0);
|
||||
|
||||
// In "interacting" mode we need to handle both north and south events because
|
||||
// In "interacting" and "enclosing" mode we need to handle both north and south events because
|
||||
// we have to catch interactions between objects north and south to the scanline
|
||||
if (north || (m_mode == 0 && m_include_touching)) {
|
||||
if (north || (m_mode == 0 && m_include_touching) || (m_mode < -1 && m_include_touching)) {
|
||||
|
||||
std::set <property_type> *inside = north ? &m_inside_n : &m_inside_s;
|
||||
|
||||
|
|
@ -675,25 +675,13 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
|
|||
|
||||
inside->erase (p);
|
||||
|
||||
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_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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -702,39 +690,38 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
|
|||
|
||||
if (m_mode != 0) {
|
||||
|
||||
// in enclosing/inside/outside mode we are only interested in interactions with a primary
|
||||
// enclosing/inside/outside mode
|
||||
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 {
|
||||
// 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);
|
||||
// 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_last_primary_id) {
|
||||
if (m_mode < -1) {
|
||||
// enclosing mode: an opening primary (= enclosing one) whith open secondaries means the secondary
|
||||
// has been opened before and did not close. Because we sort by property ID this must have happened
|
||||
// before, hence the secondary is overlapping. Make them non-interactions. We still have to record them
|
||||
// as interactions because this is how we skip the primaries later.
|
||||
m_non_interactions.insert (*i);
|
||||
}
|
||||
m_interactions.insert (std::make_pair (p, *i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -777,18 +764,19 @@ InteractionDetector::finish ()
|
|||
{
|
||||
if (m_mode < -1) {
|
||||
|
||||
// In enclosing mode remove those objects which have an interaction with a primary having a non-interaction
|
||||
std::set<property_type> secondaries_to_delete;
|
||||
// In enclosing mode remove those objects which have an interaction with a secondary having a non-interaction:
|
||||
// these are the ones where secondaries overlap and stick to the outside.
|
||||
std::set<property_type> primaries_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);
|
||||
if (m_non_interactions.find (i->second) != m_non_interactions.end ()) {
|
||||
primaries_to_delete.insert (i->first);
|
||||
}
|
||||
}
|
||||
|
||||
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 ()) {
|
||||
if (primaries_to_delete.find (i->first) != primaries_to_delete.end ()) {
|
||||
m_interactions.erase (i);
|
||||
}
|
||||
i = ii;
|
||||
|
|
@ -800,7 +788,7 @@ InteractionDetector::finish ()
|
|||
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 ()) {
|
||||
if (m_non_interactions.find (i->second) != m_non_interactions.end ()) {
|
||||
m_interactions.erase (i);
|
||||
}
|
||||
i = ii;
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ public:
|
|||
* The mode parameter selects the interaction check mode.
|
||||
* 0 is "overlapping" or "touching".
|
||||
* -1 will select all secondary polygons inside polygons from the primary.
|
||||
* -2 will select all secondary polygons enclosing polygons from the primary.
|
||||
* -2 will select all primary polygons enclosing polygons from the secondary.
|
||||
* +1 will select all secondary polygons outside polygons from the primary.
|
||||
*
|
||||
* Use set_include_touching(f) to specify whether to include or not include the touching
|
||||
|
|
|
|||
|
|
@ -441,29 +441,47 @@ void interacting_local_operation<TS, TI, TR>::compute_local (db::Layout * /*layo
|
|||
}
|
||||
|
||||
size_t nstart = 0;
|
||||
size_t n = 0;
|
||||
|
||||
if (m_min_count == size_t (1) && m_max_count == std::numeric_limits<size_t>::max ()) {
|
||||
if (m_mode < -1) {
|
||||
|
||||
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
|
||||
ep.insert (*o, nstart);
|
||||
// in enclosing mode self must be primary and other the secondary. For other
|
||||
// modes it's the other way round
|
||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
ep.insert (subject, n);
|
||||
}
|
||||
nstart++;
|
||||
|
||||
nstart = n;
|
||||
|
||||
}
|
||||
|
||||
if (m_mode != -2 && m_min_count == size_t (1) && m_max_count == std::numeric_limits<size_t>::max ()) {
|
||||
|
||||
// uncounted modes except enclosing (covering) can use one property ID for the primary ("other" input). This is slightly more efficient.
|
||||
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
|
||||
ep.insert (*o, n);
|
||||
}
|
||||
n++;
|
||||
|
||||
} else {
|
||||
|
||||
tl_assert (m_mode == 0);
|
||||
|
||||
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
|
||||
ep.insert (*o, nstart);
|
||||
nstart++;
|
||||
ep.insert (*o, n);
|
||||
n++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t n = nstart;
|
||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
ep.insert (subject, n);
|
||||
if (m_mode >= -1) {
|
||||
|
||||
nstart = n;
|
||||
|
||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
ep.insert (subject, n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tl_assert (nstart > 0);
|
||||
|
|
@ -477,11 +495,15 @@ void interacting_local_operation<TS, TI, TR>::compute_local (db::Layout * /*layo
|
|||
std::map <size_t, size_t> interaction_counts;
|
||||
for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) {
|
||||
if (i->first < nstart && i->second >= nstart) {
|
||||
interaction_counts[i->second] += 1;
|
||||
if (m_mode < -1) {
|
||||
interaction_counts[i->first] += 1;
|
||||
} else {
|
||||
interaction_counts[i->second] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = nstart;
|
||||
n = (m_mode < -1 ? 0 : nstart);
|
||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
|
||||
size_t count = 0;
|
||||
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);
|
||||
|
|
|
|||
|
|
@ -868,6 +868,18 @@ TEST(18a)
|
|||
o.select_not_overlapping (rr);
|
||||
EXPECT_EQ (o.to_string (), "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)");
|
||||
}
|
||||
EXPECT_EQ (r.selected_enclosing (rr).to_string (), "(0,100;0,130;30,130;30,100)");
|
||||
{
|
||||
db::Region o = r;
|
||||
o.select_enclosing (rr);
|
||||
EXPECT_EQ (o.to_string (), "(0,100;0,130;30,130;30,100)");
|
||||
o = r;
|
||||
EXPECT_EQ (o.selected_not_enclosing (rr).to_string (), "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60)");
|
||||
EXPECT_EQ (o.selected_enclosing (rr).count () + o.selected_not_enclosing (rr).count (), size_t (6));
|
||||
EXPECT_EQ (o.selected_enclosing (rr).hier_count () + o.selected_not_enclosing (rr).hier_count (), size_t (6));
|
||||
o.select_not_enclosing (rr);
|
||||
EXPECT_EQ (o.to_string (), "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60)");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(18b)
|
||||
|
|
|
|||
|
|
@ -1431,8 +1431,7 @@ CODE
|
|||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_covering.
|
||||
#
|
||||
# This method is available for polygon and edge layers. Edges can be selected
|
||||
# with respect to other edges or polygons.
|
||||
# This method is available for polygons only.
|
||||
#
|
||||
# The following image shows the effect of the "covering" method:
|
||||
#
|
||||
|
|
@ -1461,8 +1460,15 @@ CODE
|
|||
# otherwise individual shapes are selected. This method returns the inverse of \covering
|
||||
# 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.
|
||||
# The following image shows the effect of the "not_covering" method:
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_covering.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# This method is available for polygons only.
|
||||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_not_covering.
|
||||
|
||||
|
|
@ -1479,8 +1485,7 @@ CODE
|
|||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \covering.
|
||||
#
|
||||
# This method is available for polygon and edge layers. Edges can be selected
|
||||
# with respect to other edges or polygons.
|
||||
# This method is available for polygons only.
|
||||
|
||||
# %DRC%
|
||||
# @name select_not_covering
|
||||
|
|
@ -1495,8 +1500,7 @@ CODE
|
|||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \not_covering.
|
||||
#
|
||||
# This method is available for polygon and edge layers. Edges can be selected
|
||||
# with respect to other edges or polygons.
|
||||
# This method is available for polygons only.
|
||||
|
||||
# %DRC%
|
||||
# @name overlapping
|
||||
|
|
@ -1511,8 +1515,7 @@ CODE
|
|||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_overlapping.
|
||||
#
|
||||
# This method is available for polygon and edge layers. Edges can be selected
|
||||
# with respect to other edges or polygons.
|
||||
# This method is available for polygons only.
|
||||
#
|
||||
# The following image shows the effect of the "overlapping" method:
|
||||
#
|
||||
|
|
@ -1541,8 +1544,7 @@ CODE
|
|||
# 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.
|
||||
# This method is available for polygons only.
|
||||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_not_overlapping.
|
||||
|
||||
|
|
@ -1559,8 +1561,7 @@ CODE
|
|||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \overlapping.
|
||||
#
|
||||
# This method is available for polygon and edge layers. Edges can be selected
|
||||
# with respect to other edges or polygons.
|
||||
# This method is available for polygons only.
|
||||
|
||||
# %DRC%
|
||||
# @name select_not_overlapping
|
||||
|
|
@ -1575,8 +1576,7 @@ CODE
|
|||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \not_overlapping.
|
||||
#
|
||||
# This method is available for polygon and edge layers. Edges can be selected
|
||||
# with respect to other edges or polygons.
|
||||
# This method is available for polygons only.
|
||||
|
||||
# %DRC%
|
||||
# @name inside
|
||||
|
|
@ -2075,7 +2075,7 @@ CODE
|
|||
eval <<"CODE"
|
||||
def #{f}(other, *args)
|
||||
requires_same_type(other, "#{f}")
|
||||
requires_edges_or_region("#{f}")
|
||||
requires_region("#{f}")
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(:#{f}, *args)))
|
||||
end
|
||||
CODE
|
||||
|
|
@ -2086,7 +2086,7 @@ CODE
|
|||
# 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_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))
|
||||
|
|
@ -2103,7 +2103,7 @@ CODE
|
|||
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
requires_edges_or_region("#{f}")
|
||||
requires_region("#{f}")
|
||||
requires_same_type(other, "#{f}")
|
||||
if @engine.is_tiled?
|
||||
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data)
|
||||
|
|
|
|||
|
|
@ -1037,3 +1037,43 @@ TEST(23_rect_filter)
|
|||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(24_enclosing)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_24.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/drcSimpleTests_24.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au24.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,39 @@ The following images show the effect of this method:
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="covering"/><h2>"covering" - Selects shapes or regions of self which completely cover (enclose) one or more shapes from the other region</h2>
|
||||
<keyword name="covering"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.covering(other)</tt></li>
|
||||
<li><tt>layer.covering(other, min_count)</tt></li>
|
||||
<li><tt>layer.covering(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.covering(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which completly cover shapes from the other
|
||||
region. Unless self is in raw mode (see <a href="#raw">raw</a>), 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 <a href="#select_covering">select_covering</a>.
|
||||
</p><p>
|
||||
This method is available for polygons only.
|
||||
</p><p>
|
||||
The following image shows the effect of the "covering" method:
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_covering.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
A range of counts can be specified. If so, the shape from the primary layer is
|
||||
only selected when covering a given number of shapes from the other layer.
|
||||
For the interpretation of the count see <a href="#interacting">interacting</a>.
|
||||
</p><p>
|
||||
The "covering" attribute is sometimes called "enclosing", but this name is
|
||||
used for the respective DRC function (see <a href="#enclosing">enclosing</a>).
|
||||
</p>
|
||||
<a name="data"/><h2>"data" - Gets the low-level data object</h2>
|
||||
<keyword name="data"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1141,6 +1174,33 @@ written to the output (labels: red, input2: blue):
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="not_covering"/><h2>"not_covering" - Selects shapes or regions of self which do not cover (enclose) one or more shapes from the other region</h2>
|
||||
<keyword name="not_covering"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.not_covering(other)</tt></li>
|
||||
<li><tt>layer.not_covering(other, min_count)</tt></li>
|
||||
<li><tt>layer.not_covering(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.not_covering(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which do not cover shapes from the other
|
||||
region. Unless self is in raw mode (see <a href="#raw">raw</a>), coherent regions are selected from self,
|
||||
otherwise individual shapes are selected. This method returns the inverse of <a href="#covering">covering</a>
|
||||
and provides the same options.
|
||||
</p><p>
|
||||
The following image shows the effect of the "not_covering" method:
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_covering.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
This method is available for polygons only.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_not_covering">select_not_covering</a>.
|
||||
</p>
|
||||
<a name="not_in"/><h2>"not_in" - Selects shapes or regions of self which are not contained in the other layer</h2>
|
||||
<keyword name="not_in"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1265,17 +1325,20 @@ The following image shows the effect of the "not_outside" method (input1: red, i
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.not_overlapping(other)</tt></li>
|
||||
<li><tt>layer.not_overlapping(other, min_count)</tt></li>
|
||||
<li><tt>layer.not_overlapping(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.not_overlapping(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
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 <a href="#raw">raw</a>), coherent regions are selected from self,
|
||||
otherwise individual shapes are selected.
|
||||
otherwise individual shapes are selected. This method will return the inverse of <a href="#overlapping">overlapping</a>
|
||||
and provides the same options.
|
||||
</p><p>
|
||||
The "not_overlapping" method is equivalent to the <a href="#outside">outside</a> method. It is provided
|
||||
as an alias for consistency.
|
||||
The "not_overlapping" method is similar to the <a href="#outside">outside</a> method. However, "outside" does
|
||||
not provide the option to specify counts.
|
||||
</p><p>
|
||||
This method is available for polygon and edge layers. Edges can be selected
|
||||
with respect to other edges or polygons.
|
||||
This method is available for polygons only.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_not_overlapping">select_not_overlapping</a>.
|
||||
</p>
|
||||
|
|
@ -1456,6 +1519,9 @@ The following images show the effect of the overlap check (input1: red, input2:
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.overlapping(other)</tt></li>
|
||||
<li><tt>layer.overlapping(other, min_count)</tt></li>
|
||||
<li><tt>layer.overlapping(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.overlapping(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which overlap shapes from the other
|
||||
|
|
@ -1464,8 +1530,7 @@ otherwise individual shapes are selected.
|
|||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_overlapping">select_overlapping</a>.
|
||||
</p><p>
|
||||
This method is available for polygon and edge layers. Edges can be selected
|
||||
with respect to other edges or polygons.
|
||||
This method is available for polygons only.
|
||||
</p><p>
|
||||
The following image shows the effect of the "overlapping" method:
|
||||
</p><p>
|
||||
|
|
@ -1474,6 +1539,10 @@ The following image shows the effect of the "overlapping" method:
|
|||
<td><img src="/images/drc_overlapping.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
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 <a href="#interacting">interacting</a>.
|
||||
</p>
|
||||
<a name="perimeter"/><h2>"perimeter" - Returns the total perimeter of the polygons in the region</h2>
|
||||
<keyword name="perimeter"/>
|
||||
|
|
@ -1727,6 +1796,24 @@ Here is a (slow) equivalent of the area selection method:
|
|||
new_layer = layer.select { |polygon| polygon.area >= 10.0 }
|
||||
</pre>
|
||||
</p>
|
||||
<a name="select_covering"/><h2>"select_covering" - Selects shapes or regions of self which completely cover (enclose) one or more shapes from the other region</h2>
|
||||
<keyword name="select_covering"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_covering(other)</tt></li>
|
||||
<li><tt>layer.select_covering(other, min_count)</tt></li>
|
||||
<li><tt>layer.select_covering(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.select_covering(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which cover shapes from the other
|
||||
region. Unless self is in raw mode (see <a href="#raw">raw</a>), 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 <a href="#covering">covering</a>.
|
||||
</p><p>
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="select_inside"/><h2>"select_inside" - Selects shapes or regions of self which are inside the other region</h2>
|
||||
<keyword name="select_inside"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1769,6 +1856,24 @@ number of (different) shapes from the other layer. If a min and max count is giv
|
|||
self are selected only if they interact with min_count or more, but a maximum of max_count different shapes
|
||||
from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
|
||||
</p>
|
||||
<a name="select_not_covering"/><h2>"select_not_covering" - Selects shapes or regions of self which do not cover (enclose) one or more shapes from the other region</h2>
|
||||
<keyword name="select_not_covering"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_not_covering(other)</tt></li>
|
||||
<li><tt>layer.select_not_covering(other, min_count)</tt></li>
|
||||
<li><tt>layer.select_not_covering(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.select_not_covering(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which do not cover shapes from the other
|
||||
region. Unless self is in raw mode (see <a href="#raw">raw</a>), 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 <a href="#not_covering">not_covering</a>.
|
||||
</p><p>
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="select_not_inside"/><h2>"select_not_inside" - Selects shapes or regions of self which are not inside the other region</h2>
|
||||
<keyword name="select_not_inside"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1833,6 +1938,9 @@ This method is available for polygon layers.
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_not_overlapping(other)</tt></li>
|
||||
<li><tt>layer.select_not_overlapping(other, min_count)</tt></li>
|
||||
<li><tt>layer.select_not_overlapping(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.select_not_overlapping(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which do not overlap shapes from the other
|
||||
|
|
@ -1841,8 +1949,7 @@ otherwise individual shapes are selected.
|
|||
It modifies self to contain the selected shapes. A version which does not modify self
|
||||
is <a href="#not_overlapping">not_overlapping</a>.
|
||||
</p><p>
|
||||
This method is available for polygon and edge layers. Edges can be selected
|
||||
with respect to other edges or polygons.
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="select_outside"/><h2>"select_outside" - Selects shapes or regions of self which are outside the other region</h2>
|
||||
<keyword name="select_outside"/>
|
||||
|
|
@ -1866,6 +1973,9 @@ This method is available for polygon layers.
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_overlapping(other)</tt></li>
|
||||
<li><tt>layer.select_overlapping(other, min_count)</tt></li>
|
||||
<li><tt>layer.select_overlapping(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.select_overlapping(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which overlap shapes from the other
|
||||
|
|
@ -1874,8 +1984,7 @@ otherwise individual shapes are selected.
|
|||
It modifies self to contain the selected shapes. A version which does not modify self
|
||||
is <a href="#overlapping">overlapping</a>.
|
||||
</p><p>
|
||||
This method is available for polygon and edge layers. Edges can be selected
|
||||
with respect to other edges or polygons.
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="sep"/><h2>"sep" - An alias for "separation"</h2>
|
||||
<keyword name="sep"/>
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
|
|
@ -59,6 +59,8 @@
|
|||
<file alias="drc_not3.png">doc/images/drc_not3.png</file>
|
||||
<file alias="drc_inside_part.png">doc/images/drc_inside_part.png</file>
|
||||
<file alias="drc_outside_part.png">doc/images/drc_outside_part.png</file>
|
||||
<file alias="drc_covering.png">doc/images/drc_covering.png</file>
|
||||
<file alias="drc_not_covering.png">doc/images/drc_not_covering.png</file>
|
||||
<file alias="drc_interacting2.png">doc/images/drc_interacting2.png</file>
|
||||
<file alias="drc_interacting3.png">doc/images/drc_interacting3.png</file>
|
||||
<file alias="drc_interacting4.png">doc/images/drc_interacting4.png</file>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
# shielded/transparent
|
||||
|
||||
source($drc_test_source, "TOP")
|
||||
target($drc_test_target)
|
||||
|
||||
a = input(1, 0)
|
||||
b = input(2, 0)
|
||||
|
||||
a.output(1, 0)
|
||||
b.output(2, 0)
|
||||
|
||||
a.covering(b).output(100, 0)
|
||||
a.covering(b, 1..1).output(101, 0)
|
||||
a.covering(b, 2..2).output(102, 0)
|
||||
a.covering(b, 3..3).output(103, 0)
|
||||
b.inside(a).output(110, 0)
|
||||
|
||||
deep
|
||||
|
||||
a = input(1, 0)
|
||||
b = input(2, 0)
|
||||
|
||||
a.covering(b).output(200, 0)
|
||||
a.covering(b, 1..1).output(201, 0)
|
||||
a.covering(b, 2..2).output(202, 0)
|
||||
a.covering(b, 3..3).output(203, 0)
|
||||
b.inside(a).output(210, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue