Fixed enclosing feature, added tests + DRC impl., DRC doc.

This commit is contained in:
Matthias Koefferlein 2020-12-08 22:44:33 +01:00
parent 1b26f48b13
commit 57a7671640
16 changed files with 356 additions and 112 deletions

View File

@ -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.inside_part(input2)", "drc_inside_part.png"
run_demo gen, "input1.edges.outside_part(input2)", "drc_outside_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 class Gen
def produce(s1, s2) def produce(s1, s2)
s1.insert(RBA::Box::new(0, 5000, 2000, 7000)) s1.insert(RBA::Box::new(0, 5000, 2000, 7000))

View File

@ -580,8 +580,24 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
db::EdgeProcessor ep (report_progress (), progress_desc ()); db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ()); ep.set_base_verbosity (base_verbosity ());
size_t n = 0;
size_t nstart = 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 (min_count == size_t (1) && max_count == std::numeric_limits<size_t>::max ()) {
if (mode < 0) { 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 // 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, n);
} }
} }
@ -597,13 +613,13 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
for (RegionIterator p = other.begin (); ! p.at_end (); ++p) { for (RegionIterator p = other.begin (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) { if (p->box ().touches (bbox ())) {
ep.insert (*p, nstart); ep.insert (*p, n);
} }
} }
} }
++nstart; ++n;
} else { } 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) { 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, 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 // there should be at least one element to look at for primary
tl_assert (nstart > 0); 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); db::InteractionDetector id (mode, nstart - 1);
id.set_include_touching (touching); id.set_include_touching (touching);
db::EdgeSink es; 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::auto_ptr<FlatRegion> output (new FlatRegion (false));
std::map <size_t, size_t> interaction_counts; std::map <size_t, size_t> interaction_counts;
n = 0;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) { for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) {
++n;
if (i->first < nstart && i->second >= nstart) { if (i->first < nstart && i->second >= nstart) {
interaction_counts [i->second] += 1; interaction_counts [mode < -1 ? i->first : i->second] += 1;
} }
} }
output->reserve (n); output->reserve (n);
n = nstart; n = (mode < -1 ? 0 : nstart);
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
size_t count = 0; size_t count = 0;
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n); std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);

View File

@ -190,12 +190,12 @@ public:
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const 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 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 virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const

View File

@ -665,9 +665,9 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
*wcv += (enter ? 1 : -1); *wcv += (enter ? 1 : -1);
bool inside_after = (*wcv != 0); 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 // 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; std::set <property_type> *inside = north ? &m_inside_n : &m_inside_s;
@ -675,17 +675,6 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
inside->erase (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 // the primary objects are delivered last of all coincident edges
// (due to prefer_touch == true and the sorting of coincident edges by property id) // (due to prefer_touch == true and the sorting of coincident edges by property id)
// hence every remaining parts count as non-interacting (outside) // hence every remaining parts count as non-interacting (outside)
@ -696,24 +685,14 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
} }
} }
} }
}
} else if (inside_after > inside_before) { } else if (inside_after > inside_before) {
if (m_mode != 0) { 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 (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 // 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 hence we can check whether the primary is present even for coincident
// edges // edges
@ -727,14 +706,22 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
if (! any) { if (! any) {
m_non_interactions.insert (p); m_non_interactions.insert (p);
} }
}
} else { } else {
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_last_primary_id) { 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)); m_interactions.insert (std::make_pair (p, *i));
} }
} }
} }
} else { } else {
@ -777,18 +764,19 @@ InteractionDetector::finish ()
{ {
if (m_mode < -1) { if (m_mode < -1) {
// In enclosing mode remove those objects which have an interaction with a primary having a non-interaction // In enclosing mode remove those objects which have an interaction with a secondary having a non-interaction:
std::set<property_type> secondaries_to_delete; // 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) { 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 ()) { if (m_non_interactions.find (i->second) != m_non_interactions.end ()) {
secondaries_to_delete.insert (i->second); primaries_to_delete.insert (i->first);
} }
} }
for (std::set<std::pair<property_type, property_type> >::iterator i = m_interactions.begin (); i != m_interactions.end (); ) { 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; std::set<std::pair<property_type, property_type> >::iterator ii = i;
++ii; ++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); m_interactions.erase (i);
} }
i = ii; 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 (); ) { 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; std::set<std::pair<property_type, property_type> >::iterator ii = i;
++ii; ++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); m_interactions.erase (i);
} }
i = ii; i = ii;

View File

@ -234,7 +234,7 @@ public:
* The mode parameter selects the interaction check mode. * The mode parameter selects the interaction check mode.
* 0 is "overlapping" or "touching". * 0 is "overlapping" or "touching".
* -1 will select all secondary polygons inside polygons from the primary. * -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. * +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 * Use set_include_touching(f) to specify whether to include or not include the touching

View File

@ -441,31 +441,49 @@ void interacting_local_operation<TS, TI, TR>::compute_local (db::Layout * /*layo
} }
size_t nstart = 0; 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) { // in enclosing mode self must be primary and other the secondary. For other
ep.insert (*o, nstart); // modes it's the other way round
}
nstart++;
} 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++;
}
}
size_t n = nstart;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
const TS &subject = interactions.subject_shape (i->first); const TS &subject = interactions.subject_shape (i->first);
ep.insert (subject, n); ep.insert (subject, n);
} }
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 {
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
ep.insert (*o, n);
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); tl_assert (nstart > 0);
db::InteractionDetector id (m_mode, nstart - 1); db::InteractionDetector id (m_mode, nstart - 1);
@ -477,11 +495,15 @@ void interacting_local_operation<TS, TI, TR>::compute_local (db::Layout * /*layo
std::map <size_t, size_t> interaction_counts; std::map <size_t, size_t> interaction_counts;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) { for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) {
if (i->first < nstart && i->second >= nstart) { if (i->first < nstart && i->second >= nstart) {
if (m_mode < -1) {
interaction_counts[i->first] += 1;
} else {
interaction_counts[i->second] += 1; 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) { for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
size_t count = 0; size_t count = 0;
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n); std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);

View File

@ -868,6 +868,18 @@ TEST(18a)
o.select_not_overlapping (rr); 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 (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) TEST(18b)

View File

@ -1431,8 +1431,7 @@ CODE
# It returns a new layer containing the selected shapes. A version which modifies self # It returns a new layer containing the selected shapes. A version which modifies self
# is \select_covering. # is \select_covering.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygons only.
# with respect to other edges or polygons.
# #
# The following image shows the effect of the "covering" method: # 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 # otherwise individual shapes are selected. This method returns the inverse of \covering
# and provides the same options. # and provides the same options.
# #
# This method is available for polygon and edge layers. Edges can be selected # The following image shows the effect of the "not_covering" method:
# with respect to other edges or polygons. #
# @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 # It returns a new layer containing the selected shapes. A version which modifies self
# is \select_not_covering. # is \select_not_covering.
@ -1479,8 +1485,7 @@ CODE
# It modifies self to contain the selected shapes. A version which does not modify self # It modifies self to contain the selected shapes. A version which does not modify self
# is \covering. # is \covering.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygons only.
# with respect to other edges or polygons.
# %DRC% # %DRC%
# @name select_not_covering # @name select_not_covering
@ -1495,8 +1500,7 @@ CODE
# It modifies self to contain the selected shapes. A version which does not modify self # It modifies self to contain the selected shapes. A version which does not modify self
# is \not_covering. # is \not_covering.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygons only.
# with respect to other edges or polygons.
# %DRC% # %DRC%
# @name overlapping # @name overlapping
@ -1511,8 +1515,7 @@ CODE
# It returns a new layer containing the selected shapes. A version which modifies self # It returns a new layer containing the selected shapes. A version which modifies self
# is \select_overlapping. # is \select_overlapping.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygons only.
# with respect to other edges or polygons.
# #
# The following image shows the effect of the "overlapping" method: # 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 # The "not_overlapping" method is similar to the \outside method. However, "outside" does
# not provide the option to specify counts. # 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 polygons only.
# with respect to other edges or polygons.
# It returns a new layer containing the selected shapes. A version which modifies self # It returns a new layer containing the selected shapes. A version which modifies self
# is \select_not_overlapping. # is \select_not_overlapping.
@ -1559,8 +1561,7 @@ CODE
# It modifies self to contain the selected shapes. A version which does not modify self # It modifies self to contain the selected shapes. A version which does not modify self
# is \overlapping. # is \overlapping.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygons only.
# with respect to other edges or polygons.
# %DRC% # %DRC%
# @name select_not_overlapping # @name select_not_overlapping
@ -1575,8 +1576,7 @@ CODE
# It modifies self to contain the selected shapes. A version which does not modify self # It modifies self to contain the selected shapes. A version which does not modify self
# is \not_overlapping. # is \not_overlapping.
# #
# This method is available for polygon and edge layers. Edges can be selected # This method is available for polygons only.
# with respect to other edges or polygons.
# %DRC% # %DRC%
# @name inside # @name inside
@ -2075,7 +2075,7 @@ CODE
eval <<"CODE" eval <<"CODE"
def #{f}(other, *args) def #{f}(other, *args)
requires_same_type(other, "#{f}") 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))) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(:#{f}, *args)))
end end
CODE CODE
@ -2086,7 +2086,7 @@ CODE
# 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"
def #{f}(other, *args) def #{f}(other, *args)
requires_edges_or_region("#{f}") requires_region("#{f}")
requires_same_type(other, "#{f}") requires_same_type(other, "#{f}")
if @engine.is_tiled? if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(:#{fi}, *args)) 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. # In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
eval <<"CODE" eval <<"CODE"
def #{f}(other) def #{f}(other)
requires_edges_or_region("#{f}") requires_region("#{f}")
requires_same_type(other, "#{f}") requires_same_type(other, "#{f}")
if @engine.is_tiled? if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data) self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data)

View File

@ -1037,3 +1037,43 @@ TEST(23_rect_filter)
db::compare_layouts (_this, layout, au, db::NoNormalization); 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);
}

View File

@ -278,6 +278,39 @@ The following images show the effect of this method:
</tr> </tr>
</table> </table>
</p> </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> <a name="data"/><h2>"data" - Gets the low-level data object</h2>
<keyword name="data"/> <keyword name="data"/>
<p>Usage:</p> <p>Usage:</p>
@ -1141,6 +1174,33 @@ written to the output (labels: red, input2: blue):
</tr> </tr>
</table> </table>
</p> </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> <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"/> <keyword name="not_in"/>
<p>Usage:</p> <p>Usage:</p>
@ -1265,17 +1325,20 @@ The following image shows the effect of the "not_outside" method (input1: red, i
<p>Usage:</p> <p>Usage:</p>
<ul> <ul>
<li><tt>layer.not_overlapping(other)</tt></li> <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> </ul>
<p> <p>
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 <a href="#raw">raw</a>), coherent regions are selected from self, 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> </p><p>
The "not_overlapping" method is equivalent to the <a href="#outside">outside</a> method. It is provided The "not_overlapping" method is similar to the <a href="#outside">outside</a> method. However, "outside" does
as an alias for consistency. not provide the option to specify counts.
</p><p> </p><p>
This method is available for polygon and edge layers. Edges can be selected This method is available for polygons only.
with respect to other edges or polygons.
It returns a new layer containing the selected shapes. A version which modifies self It returns a new layer containing the selected shapes. A version which modifies self
is <a href="#select_not_overlapping">select_not_overlapping</a>. is <a href="#select_not_overlapping">select_not_overlapping</a>.
</p> </p>
@ -1456,6 +1519,9 @@ The following images show the effect of the overlap check (input1: red, input2:
<p>Usage:</p> <p>Usage:</p>
<ul> <ul>
<li><tt>layer.overlapping(other)</tt></li> <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> </ul>
<p> <p>
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
@ -1464,8 +1530,7 @@ otherwise individual shapes are selected.
It returns a new layer containing the selected shapes. A version which modifies self It returns a new layer containing the selected shapes. A version which modifies self
is <a href="#select_overlapping">select_overlapping</a>. is <a href="#select_overlapping">select_overlapping</a>.
</p><p> </p><p>
This method is available for polygon and edge layers. Edges can be selected This method is available for polygons only.
with respect to other edges or polygons.
</p><p> </p><p>
The following image shows the effect of the "overlapping" method: The following image shows the effect of the "overlapping" method:
</p><p> </p><p>
@ -1474,6 +1539,10 @@ The following image shows the effect of the "overlapping" method:
<td><img src="/images/drc_overlapping.png"/></td> <td><img src="/images/drc_overlapping.png"/></td>
</tr> </tr>
</table> </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> </p>
<a name="perimeter"/><h2>"perimeter" - Returns the total perimeter of the polygons in the region</h2> <a name="perimeter"/><h2>"perimeter" - Returns the total perimeter of the polygons in the region</h2>
<keyword name="perimeter"/> <keyword name="perimeter"/>
@ -1727,6 +1796,24 @@ Here is a (slow) equivalent of the area selection method:
new_layer = layer.select { |polygon| polygon.area &gt;= 10.0 } new_layer = layer.select { |polygon| polygon.area &gt;= 10.0 }
</pre> </pre>
</p> </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> <a name="select_inside"/><h2>"select_inside" - Selects shapes or regions of self which are inside the other region</h2>
<keyword name="select_inside"/> <keyword name="select_inside"/>
<p>Usage:</p> <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 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. from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
</p> </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> <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"/> <keyword name="select_not_inside"/>
<p>Usage:</p> <p>Usage:</p>
@ -1833,6 +1938,9 @@ This method is available for polygon layers.
<p>Usage:</p> <p>Usage:</p>
<ul> <ul>
<li><tt>layer.select_not_overlapping(other)</tt></li> <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> </ul>
<p> <p>
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
@ -1841,8 +1949,7 @@ otherwise individual shapes are selected.
It modifies self to contain the selected shapes. A version which does not modify self It modifies self to contain the selected shapes. A version which does not modify self
is <a href="#not_overlapping">not_overlapping</a>. is <a href="#not_overlapping">not_overlapping</a>.
</p><p> </p><p>
This method is available for polygon and edge layers. Edges can be selected This method is available for polygons only.
with respect to other edges or polygons.
</p> </p>
<a name="select_outside"/><h2>"select_outside" - Selects shapes or regions of self which are outside the other region</h2> <a name="select_outside"/><h2>"select_outside" - Selects shapes or regions of self which are outside the other region</h2>
<keyword name="select_outside"/> <keyword name="select_outside"/>
@ -1866,6 +1973,9 @@ This method is available for polygon layers.
<p>Usage:</p> <p>Usage:</p>
<ul> <ul>
<li><tt>layer.select_overlapping(other)</tt></li> <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> </ul>
<p> <p>
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
@ -1874,8 +1984,7 @@ otherwise individual shapes are selected.
It modifies self to contain the selected shapes. A version which does not modify self It modifies self to contain the selected shapes. A version which does not modify self
is <a href="#overlapping">overlapping</a>. is <a href="#overlapping">overlapping</a>.
</p><p> </p><p>
This method is available for polygon and edge layers. Edges can be selected This method is available for polygons only.
with respect to other edges or polygons.
</p> </p>
<a name="sep"/><h2>"sep" - An alias for "separation"</h2> <a name="sep"/><h2>"sep" - An alias for "separation"</h2>
<keyword name="sep"/> <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

View File

@ -59,6 +59,8 @@
<file alias="drc_not3.png">doc/images/drc_not3.png</file> <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_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_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_interacting2.png">doc/images/drc_interacting2.png</file>
<file alias="drc_interacting3.png">doc/images/drc_interacting3.png</file> <file alias="drc_interacting3.png">doc/images/drc_interacting3.png</file>
<file alias="drc_interacting4.png">doc/images/drc_interacting4.png</file> <file alias="drc_interacting4.png">doc/images/drc_interacting4.png</file>

29
testdata/drc/drcSimpleTests_24.drc vendored Normal file
View 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)

BIN
testdata/drc/drcSimpleTests_24.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au24.gds vendored Normal file

Binary file not shown.