diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 561b7be6c..7ffc943bb 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -36,12 +36,41 @@ #include "dbBoxScanner.h" #include "dbClip.h" #include "dbPolygonTools.h" +#include "dbHash.h" #include namespace db { +namespace { + +struct ResultCountingInserter +{ + typedef db::Polygon value_type; + + ResultCountingInserter (std::unordered_map > &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 > *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::max ()); + + std::unordered_map > counted_results; + ResultCountingInserter inserter (counted_results); + db::box_scanner2 scanner (report_progress (), progress_desc ()); scanner.reserve1 (size ()); scanner.reserve2 (other.size ()); std::auto_ptr output (new FlatRegion (false)); - region_to_edge_interaction_filter filter (output->raw_polygons (), inverse); + region_to_edge_interaction_filter 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::box_convert ()); - if (inverse) { - filter.fill_output (); + // select hits based on their count + + for (std::unordered_map >::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::max ()); + + std::unordered_map > counted_results; + ResultCountingInserter inserter (counted_results); + db::box_scanner2 scanner (report_progress (), progress_desc ()); scanner.reserve1 (size ()); scanner.reserve2 (other.size ()); - std::auto_ptr output (new FlatRegion (true)); - region_to_text_interaction_filter filter (*output, inverse); + region_to_text_interaction_filter 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::box_convert ()); - if (inverse) { - filter.fill_output (); + // select hits based on their count + + std::auto_ptr output (new FlatRegion (true)); + + for (std::unordered_map >::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::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 output (new FlatRegion (false)); + std::map interaction_counts; n = 0; - std::set 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 ::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); } } diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index 791e0dddf..7e998ef45 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -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::max ()) const; + virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const; + virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits::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; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 4dc4c53ba..155cc4792 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1487,8 +1487,8 @@ class InteractingLocalOperation : public local_operation { 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::max ()) { + + for (std::set::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::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::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::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 selected; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { - ++n; - selected.insert (i->second); + std::map 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::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { - if ((selected.find (n) == selected.end ()) == m_inverse) { + size_t count = 0; + std::map ::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 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 *mp_result; }; +struct ResultCountingInserter +{ + typedef db::Polygon value_type; + + ResultCountingInserter (db::Layout *layout, std::unordered_map &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 *mp_result; +}; + struct EdgeResultInserter { typedef db::Edge value_type; @@ -1690,8 +1737,8 @@ class InteractingWithEdgeLocalOperation : public local_operation { 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 &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); + std::unordered_map counted_results; + bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); db::box_scanner2 scanner; - ResultInserter inserter (layout, result); - region_to_edge_interaction_filter filter (inserter, m_inverse); + ResultCountingInserter inserter (layout, counted_results); + region_to_edge_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); + std::set intruder_ids; for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { for (shape_interactions::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::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + } + std::list heap; for (shape_interactions::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::box_convert ()); - if (m_inverse) { - filter.fill_output (); + + // select hits based on their count + + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + for (std::unordered_map::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 intruder_ids; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + intruder_ids.insert (*j); + } + } + + for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + } + std::list heap; for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { @@ -1888,8 +1961,8 @@ class InteractingWithTextLocalOperation : public local_operation { 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 &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); + std::unordered_map counted_results; + bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); db::box_scanner2 scanner; - ResultInserter inserter (layout, result); - region_to_text_interaction_filter filter (inserter, m_inverse); + ResultCountingInserter inserter (layout, counted_results); + region_to_text_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { - scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + std::set intruder_ids; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + intruder_ids.insert (*j); } } + for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + } + std::list heap; for (shape_interactions::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::box_convert ()); - if (m_inverse) { - filter.fill_output (); + + // select hits based on their count + + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + for (std::unordered_map::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::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 proc (const_cast (&polygons.layout ()), const_cast (&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::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 proc (const_cast (&polygons.layout ()), const_cast (&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 proc (const_cast (&polygons.layout ()), const_cast (&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 ()); diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 9baed798b..e5e2adda2 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -188,9 +188,9 @@ private: std::pair 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; diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index 78a0b6a55..64015ca41 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -717,7 +717,7 @@ InteractionDetector::edge (bool north, bool enter, property_type p) for (std::set ::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 ::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)); } } diff --git a/src/db/db/dbEdgeProcessor.h b/src/db/db/dbEdgeProcessor.h index 7aff70ea8..836aa48d0 100644 --- a/src/db/db/dbEdgeProcessor.h +++ b/src/db/db/dbEdgeProcessor.h @@ -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); diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 2a862a7c7..c5e35ac86 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -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 (); } diff --git a/src/db/db/dbHash.h b/src/db/db/dbHash.h index 26d41ee3d..f73038fc1 100644 --- a/src/db/db/dbHash.h +++ b/src/db/db/dbHash.h @@ -443,6 +443,19 @@ namespace std return hf; } }; + + /** + * @brief Create a pointer hash from the pointer's value + */ + template + struct ptr_hash_from_value + { + size_t operator() (const X *ptr) const + { + return ptr ? hash () (*ptr) : 0; + } + }; + } #endif diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index b66f13c2b..0278ed4c5 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -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::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::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::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::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::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::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::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::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::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::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::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::max ()) const { - return Region (mp_delegate->selected_not_interacting (other)); + return Region (mp_delegate->selected_not_interacting (other, min_count, max_count)); } /** diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 1f460c9e3..928bbe114 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -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; diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index deb735ce7..ee2e54f4d 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -364,8 +364,8 @@ Poly2PolyCheckBase::enter (const db::Polygon &o1, size_t p1, const db::Polygon & // RegionToEdgeInteractionFilterBase implementation template -region_to_edge_interaction_filter_base::region_to_edge_interaction_filter_base (bool inverse) - : m_inverse (inverse) +region_to_edge_interaction_filter_base::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::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::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; // RegionToTextInteractionFilterBase implementation template -region_to_text_interaction_filter_base::region_to_text_interaction_filter_base (bool inverse) - : m_inverse (inverse) +region_to_text_interaction_filter_base::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::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::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); } } diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 7232b877e..2f9f31bc5 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -596,7 +596,7 @@ class DB_PUBLIC region_to_edge_interaction_filter_base : public db::box_scanner_receiver2 { 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 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 { public: - region_to_edge_interaction_filter (OutputContainer &output, bool inverse) - : region_to_edge_interaction_filter_base (inverse), mp_output (&output) + region_to_edge_interaction_filter (OutputContainer &output, bool inverse, bool get_all = false) + : region_to_edge_interaction_filter_base (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 { 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 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 { public: - region_to_text_interaction_filter (OutputContainer &output, bool inverse) - : region_to_text_interaction_filter_base (inverse), mp_output (&output) + region_to_text_interaction_filter (OutputContainer &output, bool inverse, bool get_all = false) + : region_to_text_interaction_filter_base (inverse, get_all), mp_output (&output) { // .. nothing yet .. } diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index b5ff0f78e..68966276b 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1476,100 +1476,172 @@ Class 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::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::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::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::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::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::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::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::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::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::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::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::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" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 8cf5dc65f..4301525aa 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -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; diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 7fcbf2ac5..0d74749d5 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -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; diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 1c1b4ba49..fc91bdaf0 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -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