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.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))

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

View File

@ -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 &gt;= 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

View File

@ -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>

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.