diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 7e31ca54a..a80066242 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -27,6 +27,7 @@ #include "dbFlatEdges.h" #include "dbEmptyRegion.h" #include "dbEmptyEdgePairs.h" +#include "dbEmptyEdges.h" #include "dbRegion.h" #include "dbRegionUtils.h" #include "dbShapeProcessor.h" @@ -337,7 +338,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) 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 (output->raw_polygons (), inverse); AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); @@ -423,6 +424,92 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo return output.release (); } +EdgesDelegate * +AsIfFlatRegion::pull_generic (const Edges &other) const +{ + if (other.empty ()) { + return other.delegate ()->clone (); + } else if (empty ()) { + return new EmptyEdges (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatEdges (false)); + region_to_edge_interaction_filter filter (output->raw_edges (), false); + + AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); + + for ( ; ! p.at_end (); ++p) { + scanner.insert1 (p.operator-> (), 0); + } + + AddressableEdgeDelivery e (other.addressable_edges ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert2 (e.operator-> (), 0); + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + return output.release (); +} + +RegionDelegate * +AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const +{ + db::EdgeProcessor ep (report_progress (), progress_desc ()); + ep.set_base_verbosity (base_verbosity ()); + + // shortcut + if (empty ()) { + return clone (); + } else if (other.empty ()) { + return new EmptyRegion (); + } + + size_t n = 1; + for (RegionIterator p = other.begin (); ! p.at_end (); ++p, ++n) { + if (p->box ().touches (bbox ())) { + ep.insert (*p, n); + } + } + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + if (mode > 0 || p->box ().touches (other.bbox ())) { + ep.insert (*p, 0); + } + } + + db::InteractionDetector id (mode, 0); + id.set_include_touching (touching); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + std::auto_ptr output (new FlatRegion (false)); + + n = 0; + std::set selected; + for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { + ++n; + selected.insert (i->second); + } + + output->reserve (n); + + n = 1; + for (RegionIterator p = other.begin (); ! p.at_end (); ++p, ++n) { + if (selected.find (n) != selected.end ()) { + output->raw_polygons ().insert (*p); + } + } + + return output.release (); +} + template void AsIfFlatRegion::produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes) diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index b6c1b3e93..35824d0c8 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -205,6 +205,26 @@ public: return selected_interacting_generic (other, 0, false, true); } + virtual RegionDelegate *pull_inside (const Region &other) const + { + return pull_generic (other, -1, true); + } + + virtual RegionDelegate *pull_interacting (const Region &other) const + { + return pull_generic (other, 0, true); + } + + virtual EdgesDelegate *pull_interacting (const Edges &other) const + { + return pull_generic (other); + } + + virtual RegionDelegate *pull_overlapping (const Region &other) const + { + return pull_generic (other, 0, false); + } + virtual RegionDelegate *in (const Region &other, bool invert) const; virtual bool equals (const Region &other) const; @@ -220,6 +240,8 @@ protected: 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) const; RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; + RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; + EdgesDelegate *pull_generic (const Edges &other) const; template static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes); diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 149555c20..383143703 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1617,8 +1617,82 @@ private: mutable db::EdgeProcessor m_ep; }; +class PullLocalOperation + : public local_operation +{ +public: + PullLocalOperation (int mode, bool touching) + : m_mode (mode), m_touching (touching) + { + // .. nothing yet .. + } + + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + m_ep.clear (); + + std::set others; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j)); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::PolygonRef &subject = interactions.subject_shape (i->first); + for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { + m_ep.insert (*e, 0); + } + } + + size_t n = 1; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o, ++n) { + for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { + m_ep.insert (*e, n); + } + } + + db::InteractionDetector id (m_mode, 0); + id.set_include_touching (m_touching); + db::EdgeSink es; + m_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); + } + + n = 1; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o, ++n) { + if (selected.find (n) != selected.end ()) { + result.insert (*o); + } + } + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + return Drop; + } + + virtual std::string description () const + { + return tl::to_string (tr ("Pull regions by their geometric relation to first (interacting, inside)")); + } + +private: + int m_mode; + bool m_touching; + mutable db::EdgeProcessor m_ep; +}; + struct ResultInserter { + typedef db::Polygon value_type; + ResultInserter (db::Layout *layout, std::unordered_set &result) : mp_layout (layout), mp_result (&result) { @@ -1635,6 +1709,25 @@ private: std::unordered_set *mp_result; }; +struct EdgeResultInserter +{ + typedef db::Edge value_type; + + EdgeResultInserter (std::unordered_set &result) + : mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Edge &e) + { + (*mp_result).insert (e); + } + +private: + std::unordered_set *mp_result; +}; + class InteractingWithEdgeLocalOperation : public local_operation { @@ -1652,7 +1745,7 @@ public: ResultInserter inserter (layout, result); region_to_edge_interaction_filter filter (inserter, m_inverse); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { m_scanner.insert2 (& interactions.intruder_shape (*j), 0); } @@ -1688,7 +1781,7 @@ public: virtual std::string description () const { - return tl::to_string (tr ("Select regions by their geometric relation (interacting, inside, outside ..)")); + return tl::to_string (tr ("Select regions by their geometric relation to edges")); } private: @@ -1696,6 +1789,55 @@ private: mutable db::box_scanner2 m_scanner; }; +class PullWithEdgeLocalOperation + : public local_operation +{ +public: + PullWithEdgeLocalOperation () + { + // .. nothing yet .. + } + + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + m_scanner.clear (); + + EdgeResultInserter inserter (result); + region_to_edge_interaction_filter filter (inserter, false); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + m_scanner.insert2 (& interactions.intruder_shape (*j), 0); + } + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRef &subject = interactions.subject_shape (i->first); + heap.push_back (subject.obj ().transformed (subject.trans ())); + + m_scanner.insert1 (&heap.back (), 0); + + } + + m_scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + return Drop; + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select edges from second by their geometric relation to first")); + } + +private: + mutable db::box_scanner2 m_scanner; +}; + } RegionDelegate * @@ -1766,4 +1908,60 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) cons return res; } +RegionDelegate * +DeepRegion::pull_generic (const Region &other, int mode, bool touching) const +{ + // with these flag set to true, the resulting polygons are broken again. + bool split_after = false; + + const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + return db::AsIfFlatRegion::pull_generic (other, mode, touching); + } + + ensure_merged_polygons_valid (); + + DeepLayer dl_out (m_deep_layer.derived ()); + + db::PullLocalOperation op (mode, touching); + + db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (m_deep_layer.store ()->threads ()); + if (split_after) { + proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); + proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + } + + proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + db::DeepRegion *res = new db::DeepRegion (dl_out); + if (! split_after) { + res->set_is_merged (true); + } + return res; +} + +EdgesDelegate * +DeepRegion::pull_generic (const Edges &other) const +{ + const db::DeepEdges *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + return db::AsIfFlatRegion::pull_generic (other); + } + + ensure_merged_polygons_valid (); + + DeepLayer dl_out (m_deep_layer.derived ()); + + db::PullWithEdgeLocalOperation op; + + db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (m_deep_layer.store ()->threads ()); + proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + return new db::DeepEdges (dl_out); +} + } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index ce554ffb9..2f70eb2fd 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -240,6 +240,8 @@ private: 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) const; RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; + RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; + EdgesDelegate *pull_generic (const Edges &other) const; const DeepLayer &merged_deep_layer () const { diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index d57a8e512..0ea403ebe 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -26,6 +26,7 @@ #include "dbCommon.h" #include "dbRegionDelegate.h" +#include "dbEmptyEdges.h" namespace db { @@ -106,6 +107,10 @@ public: virtual RegionDelegate *selected_not_interacting (const Edges &) 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 (); } + virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); } + virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); } + virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); } virtual bool has_valid_polygons () const { return true; } diff --git a/src/db/db/dbFlatEdges.h b/src/db/db/dbFlatEdges.h index e1a80f014..415a0ca54 100644 --- a/src/db/db/dbFlatEdges.h +++ b/src/db/db/dbFlatEdges.h @@ -178,6 +178,8 @@ public: } } + db::Shapes &raw_edges () { return m_edges; } + protected: virtual void merged_semantics_changed (); virtual Box compute_bbox () const; @@ -187,8 +189,6 @@ protected: private: friend class AsIfFlatEdges; - db::Shapes &raw_edges () { return m_edges; } - FlatEdges &operator= (const FlatEdges &other); bool m_is_merged; diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 1c6e5ff37..b8f96c109 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1355,6 +1355,46 @@ public: return Region (mp_delegate->selected_not_overlapping (other)); } + /** + * @brief Returns all polygons of "other" which are inside polygons of this region + * + * Merged semantics applies. + */ + Region pull_inside (const Region &other) const + { + return Region (mp_delegate->pull_inside (other)); + } + + /** + * @brief Returns all edges of "other" which are interacting (touching or overlapping with) polygons of this region + * + * Merged semantics applies. + */ + Edges pull_interacting (const Edges &other) const + { + return Edges (mp_delegate->pull_interacting (other)); + } + + /** + * @brief Returns all polygons of "other" which are interacting (touching or overlapping with) polygons of this region + * + * Merged semantics applies. + */ + Region pull_interacting (const Region &other) const + { + return Region (mp_delegate->pull_interacting (other)); + } + + /** + * @brief Returns all polygons of "other" which are overlapping with polygons of this region + * + * Merged semantics applies. + */ + Region pull_overlapping (const Region &other) const + { + return Region (mp_delegate->pull_overlapping (other)); + } + /** * @brief Returns the holes * diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 8fe79edb9..5bfea5e07 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -294,6 +294,10 @@ public: virtual RegionDelegate *selected_not_interacting (const Edges &other) 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; + virtual RegionDelegate *pull_interacting (const Region &other) const = 0; + virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0; + virtual RegionDelegate *pull_overlapping (const Region &other) const = 0; virtual RegionDelegate *in (const Region &other, bool invert) const = 0; virtual const db::Polygon *nth (size_t n) const = 0; diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 82a70313f..90afa9148 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -288,22 +288,47 @@ Poly2PolyCheckBase::enter (const db::Polygon &o1, size_t p1, const db::Polygon & // ------------------------------------------------------------------------------------- // RegionToEdgeInteractionFilterBase implementation -RegionToEdgeInteractionFilterBase::RegionToEdgeInteractionFilterBase (bool inverse) +namespace +{ + +template +struct edge_or_polygon; + +template <> +struct edge_or_polygon +{ + const db::Polygon *operator() (const db::Polygon *p, const db::Edge *) const { return p; } +}; + +template <> +struct edge_or_polygon +{ + const db::Edge *operator() (const db::Polygon *, const db::Edge *e) const { return e; } +}; + +} + +template +region_to_edge_interaction_filter_base::region_to_edge_interaction_filter_base (bool inverse) : m_inverse (inverse) { // .. nothing yet .. } +template void -RegionToEdgeInteractionFilterBase::preset (const db::Polygon *poly) +region_to_edge_interaction_filter_base::preset (const OutputType *s) { - m_seen.insert (poly); + m_seen.insert (s); } +template void -RegionToEdgeInteractionFilterBase::add (const db::Polygon *p, size_t, const db::Edge *e, size_t) +region_to_edge_interaction_filter_base::add (const db::Polygon *p, size_t, const db::Edge *e, size_t) { - if ((m_seen.find (p) == m_seen.end ()) != m_inverse) { + const OutputType *o = edge_or_polygon () (p, e); + + if ((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 @@ -320,23 +345,28 @@ RegionToEdgeInteractionFilterBase::add (const db::Polygon *p, size_t, const db:: if (interacts) { if (m_inverse) { - m_seen.erase (p); + m_seen.erase (o); } else { - m_seen.insert (p); - put (*p); + m_seen.insert (o); + put (*o); } } } } +template void -RegionToEdgeInteractionFilterBase::fill_output () +region_to_edge_interaction_filter_base::fill_output () { - for (std::set::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) { - put (**p); + for (typename std::set::const_iterator s = m_seen.begin (); s != m_seen.end (); ++s) { + put (**s); } } +// explicit instantiations +template class region_to_edge_interaction_filter_base; +template class region_to_edge_interaction_filter_base; + } diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index ce847fd9e..9e082f582 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -481,40 +481,41 @@ public: /** * @brief A helper class for the region to edge interaction functionality */ -class DB_PUBLIC RegionToEdgeInteractionFilterBase +template +class DB_PUBLIC region_to_edge_interaction_filter_base : public db::box_scanner_receiver2 { public: - RegionToEdgeInteractionFilterBase (bool inverse); + region_to_edge_interaction_filter_base (bool inverse); - void preset (const db::Polygon *poly); + void preset (const OutputType *s); void add (const db::Polygon *p, size_t, const db::Edge *e, size_t); void fill_output (); protected: - virtual void put (const db::Polygon &poly) const = 0; + virtual void put (const OutputType &s) const = 0; private: - std::set m_seen; + std::set m_seen; bool m_inverse; }; /** * @brief A helper class for the region to edge interaction functionality */ -template +template class DB_PUBLIC_TEMPLATE region_to_edge_interaction_filter - : public RegionToEdgeInteractionFilterBase + : public region_to_edge_interaction_filter_base { public: region_to_edge_interaction_filter (OutputContainer &output, bool inverse) - : RegionToEdgeInteractionFilterBase (inverse), mp_output (&output) + : region_to_edge_interaction_filter_base (inverse), mp_output (&output) { // .. nothing yet .. } protected: - virtual void put (const db::Polygon &poly) const + virtual void put (const OutputType &poly) const { mp_output->insert (poly); } diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 16a5d5883..cfb6bf25c 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1600,6 +1600,49 @@ Class decl_Region ("db", "Region", "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" ) + + method ("pull_inside", &db::Region::pull_inside, gsi::arg ("other"), + "@brief Returns all polygons of \"other\" which are inside polygons of this region\n" + "The \"pull_...\" methods are similar to \"selected_...\" but work the opposite way: they " + "select shapes from the argument region rather than self. In a deep (hierarchical) context " + "the output region will be hierarchically aligned with self, so the \"pull_...\" methods " + "provide a way for rehierarchisation.\n" + "\n" + "@return The region after the polygons have been selected (from other)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.26.1\n" + ) + + method ("pull_overlapping", &db::Region::pull_overlapping, gsi::arg ("other"), + "@brief Returns all polygons of \"other\" which are overlapping polygons of this region\n" + "See \\pull_inside for a description of the \"pull_...\" methods.\n" + "\n" + "@return The region after the polygons have been selected (from other)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.26.1\n" + ) + + method ("pull_interacting", static_cast (&db::Region::pull_interacting), gsi::arg ("other"), + "@brief Returns all polygons of \"other\" which are interacting with (overlapping, touching) polygons of this region\n" + "See \\pull_inside for a description of the \"pull_...\" methods.\n" + "\n" + "@return The region after the polygons have been selected (from other)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.26.1\n" + ) + + method ("pull_interacting", static_cast (&db::Region::pull_interacting), gsi::arg ("other"), + "@brief Returns all edges of \"other\" which are interacting with polygons of this region\n" + "See \\pull_inside for a description of the \"pull_...\" methods.\n" + "\n" + "@return The edge collection after the edges have been selected (from other)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.26.1\n" + ) + method ("is_box?", &db::Region::is_box, "@brief Returns true, if the region is a simple box\n" "\n"