WIP: Basic implementation of Region::interact with count

This commit is contained in:
Matthias Koefferlein 2020-09-21 22:54:46 +02:00
parent 965d796992
commit 91e924c559
16 changed files with 1060 additions and 175 deletions

View File

@ -36,12 +36,41 @@
#include "dbBoxScanner.h"
#include "dbClip.h"
#include "dbPolygonTools.h"
#include "dbHash.h"
#include <sstream>
namespace db
{
namespace {
struct ResultCountingInserter
{
typedef db::Polygon value_type;
ResultCountingInserter (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > &result)
: mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Polygon &p)
{
(*mp_result)[&p] += 1;
}
void init (const db::Polygon *p)
{
(*mp_result)[p] = 0;
}
private:
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > *mp_result;
};
}
// -------------------------------------------------------------------------------------------------------------
// AsIfFlagRegion implementation
@ -339,9 +368,11 @@ AsIfFlatRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &f
}
RegionDelegate *
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) const
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
{
if (other.empty ()) {
min_count = std::max (size_t (1), min_count);
if (max_count < min_count || other.empty ()) {
if (! inverse) {
return new EmptyRegion ();
} else {
@ -351,23 +382,28 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
return clone ();
}
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > counted_results;
ResultCountingInserter inserter (counted_results);
db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve1 (size ());
scanner.reserve2 (other.size ());
std::auto_ptr<FlatRegion> output (new FlatRegion (false));
region_to_edge_interaction_filter<Shapes, db::Polygon> filter (output->raw_polygons (), inverse);
region_to_edge_interaction_filter<ResultCountingInserter, db::Polygon> filter (inserter, false, counting /*get all in counting mode*/);
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
for ( ; ! p.at_end (); ++p) {
scanner.insert1 (p.operator-> (), 0);
if (inverse) {
filter.preset (p.operator-> ());
inserter.init (p.operator-> ());
}
}
AddressableEdgeDelivery e (other.addressable_edges ());
AddressableEdgeDelivery e (counting ? other.addressable_merged_edges () : other.addressable_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert2 (e.operator-> (), 0);
@ -375,17 +411,24 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
if (inverse) {
filter.fill_output ();
// select hits based on their count
for (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= min_count && r->second <= max_count;
if (hit != inverse) {
output->insert (*r->first);
}
}
return output.release ();
}
RegionDelegate *
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) const
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const
{
if (other.empty ()) {
min_count = std::max (size_t (1), min_count);
if (max_count < min_count || other.empty ()) {
if (! inverse) {
return new EmptyRegion ();
} else {
@ -395,19 +438,23 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse)
return clone ();
}
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > counted_results;
ResultCountingInserter inserter (counted_results);
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve1 (size ());
scanner.reserve2 (other.size ());
std::auto_ptr<FlatRegion> output (new FlatRegion (true));
region_to_text_interaction_filter<FlatRegion, db::Text> filter (*output, inverse);
region_to_text_interaction_filter<ResultCountingInserter, db::Text> filter (inserter, false, counting /*get all in counting mode*/);
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
for ( ; ! p.at_end (); ++p) {
scanner.insert1 (p.operator-> (), 0);
if (inverse) {
filter.preset (p.operator-> ());
inserter.init (p.operator-> ());
}
}
@ -419,23 +466,32 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse)
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
if (inverse) {
filter.fill_output ();
// select hits based on their count
std::auto_ptr<FlatRegion> output (new FlatRegion (true));
for (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= min_count && r->second <= max_count;
if (hit != inverse) {
output->insert (*r->first);
}
}
return output.release ();
}
RegionDelegate *
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());
// shortcut
if (empty ()) {
return clone ();
} else if (other.empty ()) {
} else if (max_count < min_count || other.empty ()) {
// clear, if b is empty and
// * mode is inside or interacting and inverse is false ("inside" or "interacting")
// * mode is outside and inverse is true ("not outside")
@ -446,13 +502,48 @@ 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, 0);
size_t nstart = 0;
if (min_count == size_t (1) && max_count == std::numeric_limits<size_t>::max ()) {
if (mode < 0) {
// NOTE: on "inside", 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);
}
}
} else {
for (RegionIterator p = other.begin (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, nstart);
}
}
}
++nstart;
} else {
// with counting we need to separate the other polygons by different properties
// can only have min_count/max_count in interact mode
tl_assert (mode == 0);
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, nstart);
}
++nstart;
}
}
size_t n = 1;
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);
@ -467,19 +558,26 @@ 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;
std::set <size_t> selected;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) {
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) {
++n;
selected.insert (i->second);
if (i->first < nstart && i->second >= nstart) {
interaction_counts [i->second] += 1;
}
}
output->reserve (n);
n = 1;
n = nstart;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
if ((selected.find (n) == selected.end ()) == inverse) {
output->raw_polygons ().insert (*p);
size_t count = 0;
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);
if (c != interaction_counts.end ()) {
count = c->second;
}
if ((count >= min_count && count <= max_count) != inverse) {
output->insert (*p);
}
}

View File

@ -183,34 +183,34 @@ public:
return selected_interacting_generic (other, -1, true, true);
}
virtual RegionDelegate *selected_interacting (const Region &other) const
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, true, false);
return selected_interacting_generic (other, 0, true, false, min_count, max_count);
}
virtual RegionDelegate *selected_not_interacting (const Region &other) const
virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, true, true);
return selected_interacting_generic (other, 0, true, true, min_count, max_count);
}
virtual RegionDelegate *selected_interacting (const Edges &other) const
virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, false);
return selected_interacting_generic (other, false, min_count, max_count);
}
virtual RegionDelegate *selected_not_interacting (const Edges &other) const
virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, true);
return selected_interacting_generic (other, true, min_count, max_count);
}
virtual RegionDelegate *selected_interacting (const Texts &other) const
virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, false);
return selected_interacting_generic (other, false, min_count, max_count);
}
virtual RegionDelegate *selected_not_interacting (const Texts &other) const
virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, true);
return selected_interacting_generic (other, true, min_count, max_count);
}
virtual RegionDelegate *selected_overlapping (const Region &other) const
@ -261,9 +261,9 @@ protected:
EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection, bool shielded) const;
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection, bool shielded) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &other) const;

View File

@ -1487,8 +1487,8 @@ class InteractingLocalOperation
: public local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>
{
public:
InteractingLocalOperation (int mode, bool touching, bool inverse)
: m_mode (mode), m_touching (touching), m_inverse (inverse)
InteractingLocalOperation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
: m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
{
// .. nothing yet ..
}
@ -1512,7 +1512,31 @@ public:
}
}
size_t n = 1;
size_t nstart = 0;
if (m_min_count == size_t (1) && m_max_count == std::numeric_limits<size_t>::max ()) {
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, nstart);
}
}
nstart++;
} else {
tl_assert (m_mode == 0);
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, nstart);
}
nstart++;
}
}
size_t n = nstart;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
const db::PolygonRef &subject = interactions.subject_shape (i->first);
for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) {
@ -1520,28 +1544,27 @@ public:
}
}
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, 0);
}
}
db::InteractionDetector id (m_mode, 0);
id.set_include_touching (m_touching);
db::EdgeSink es;
ep.process (es, id);
id.finish ();
n = 0;
std::set <size_t> selected;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) {
++n;
selected.insert (i->second);
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;
}
}
n = 1;
n = nstart;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
if ((selected.find (n) == selected.end ()) == m_inverse) {
size_t count = 0;
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);
if (c != interaction_counts.end ()) {
count = c->second;
}
if ((count >= m_min_count && count <= m_max_count) != m_inverse) {
const db::PolygonRef &subject = interactions.subject_shape (i->first);
result.insert (subject);
}
@ -1566,6 +1589,7 @@ private:
int m_mode;
bool m_touching;
bool m_inverse;
size_t m_min_count, m_max_count;
};
class PullLocalOperation
@ -1617,10 +1641,8 @@ public:
ep.process (es, id);
id.finish ();
n = 0;
std::set <size_t> selected;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) {
++n;
selected.insert (i->second);
}
@ -1667,6 +1689,31 @@ private:
std::unordered_set<db::PolygonRef> *mp_result;
};
struct ResultCountingInserter
{
typedef db::Polygon value_type;
ResultCountingInserter (db::Layout *layout, std::unordered_map<db::PolygonRef, size_t> &result)
: mp_layout (layout), mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Polygon &p)
{
(*mp_result)[db::PolygonRef (p, mp_layout->shape_repository ())] += 1;
}
void init (const db::Polygon &p)
{
(*mp_result)[db::PolygonRef (p, mp_layout->shape_repository ())] = 0;
}
private:
db::Layout *mp_layout;
std::unordered_map<db::PolygonRef, size_t> *mp_result;
};
struct EdgeResultInserter
{
typedef db::Edge value_type;
@ -1690,8 +1737,8 @@ class InteractingWithEdgeLocalOperation
: public local_operation<db::PolygonRef, db::Edge, db::PolygonRef>
{
public:
InteractingWithEdgeLocalOperation (bool inverse)
: m_inverse (inverse)
InteractingWithEdgeLocalOperation (bool inverse, size_t min_count, size_t max_count)
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
{
// .. nothing yet ..
}
@ -1704,20 +1751,25 @@ public:
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::Edge> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
std::unordered_map<db::PolygonRef, size_t> counted_results;
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ());
db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> scanner;
ResultInserter inserter (layout, result);
region_to_edge_interaction_filter<ResultInserter> filter (inserter, m_inverse);
ResultCountingInserter inserter (layout, counted_results);
region_to_edge_interaction_filter<ResultCountingInserter> filter (inserter, false, counting /*get all in counting mode*/);
std::set<unsigned int> intruder_ids;
for (shape_interactions<db::PolygonRef, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
intruder_ids.insert (*j);
}
}
for (std::set<unsigned int>::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
}
std::list<db::Polygon> heap;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
@ -1726,14 +1778,23 @@ public:
scanner.insert1 (&heap.back (), 0);
if (m_inverse) {
filter.preset (&heap.back ());
inserter.init (heap.back ());
}
}
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
if (m_inverse) {
filter.fill_output ();
// select hits based on their count
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
for (std::unordered_map<db::PolygonRef, size_t>::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= m_min_count && r->second <= m_max_count;
if (hit != m_inverse) {
result.insert (r->first);
}
}
}
@ -1753,6 +1814,7 @@ public:
private:
bool m_inverse;
size_t m_min_count, m_max_count;
};
class PullWithEdgeLocalOperation
@ -1860,6 +1922,17 @@ public:
}
}
std::set<unsigned int> intruder_ids;
for (shape_interactions<db::PolygonRef, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
intruder_ids.insert (*j);
}
}
for (std::set<unsigned int>::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
}
std::list<db::Polygon> heap;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
@ -1888,8 +1961,8 @@ class InteractingWithTextLocalOperation
: public local_operation<db::PolygonRef, db::TextRef, db::PolygonRef>
{
public:
InteractingWithTextLocalOperation (bool inverse)
: m_inverse (inverse)
InteractingWithTextLocalOperation (bool inverse, size_t min_count, size_t max_count)
: m_inverse (inverse), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
}
@ -1902,20 +1975,25 @@ public:
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::TextRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
std::unordered_map<db::PolygonRef, size_t> counted_results;
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ());
db::box_scanner2<db::Polygon, size_t, db::TextRef, size_t> scanner;
ResultInserter inserter (layout, result);
region_to_text_interaction_filter<ResultInserter, db::TextRef> filter (inserter, m_inverse);
ResultCountingInserter inserter (layout, counted_results);
region_to_text_interaction_filter<ResultCountingInserter, db::TextRef> filter (inserter, false, counting /*get all in counting mode*/);
for (shape_interactions<db::PolygonRef, db::Text>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Text>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
std::set<unsigned int> intruder_ids;
for (shape_interactions<db::PolygonRef, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
intruder_ids.insert (*j);
}
}
for (std::set<unsigned int>::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) {
scanner.insert2 (& interactions.intruder_shape (*j).second, 0);
}
std::list<db::Polygon> heap;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
@ -1924,14 +2002,23 @@ public:
scanner.insert1 (&heap.back (), 0);
if (m_inverse) {
filter.preset (&heap.back ());
inserter.init (heap.back ());
}
}
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::TextRef> ());
if (m_inverse) {
filter.fill_output ();
// select hits based on their count
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
for (std::unordered_map<db::PolygonRef, size_t>::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= m_min_count && r->second <= m_max_count;
if (hit != m_inverse) {
result.insert (r->first);
}
}
}
@ -1951,13 +2038,16 @@ public:
private:
bool m_inverse;
size_t m_min_count, m_max_count;
};
}
RegionDelegate *
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
{
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
@ -1970,12 +2060,12 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
}
const db::DeepLayer &polygons = merged_deep_layer ();
// NOTE: on "inside", the other polygons must be merged
const db::DeepLayer &other_polygons = mode < 0 ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
// NOTE: on "inside" or with counting, the other polygons must be merged
const db::DeepLayer &other_polygons = (mode < 0 || counting) ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
DeepLayer dl_out (polygons.derived ());
db::InteractingLocalOperation op (mode, touching, inverse);
db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count);
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
@ -1995,8 +2085,10 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
}
RegionDelegate *
DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) const
DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
{
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
@ -2012,7 +2104,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) cons
DeepLayer dl_out (polygons.derived ());
db::InteractingWithEdgeLocalOperation op (inverse);
db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count);
db::local_processor<db::PolygonRef, db::Edge, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
@ -2022,7 +2114,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) cons
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
}
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), dl_out.layer ());
db::DeepRegion *res = new db::DeepRegion (dl_out);
if (! split_after) {
@ -2129,7 +2221,7 @@ DeepRegion::pull_generic (const Texts &other) const
}
RegionDelegate *
DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) const
DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const
{
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
@ -2146,7 +2238,7 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) cons
DeepLayer dl_out (polygons.derived ());
db::InteractingWithTextLocalOperation op (inverse);
db::InteractingWithTextLocalOperation op (inverse, min_count, max_count);
db::local_processor<db::PolygonRef, db::TextRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());

View File

@ -188,9 +188,9 @@ private:
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other) const;
EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection, bool shielded) const;
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection, bool shielded) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const;
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const;
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const;
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &other) const;

View File

@ -717,7 +717,7 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
for (std::set <property_type>::const_iterator i = m_inside_n.begin (); i != m_inside_n.end (); ++i) {
if (*i < p) {
m_interactions.insert (std::make_pair (*i, p));
} else if (*i > p) {
} else if (p < *i) {
m_interactions.insert (std::make_pair (p, *i));
}
}
@ -725,7 +725,7 @@ InteractionDetector::edge (bool north, bool enter, property_type p)
for (std::set <property_type>::const_iterator i = m_inside_s.begin (); i != m_inside_s.end (); ++i) {
if (*i < p) {
m_interactions.insert (std::make_pair (*i, p));
} else if (*i > p) {
} else if (p < *i) {
m_interactions.insert (std::make_pair (p, *i));
}
}

View File

@ -245,8 +245,11 @@ public:
* Mode -1 (inside) and +1 (outside) requires a single property value for the containing region.
* This property value must be specified in the container_id parameter.
* For correct operation, the container_id must be the lowest property ID and
* the interacting edges must have higher property id's.
* the interacting objects must have higher property id's.
* The reported interactions will be (container_id,polygon_id) even for outside mode.
*
* For mode 0, property ids <= container_id are considered to belong to the first
* container and property ids > container_id to the second container.
*/
InteractionDetector (int mode = 0, property_type container_id = 0);

View File

@ -105,12 +105,12 @@ public:
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_interacting (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_interacting (const Edges &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_interacting (const Texts &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Texts &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); }

View File

@ -443,6 +443,19 @@ namespace std
return hf;
}
};
/**
* @brief Create a pointer hash from the pointer's value
*/
template <class X>
struct ptr_hash_from_value
{
size_t operator() (const X *ptr) const
{
return ptr ? hash<X> () (*ptr) : 0;
}
};
}
#endif

View File

@ -1251,22 +1251,30 @@ public:
/**
* @brief Selects all polygons of this region which overlap or touch polygons from the other region
*
* The argument (if given) specifies and range of interaction counts: polygons will only be selected
* if the number of interacting (different) polygons from the other region is between min_count and
* max_count (inclusive).
*
* Merged semantics applies.
*/
Region &select_interacting (const Region &other)
Region &select_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
/**
* @brief Selects all polygons of this region which do not overlap or touch polygons from the other region
*
* The argument (if given) specifies and range of interaction counts: polygons will not be selected
* if the number of interacting (different) polygons from the other region is between min_count and
* max_count (inclusive).
*
* Merged semantics applies.
*/
Region &select_not_interacting (const Region &other)
Region &select_not_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@ -1277,9 +1285,9 @@ public:
*
* Merged semantics applies.
*/
Region selected_interacting (const Region &other) const
Region selected_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Region (mp_delegate->selected_interacting (other));
return Region (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
@ -1289,9 +1297,9 @@ public:
*
* Merged semantics applies.
*/
Region selected_not_interacting (const Region &other) const
Region selected_not_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Region (mp_delegate->selected_not_interacting (other));
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
@ -1299,9 +1307,9 @@ public:
*
* Merged semantics applies to both operators.
*/
Region &select_interacting (const Edges &other)
Region &select_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
@ -1310,9 +1318,9 @@ public:
*
* Merged semantics applies to both operators.
*/
Region &select_not_interacting (const Edges &other)
Region &select_not_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@ -1323,9 +1331,9 @@ public:
*
* Merged semantics applies to both operators.
*/
Region selected_interacting (const Edges &other) const
Region selected_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Region (mp_delegate->selected_interacting (other));
return Region (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
@ -1335,9 +1343,9 @@ public:
*
* Merged semantics applies to both operators.
*/
Region selected_not_interacting (const Edges &other) const
Region selected_not_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Region (mp_delegate->selected_not_interacting (other));
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
@ -1345,9 +1353,9 @@ public:
*
* Merged semantics applies.
*/
Region &select_interacting (const Texts &other)
Region &select_interacting (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
@ -1356,9 +1364,9 @@ public:
*
* Merged semantics applies.
*/
Region &select_not_interacting (const Texts &other)
Region &select_not_interacting (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@ -1369,9 +1377,9 @@ public:
*
* Merged semantics applies.
*/
Region selected_interacting (const Texts &other) const
Region selected_interacting (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Region (mp_delegate->selected_interacting (other));
return Region (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
@ -1381,9 +1389,9 @@ public:
*
* Merged semantics applies.
*/
Region selected_not_interacting (const Texts &other) const
Region selected_not_interacting (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Region (mp_delegate->selected_not_interacting (other));
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**

View File

@ -269,12 +269,12 @@ public:
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;
virtual RegionDelegate *selected_inside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_inside (const Region &other) const = 0;
virtual RegionDelegate *selected_interacting (const Region &other) const = 0;
virtual RegionDelegate *selected_not_interacting (const Region &other) const = 0;
virtual RegionDelegate *selected_interacting (const Edges &other) const = 0;
virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0;
virtual RegionDelegate *selected_interacting (const Texts &other) const = 0;
virtual RegionDelegate *selected_not_interacting (const Texts &other) const = 0;
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_overlapping (const Region &other) const = 0;
virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0;
virtual RegionDelegate *pull_inside (const Region &other) const = 0;

View File

@ -364,8 +364,8 @@ Poly2PolyCheckBase::enter (const db::Polygon &o1, size_t p1, const db::Polygon &
// RegionToEdgeInteractionFilterBase implementation
template <class OutputType>
region_to_edge_interaction_filter_base<OutputType>::region_to_edge_interaction_filter_base (bool inverse)
: m_inverse (inverse)
region_to_edge_interaction_filter_base<OutputType>::region_to_edge_interaction_filter_base (bool inverse, bool get_all)
: m_inverse (inverse), m_get_all (get_all)
{
// .. nothing yet ..
}
@ -384,7 +384,7 @@ region_to_edge_interaction_filter_base<OutputType>::add (const db::Polygon *p, s
const OutputType *o = 0;
tl::select (o, p, e);
if ((m_seen.find (o) == m_seen.end ()) != m_inverse) {
if (m_get_all || (m_seen.find (o) == m_seen.end ()) != m_inverse) {
// A polygon and an edge interact if the edge is either inside completely
// of at least one edge of the polygon intersects with the edge
@ -403,7 +403,9 @@ region_to_edge_interaction_filter_base<OutputType>::add (const db::Polygon *p, s
if (m_inverse) {
m_seen.erase (o);
} else {
m_seen.insert (o);
if (! m_get_all) {
m_seen.insert (o);
}
put (*o);
}
}
@ -428,8 +430,8 @@ template class region_to_edge_interaction_filter_base<db::Edge>;
// RegionToTextInteractionFilterBase implementation
template <class OutputType, class TextType>
region_to_text_interaction_filter_base<OutputType, TextType>::region_to_text_interaction_filter_base (bool inverse)
: m_inverse (inverse)
region_to_text_interaction_filter_base<OutputType, TextType>::region_to_text_interaction_filter_base (bool inverse, bool get_all)
: m_inverse (inverse), m_get_all (get_all)
{
// .. nothing yet ..
}
@ -448,7 +450,7 @@ region_to_text_interaction_filter_base<OutputType, TextType>::add (const db::Pol
const OutputType *o = 0;
tl::select (o, p, t);
if ((m_seen.find (o) == m_seen.end ()) != m_inverse) {
if (m_get_all || (m_seen.find (o) == m_seen.end ()) != m_inverse) {
// A polygon and an text interact if the text is either inside completely
// of at least one text of the polygon intersects with the text
@ -457,7 +459,9 @@ region_to_text_interaction_filter_base<OutputType, TextType>::add (const db::Pol
if (m_inverse) {
m_seen.erase (o);
} else {
m_seen.insert (o);
if (! m_get_all) {
m_seen.insert (o);
}
put (*o);
}
}

View File

@ -596,7 +596,7 @@ class DB_PUBLIC region_to_edge_interaction_filter_base
: public db::box_scanner_receiver2<db::Polygon, size_t, db::Edge, size_t>
{
public:
region_to_edge_interaction_filter_base (bool inverse);
region_to_edge_interaction_filter_base (bool inverse, bool get_all);
void preset (const OutputType *s);
void add (const db::Polygon *p, size_t, const db::Edge *e, size_t);
@ -607,7 +607,7 @@ protected:
private:
std::set<const OutputType *> m_seen;
bool m_inverse;
bool m_inverse, m_get_all;
};
/**
@ -618,8 +618,8 @@ class DB_PUBLIC_TEMPLATE region_to_edge_interaction_filter
: public region_to_edge_interaction_filter_base<OutputType>
{
public:
region_to_edge_interaction_filter (OutputContainer &output, bool inverse)
: region_to_edge_interaction_filter_base<OutputType> (inverse), mp_output (&output)
region_to_edge_interaction_filter (OutputContainer &output, bool inverse, bool get_all = false)
: region_to_edge_interaction_filter_base<OutputType> (inverse, get_all), mp_output (&output)
{
// .. nothing yet ..
}
@ -642,7 +642,7 @@ class DB_PUBLIC region_to_text_interaction_filter_base
: public db::box_scanner_receiver2<db::Polygon, size_t, TextType, size_t>
{
public:
region_to_text_interaction_filter_base (bool inverse);
region_to_text_interaction_filter_base (bool inverse, bool get_all);
void preset (const OutputType *s);
void add (const db::Polygon *p, size_t, const TextType *e, size_t);
@ -653,7 +653,7 @@ protected:
private:
std::set<const OutputType *> m_seen;
bool m_inverse;
bool m_inverse, m_get_all;
};
/**
@ -664,8 +664,8 @@ class DB_PUBLIC_TEMPLATE region_to_text_interaction_filter
: public region_to_text_interaction_filter_base<OutputType, TextType>
{
public:
region_to_text_interaction_filter (OutputContainer &output, bool inverse)
: region_to_text_interaction_filter_base<OutputType, TextType> (inverse), mp_output (&output)
region_to_text_interaction_filter (OutputContainer &output, bool inverse, bool get_all = false)
: region_to_text_interaction_filter_base<OutputType, TextType> (inverse, get_all), mp_output (&output)
{
// .. nothing yet ..
}

View File

@ -1476,100 +1476,172 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method ("interacting", (db::Region (db::Region::*) (const db::Region &) const) &db::Region::selected_interacting, gsi::arg ("other"),
method ("interacting", (db::Region (db::Region::*) (const db::Region &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which overlap or touch polygons from the other region\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with (different) polygons of the other region to make the polygon selected. A polygon is "
"selected by this method if the number of polygons interacting with a polygon of this region is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return A new region containing the polygons overlapping or touching polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method ("not_interacting", (db::Region (db::Region::*) (const db::Region &) const) &db::Region::selected_not_interacting, gsi::arg ("other"),
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("not_interacting", (db::Region (db::Region::*) (const db::Region &, size_t, size_t) const) &db::Region::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which do not overlap or touch polygons from the other region\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with (different) polygons of the other region to make the polygon not selected. A polygon is not "
"selected by this method if the number of polygons interacting with a polygon of this region is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return A new region containing the polygons not overlapping or touching polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Region &)) &db::Region::select_interacting, gsi::arg ("other"),
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Region &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which overlap or touch polygons from the other region\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with (different) polygons of the other region to make the polygon selected. A polygon is "
"selected by this method if the number of polygons interacting with a polygon of this region is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Region &)) &db::Region::select_not_interacting, gsi::arg ("other"),
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Region &, size_t, size_t)) &db::Region::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which do not overlap or touch polygons from the other region\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with (different) polygons of the other region to make the polygon not selected. A polygon is not "
"selected by this method if the number of polygons interacting with a polygon of this region is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method ("interacting", (db::Region (db::Region::*) (const db::Edges &) const) &db::Region::selected_interacting, gsi::arg ("other"),
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("interacting", (db::Region (db::Region::*) (const db::Edges &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which overlap or touch edges from the edge collection\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with edges of the edge collection to make the polygon selected. A polygon is "
"selected by this method if the number of edges interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return A new region containing the polygons overlapping or touching edges from the edge collection\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.25\n"
"This method has been introduced in version 0.25.\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("not_interacting", (db::Region (db::Region::*) (const db::Edges &) const) &db::Region::selected_not_interacting, gsi::arg ("other"),
method ("not_interacting", (db::Region (db::Region::*) (const db::Edges &, size_t, size_t) const) &db::Region::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which do not overlap or touch edges from the edge collection\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with edges of the edge collection to make the polygon not selected. A polygon is not "
"selected by this method if the number of edges interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return A new region containing the polygons not overlapping or touching edges from the edge collection\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.25\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Edges &)) &db::Region::select_interacting, gsi::arg ("other"),
method ("select_interacting", (db::Region &(db::Region::*) (const db::Edges &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which overlap or touch edges from the edge collection\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with edges of the edge collection to make the polygon selected. A polygon is "
"selected by this method if the number of edges interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.25\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Edges &)) &db::Region::select_not_interacting, gsi::arg ("other"),
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Edges &, size_t, size_t)) &db::Region::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which do not overlap or touch edges from the edge collection\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with edges of the edge collection to make the polygon not selected. A polygon is not "
"selected by this method if the number of edges interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.25\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method ("interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_interacting, gsi::arg ("other"),
method ("interacting", (db::Region (db::Region::*) (const db::Texts &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which overlap or touch texts\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with texts of the text collection to make the polygon selected. A polygon is "
"selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return A new region containing the polygons overlapping or touching texts\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
method ("not_interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_not_interacting, gsi::arg ("other"),
method ("not_interacting", (db::Region (db::Region::*) (const db::Texts &, size_t, size_t) const) &db::Region::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which do not overlap or touch texts\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with texts of the text collection to make the polygon not selected. A polygon is not "
"selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return A new region containing the polygons not overlapping or touching texts\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &)) &db::Region::select_interacting, gsi::arg ("other"),
method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons of this region which overlap or touch texts\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with texts of the text collection to make the polygon selected. A polygon is "
"selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Texts &)) &db::Region::select_not_interacting, gsi::arg ("other"),
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Texts &, size_t, size_t)) &db::Region::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons of this region which do not overlap or touch texts\n"
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times a polygon of this region "
"has to interact with texts of the text collection to make the polygon not selected. A polygon is not "
"selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"

View File

@ -1689,6 +1689,278 @@ TEST(29_InteractionsWithTexts)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au29.gds");
}
TEST(30a_interact_with_count_region)
{
db::DeepShapeStore dss;
db::Layout ly;
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
db::cell_index_type ci1 = ly.add_cell ("C1");
db::Cell &c1 = ly.cell (ci1);
db::cell_index_type ci2 = ly.add_cell ("C2");
db::Cell &c2 = ly.cell (ci2);
top.insert (db::CellInstArray (db::CellInst (ci1), db::Trans ()));
top.insert (db::CellInstArray (db::CellInst (ci2), db::Trans ()));
c1.shapes (l1).insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
c1.shapes (l1).insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
c2.shapes (l2).insert (db::Box (db::Point (-10, -10), db::Point (10, 0)));
c2.shapes (l2).insert (db::Box (db::Point (-10, 0), db::Point (10, 10)));
c2.shapes (l2).insert (db::Box (db::Point (-110, -10), db::Point (-90, 10)));
c2.shapes (l2).insert (db::Box (db::Point (-110, -210), db::Point (-90, -190)));
ly.copy_layer (l2, l3);
top.shapes (l2).insert (db::Box (db::Point (90, -10), db::Point (110, 10)));
top.shapes (l2).insert (db::Box (db::Point (-110, -110), db::Point (-90, -90)));
db::Region r (db::RecursiveShapeIterator (ly, top, l1), dss);
r.set_merged_semantics (true);
r.set_min_coherence (false);
db::Region empty;
db::Region rr (db::RecursiveShapeIterator (ly, top, l2), dss);
db::Region rr2 (db::RecursiveShapeIterator (ly, top, l3), dss);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 5, 5).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 5, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 2, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(30b_interact_with_count_edge)
{
db::DeepShapeStore dss;
db::Layout ly;
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
db::cell_index_type ci1 = ly.add_cell ("C1");
db::Cell &c1 = ly.cell (ci1);
db::cell_index_type ci2 = ly.add_cell ("C2");
db::Cell &c2 = ly.cell (ci2);
top.insert (db::CellInstArray (db::CellInst (ci1), db::Trans ()));
top.insert (db::CellInstArray (db::CellInst (ci2), db::Trans ()));
c1.shapes (l1).insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
c1.shapes (l1).insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
c2.shapes (l2).insert (db::Edge (db::Point (-10, -10), db::Point (0, 0)));
c2.shapes (l2).insert (db::Edge (db::Point (0, 0), db::Point (10, 10)));
c2.shapes (l2).insert (db::Edge (db::Point (-110, -10), db::Point (-90, 10)));
c2.shapes (l2).insert (db::Edge (db::Point (-110, -210), db::Point (-90, -190)));
ly.copy_layer (l2, l3);
top.shapes (l2).insert (db::Edge (db::Point (90, -10), db::Point (110, 10)));
top.shapes (l2).insert (db::Edge (db::Point (-110, -110), db::Point (-90, -90)));
db::Region r (db::RecursiveShapeIterator (ly, top, l1), dss);
r.set_merged_semantics (true);
r.set_min_coherence (false);
db::Region empty;
db::Edges rr (db::RecursiveShapeIterator (ly, top, l2), dss);
db::Edges rr2 (db::RecursiveShapeIterator (ly, top, l3), dss);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 5, 5).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 5, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 2, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(30c_interact_with_count_text)
{
db::DeepShapeStore dss;
db::Layout ly;
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
db::cell_index_type ci1 = ly.add_cell ("C1");
db::Cell &c1 = ly.cell (ci1);
db::cell_index_type ci2 = ly.add_cell ("C2");
db::Cell &c2 = ly.cell (ci2);
top.insert (db::CellInstArray (db::CellInst (ci1), db::Trans ()));
top.insert (db::CellInstArray (db::CellInst (ci2), db::Trans ()));
c1.shapes (l1).insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
c1.shapes (l1).insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
c2.shapes (l2).insert (db::Text ("a", db::Trans (db::Vector (0, 0))));
c2.shapes (l2).insert (db::Text ("b", db::Trans (db::Vector (-100, 0))));
c2.shapes (l2).insert (db::Text ("c", db::Trans (db::Vector (-100, -200))));
ly.copy_layer (l2, l3);
top.shapes (l2).insert (db::Text ("x", db::Trans (db::Vector (100, 0))));
top.shapes (l2).insert (db::Text ("y", db::Trans (db::Vector (-100, -100))));
db::Region r (db::RecursiveShapeIterator (ly, top, l1), dss);
r.set_merged_semantics (true);
r.set_min_coherence (false);
db::Region empty;
db::Texts rr (db::RecursiveShapeIterator (ly, top, l2), dss);
db::Texts rr2 (db::RecursiveShapeIterator (ly, top, l3), dss);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 5, 5).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 5, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 2, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(100_Integration)
{
db::Layout ly;

View File

@ -1336,7 +1336,7 @@ TEST(30a)
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_not_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
db::Region rr = r;
r.select_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (-10, -10))));
@ -1365,7 +1365,7 @@ TEST(30b)
r.set_merged_semantics (true);
r.set_min_coherence (true);
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
r.select_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (-10, -10))));
EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
@ -1522,7 +1522,7 @@ TEST(34a)
db::Texts tt;
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0))));
EXPECT_EQ (r.selected_interacting (tt).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (tt).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (300, 30))))).to_string (), "");
db::Region rr = r;
r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10)))));
@ -1554,7 +1554,7 @@ TEST(34b)
db::Texts tt;
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0))));
EXPECT_EQ (r.selected_interacting (tt).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (tt).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), "");
r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10)))));
EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
@ -1588,6 +1588,221 @@ TEST(34d)
EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), "");
}
TEST(35a_interact_with_count_region)
{
db::Region r;
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
r.set_merged_semantics (true);
r.set_min_coherence (false);
db::Region empty;
db::Region rr;
rr.insert (db::Box (db::Point (-10, -10), db::Point (10, 0)));
rr.insert (db::Box (db::Point (-10, 0), db::Point (10, 10)));
rr.insert (db::Box (db::Point (-110, -10), db::Point (-90, 10)));
rr.insert (db::Box (db::Point (-110, -210), db::Point (-90, -190)));
db::Region rr2 = rr;
rr.insert (db::Box (db::Point (90, -10), db::Point (110, 10)));
rr.insert (db::Box (db::Point (-110, -110), db::Point (-90, -90)));
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 5, 5).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 5, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 2, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(35b_interact_with_count_edge)
{
db::Region r;
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
r.set_merged_semantics (true);
r.set_min_coherence (false);
db::Region empty;
db::Edges rr;
rr.insert (db::Edge (db::Point (-10, -10), db::Point (0, 0)));
rr.insert (db::Edge (db::Point (0, 0), db::Point (10, 10)));
rr.insert (db::Edge (db::Point (-110, -10), db::Point (-90, 10)));
rr.insert (db::Edge (db::Point (-110, -210), db::Point (-90, -190)));
db::Edges rr2 = rr;
rr.insert (db::Edge (db::Point (90, -10), db::Point (110, 10)));
rr.insert (db::Edge (db::Point (-110, -110), db::Point (-90, -90)));
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 5, 5).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 5, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 2, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(35c_interact_with_count_text)
{
db::Region r;
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
r.set_merged_semantics (true);
r.set_min_coherence (false);
db::Region empty;
db::Texts rr;
rr.insert (db::Text ("a", db::Trans (db::Vector (0, 0))));
rr.insert (db::Text ("b", db::Trans (db::Vector (-100, 0))));
rr.insert (db::Text ("c", db::Trans (db::Vector (-100, -200))));
db::Texts rr2 = rr;
rr.insert (db::Text ("x", db::Trans (db::Vector (100, 0))));
rr.insert (db::Text ("y", db::Trans (db::Vector (-100, -100))));
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 5, 5).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 4, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 5, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 2, 5).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr2, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (empty).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 1).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
}
TEST(100_Processors)
{
db::Region r;

View File

@ -1673,6 +1673,9 @@ CODE
# @name interacting
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region
# @synopsis layer.interacting(other)
# @synopsis layer.interacting(other, count)
# @synopsis layer.interacting(other, min_count, max_count)
# @synopsis layer.interacting(other, min_count .. max_count)
# This method selects all shapes or regions from self which touch or overlap shapes from the other
# region. Unless self is in raw mode (see \raw), coherent regions are selected from self,
# otherwise individual shapes are selected.
@ -1690,11 +1693,25 @@ CODE
# @td @img(/images/drc_interacting.png) @/td
# @/tr
# @/table
#
# If a single count is given, shapes from self are selected only if they do interact with the given
# number of (different) shapes from the other layer. If a min and max count is given, shapes from
# 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.
#
# @table
# @tr
# @td @img(/images/drc_interacting2.png) @/td
# @/tr
# @/table
# %DRC%
# @name not_interacting
# @brief Selects shapes or regions of self which do not touch or overlap shapes from the other region
# @synopsis layer.not_interacting(other)
# @synopsis layer.not_interacting(other, count)
# @synopsis layer.not_interacting(other, min_count, max_count)
# @synopsis layer.not_interacting(other, min_count .. max_count)
# This method selects all shapes or regions from self which do not touch or overlap shapes from the other
# region. Unless self is in raw mode (see \raw), coherent regions are selected from self,
# otherwise individual shapes are selected.
@ -1712,13 +1729,27 @@ CODE
# @td @img(/images/drc_not_interacting.png) @/td
# @/tr
# @/table
#
# If a single count is given, shapes from self are selected only if they do not interact with the given
# number of (different) shapes from the other layer. If a min and max count is given, shapes from
# self are selected only if they interact with less than min_count or more than max_count different shapes
# from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
#
# @table
# @tr
# @td @img(/images/drc_not_interacting2.png) @/td
# @/tr
# @/table
# %DRC%
# @name select_interacting
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region
# @synopsis layer.select_interacting(other)
# @synopsis layer.select_interacting(other, count)
# @synopsis layer.select_interacting(other, min_count, max_count)
# @synopsis layer.select_interacting(other, min_count .. max_count)
# This method selects all shapes or regions from self which touch or overlap shapes from the other
# region. Unless self is in raw mode (see \raw), coherent regions are selected from self,
# layer. Unless self is in raw mode (see \raw), coherent regions are selected from self,
# otherwise individual shapes are selected.
# It modifies self to contain the selected shapes. A version which does not modify self
# is \interacting.
@ -1726,13 +1757,21 @@ CODE
# This method is available for polygon, text and edge layers. Edges can be selected
# with respect to other edges or polygons. Texts can be selected with respect to
# polygons. Polygons can be selected with respect to edges, texts and other polygons.
#
# If a single count is given, shapes from self are selected only if they do interact with the given
# number of (different) shapes from the other layer. If a min and max count is given, shapes from
# 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.
# %DRC%
# @name select_not_interacting
# @brief Selects shapes or regions of self which do not touch or overlap shapes from the other region
# @synopsis layer.select_interacting(other)
# @synopsis layer.select_not_interacting(other)
# @synopsis layer.select_not_interacting(other, count)
# @synopsis layer.select_not_interacting(other, min_count, max_count)
# @synopsis layer.select_not_interacting(other, min_count .. max_count)
# This method selects all shapes or regions from self which do not touch or overlap shapes from the other
# region. Unless self is in raw mode (see \raw), coherent regions are selected from self,
# layer. Unless self is in raw mode (see \raw), coherent regions are selected from self,
# otherwise individual shapes are selected.
# It modifies self to contain the selected shapes. A version which does not modify self
# is \not_interacting.
@ -1740,6 +1779,11 @@ CODE
# This method is available for polygon, text and edge layers. Edges can be selected
# with respect to other edges or polygons. Texts can be selected with respect to
# polygons. Polygons can be selected with respect to edges, texts and other polygons.
#
# If a single count is given, shapes from self are selected only if they do not interact with the given
# number of (different) shapes from the other layer. If a min and max count is given, shapes from
# self are selected only if they interact with less than min_count or more than max_count different shapes
# from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
# %DRC%
# @name intersections
@ -1883,7 +1927,7 @@ CODE
%w(interacting not_interacting).each do |f|
eval <<"CODE"
def #{f}(other)
def #{f}(other, *args)
other.requires_edges_texts_or_region("#{f}")
if self.data.is_a?(RBA::Text)
other.requires_region("#{f}")
@ -1892,12 +1936,40 @@ CODE
else
other.requires_edges_or_region("#{f}")
end
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(:#{f}, *args)))
end
CODE
end
%w(interacting not_interacting overlapping not_overlapping inside not_inside outside not_outside).each do |fi|
%w(interacting not_interacting).each do |fi|
f = "select_" + fi
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
eval <<"CODE"
def #{f}(other, *args)
if :#{fi} != :interacting && :#{fi} != :not_interacting
requires_edges_or_region("#{f}")
requires_same_type(other, "#{f}")
else
requires_edges_texts_or_region("#{f}")
if self.data.is_a?(RBA::Text)
other.requires_region("#{f}")
elsif self.data.is_a?(RBA::Region)
other.requires_edges_texts_or_region("#{f}")
else
other.requires_edges_or_region("#{f}")
end
end
if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(:#{f}, *args))
DRCLayer::new(@engine, self.data)
else
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(:#{f}, *args)))
end
end
CODE
end
%w(overlapping not_overlapping inside not_inside outside not_outside).each do |fi|
f = "select_" + fi
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
eval <<"CODE"
@ -3238,6 +3310,42 @@ CODE
def requires_same_type(other, f)
self.data.class == other.data.class || raise("#{f}: Requires input of the same kind")
end
def minmax_count(f, *args)
if args.size == 0
return []
elsif args.size == 1
a = args[0]
if a.is_a?(Range)
if a.min.to_i <= 0
raise("#{f}: min_count argument must be a positive, non-zero number")
end
return [a.min.to_i, a.max.to_i]
elsif !a.is_a?(1.class)
raise("#{f}: count argument must be an integer number")
elsif a <= 0
raise("#{f}: count argument must be a positive, non-zero number")
else
return [a, a]
end
elsif args.size == 2
amin = args[0]
amax = args[1]
if !amin.is_a?(1.class)
raise("#{f}: min_count argument must be an integer number")
elsif !amax.is_a?(1.class)
raise("#{f}: max_count argument must be an integer number")
elsif amin <= 0
raise("#{f}: min_count argument must be a positive, non-zero number")
elsif amax < amin
raise("#{f}: max_count argument must be larger or equal to min_count")
else
return [amin, amax]
end
else
raise("#{f}: too many arguments")
end
end
private