diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 37481614e..65966361e 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -25,6 +25,7 @@ #include "dbFlatRegion.h" #include "dbFlatEdgePairs.h" #include "dbFlatEdges.h" +#include "dbFlatTexts.h" #include "dbEmptyRegion.h" #include "dbEmptyEdgePairs.h" #include "dbEmptyEdges.h" @@ -375,6 +376,50 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) return output.release (); } +RegionDelegate * +AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) const +{ + if (other.empty ()) { + if (! inverse) { + return new EmptyRegion (); + } else { + return clone (); + } + } else if (empty ()) { + return clone (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatRegion (false)); + region_to_text_interaction_filter filter (output->raw_polygons (), inverse); + + AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); + + for ( ; ! p.at_end (); ++p) { + scanner.insert1 (p.operator-> (), 0); + if (inverse) { + filter.preset (p.operator-> ()); + } + } + + AddressableTextDelivery e (other.addressable_texts ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert2 (e.operator-> (), 0); + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + if (inverse) { + filter.fill_output (); + } + + return output.release (); +} + RegionDelegate * AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const { @@ -468,6 +513,39 @@ AsIfFlatRegion::pull_generic (const Edges &other) const return output.release (); } +TextsDelegate * +AsIfFlatRegion::pull_generic (const Texts &other) const +{ + if (other.empty ()) { + return other.delegate ()->clone (); + } else if (empty ()) { + return new EmptyTexts (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatTexts (false)); + region_to_text_interaction_filter filter (output->raw_texts (), false); + + AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ()); + + for ( ; ! p.at_end (); ++p) { + scanner.insert1 (p.operator-> (), 0); + } + + AddressableTextDelivery e (other.addressable_texts ()); + + 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 { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index fb3a1c548..631026f4d 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -202,6 +202,16 @@ public: return selected_interacting_generic (other, true); } + virtual RegionDelegate *selected_interacting (const Texts &other) const + { + return selected_interacting_generic (other, false); + } + + virtual RegionDelegate *selected_not_interacting (const Texts &other) const + { + return selected_interacting_generic (other, true); + } + virtual RegionDelegate *selected_overlapping (const Region &other) const { return selected_interacting_generic (other, 0, false, false); @@ -227,6 +237,11 @@ public: return pull_generic (other); } + virtual TextsDelegate *pull_interacting (const Texts &other) const + { + return pull_generic (other); + } + virtual RegionDelegate *pull_overlapping (const Region &other) const { return pull_generic (other, 0, false); @@ -247,8 +262,10 @@ 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; 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 *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; 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 f56fc2be6..42510cb7d 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -28,6 +28,7 @@ #include "dbRegionUtils.h" #include "dbDeepEdges.h" #include "dbDeepEdgePairs.h" +#include "dbDeepTexts.h" #include "dbShapeProcessor.h" #include "dbFlatRegion.h" #include "dbHierProcessor.h" @@ -1896,6 +1897,143 @@ public: } }; +struct TextResultInserter +{ + typedef db::Text value_type; + + TextResultInserter (std::unordered_set &result) + : mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Text &e) + { + (*mp_result).insert (e); + } + +private: + std::unordered_set *mp_result; +}; + +class PullWithTextLocalOperation + : public local_operation +{ +public: + PullWithTextLocalOperation () + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + TextResultInserter inserter (result); + region_to_text_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) { + 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 ())); + + scanner.insert1 (&heap.back (), 0); + + } + + 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 ("Pull texts from second by their geometric relation to first")); + } +}; + +class InteractingWithTextLocalOperation + : public local_operation +{ +public: + InteractingWithTextLocalOperation (bool inverse) + : m_inverse (inverse) + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + ResultInserter inserter (layout, result); + region_to_text_interaction_filter filter (inserter, m_inverse); + + 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), 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 ())); + + scanner.insert1 (&heap.back (), 0); + if (m_inverse) { + filter.preset (&heap.back ()); + } + + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + if (m_inverse) { + filter.fill_output (); + } + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + if (!m_inverse) { + return Drop; + } else { + return Copy; + } + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select regions by their geometric relation to texts")); + } + +private: + bool m_inverse; +}; + } RegionDelegate * @@ -2042,4 +2180,70 @@ DeepRegion::pull_generic (const Edges &other) const return res; } +TextsDelegate * +DeepRegion::pull_generic (const Texts &other) const +{ + std::auto_ptr dr_holder; + const db::DeepTexts *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation + dr_holder.reset (new db::DeepTexts (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + // in "inside" mode, the first argument needs to be merged too + const db::DeepLayer &polygons = deep_layer (); + const db::DeepLayer &other_texts = other_deep->deep_layer (); + + DeepLayer dl_out (polygons.derived ()); + + db::PullWithTextLocalOperation op; + + db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (polygons.store ()->threads ()); + proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ()); + + db::DeepTexts *res = new db::DeepTexts (dl_out); + res->set_is_merged (is_merged ()); + return res; +} + +RegionDelegate * +DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) const +{ + // with these flag set to true, the resulting polygons are broken again. + bool split_after = false; + + std::auto_ptr dr_holder; + const db::DeepTexts *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation + dr_holder.reset (new db::DeepTexts (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &polygons = merged_deep_layer (); + + DeepLayer dl_out (polygons.derived ()); + + db::InteractingWithTextLocalOperation op (inverse); + + 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 ()); + proc.set_threads (polygons.store ()->threads ()); + if (split_after) { + proc.set_area_ratio (polygons.store ()->max_area_ratio ()); + proc.set_max_vertex_count (polygons.store ()->max_vertex_count ()); + } + + proc.run (&op, 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 (merged_semantics () || is_merged ()); + } + return res; +} + } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index e1cdc57c3..bf794ec48 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -193,8 +193,10 @@ 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; 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 *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; DeepRegion *apply_filter (const PolygonFilterBase &filter) const; template OutputContainer *processed_impl (const polygon_processor &filter) const; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index db7a95c55..b678b302f 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -459,6 +459,36 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC return dl; } +DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans) +{ + // reuse existing layer + std::pair lff = layer_for_flat (tl::id_of (texts.delegate ())); + if (lff.first) { + return lff.second; + } + + require_singular (); + + unsigned int layer = layout ().insert_layer (); + + db::Shapes *shapes = &initial_cell ().shapes (layer); + db::Box world = db::Box::world (); + + db::TextBuildingHierarchyBuilderShapeReceiver tb; + + std::pair ii = texts.begin_iter (); + db::ICplxTrans ttop = trans * ii.second; + while (! ii.first.at_end ()) { + tb.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes); + ++ii.first; + } + + DeepLayer dl (this, 0 /*singular layout index*/, layer); + m_layers_for_flat [tl::id_of (texts.delegate ())] = std::make_pair (dl.layout_index (), dl.layer ()); + m_flat_region_id [std::make_pair (dl.layout_index (), dl.layer ())] = tl::id_of (texts.delegate ()); + return dl; +} + std::pair DeepShapeStore::layer_for_flat (const db::Region ®ion) const { return layer_for_flat (tl::id_of (region.delegate ())); diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 3c4e678ec..032fb8aad 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -338,7 +338,18 @@ public: * After a flat layer has been created for a region, it can be retrieved * from the region later with layer_for_flat (region). */ - DeepLayer create_from_flat (const db::Edges ®ion, const db::ICplxTrans &trans = db::ICplxTrans ()); + DeepLayer create_from_flat (const db::Edges &edges, const db::ICplxTrans &trans = db::ICplxTrans ()); + + /** + * @brief Creates a new layer from a flat text collection (or the text collection is made flat) + * + * This method is intended for use with singular-created DSS objects (see + * singular constructor). + * + * After a flat layer has been created for a region, it can be retrieved + * from the region later with layer_for_flat (region). + */ + DeepLayer create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans = db::ICplxTrans ()); /** * @brief Gets the layer for a given flat region. diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 1def0413e..73739984f 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -96,6 +96,12 @@ DeepTexts::DeepTexts () // .. nothing yet .. } +DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss) + : AsIfFlatTexts () +{ + m_deep_layer = dss.create_from_flat (other); +} + DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss) : AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si)) { diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index 21da58c39..ef877be8d 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -40,6 +40,7 @@ class DB_PUBLIC DeepTexts { public: DeepTexts (); + DeepTexts (const db::Texts &other, DeepShapeStore &dss); DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss); DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 5ab62f825..ec40deffa 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbRegionDelegate.h" #include "dbEmptyEdges.h" +#include "dbEmptyTexts.h" namespace db { @@ -107,11 +108,14 @@ public: 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_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 TextsDelegate *pull_interacting (const Texts &) const { return new EmptyTexts (); } virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); } diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 23870f6d9..2db262ac4 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -157,6 +157,29 @@ public: } }; +template <> +class shape_reference_translator +{ +public: + typedef db::Text shape_type; + + shape_reference_translator (db::Layout * /*target_layout*/) + { + // .. nothing yet .. + } + + const shape_type &operator() (const shape_type &s) const + { + return s; + } + + template + shape_type operator() (const shape_type &s, const Trans &tr) const + { + return s.transformed (tr); + } +}; + template class shape_reference_translator_with_trans_from_shape_ref { @@ -633,6 +656,7 @@ shape_interactions::intruder_shape (unsigned int id) const template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; @@ -1756,6 +1780,8 @@ local_processor::compute_local_cell (const db::local_processor_conte template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 5ac56c8d4..f3f8bf576 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1322,6 +1322,52 @@ public: return Region (mp_delegate->selected_not_interacting (other)); } + /** + * @brief Selects all polygons of this region which overlap or touch texts from the text collection + * + * Merged semantics applies. + */ + Region &select_interacting (const Texts &other) + { + set_delegate (mp_delegate->selected_interacting (other)); + return *this; + } + + /** + * @brief Selects all polygons of this region which do not overlap or touch texts from the text collection + * + * Merged semantics applies. + */ + Region &select_not_interacting (const Texts &other) + { + set_delegate (mp_delegate->selected_not_interacting (other)); + return *this; + } + + /** + * @brief Returns all polygons of this which overlap or touch texts from the text collection + * + * This method is an out-of-place version of select_interacting. + * + * Merged semantics applies. + */ + Region selected_interacting (const Texts &other) const + { + return Region (mp_delegate->selected_interacting (other)); + } + + /** + * @brief Returns all polygons of this which do not overlap or touch texts from the text collection + * + * This method is an out-of-place version of select_not_interacting. + * + * Merged semantics applies. + */ + Region selected_not_interacting (const Texts &other) const + { + return Region (mp_delegate->selected_not_interacting (other)); + } + /** * @brief Selects all polygons of this region which overlap polygons from the other region * @@ -1388,6 +1434,16 @@ public: return Edges (mp_delegate->pull_interacting (other)); } + /** + * @brief Returns all texts of "other" which are interacting (touching or overlapping with) polygons of this region + * + * Merged semantics applies. + */ + Texts pull_interacting (const Texts &other) const + { + return Texts (mp_delegate->pull_interacting (other)); + } + /** * @brief Returns all polygons of "other" which are interacting (touching or overlapping with) polygons of this region * diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 9909145f2..f38e25688 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -28,6 +28,7 @@ #include "dbPolygon.h" #include "dbEdges.h" +#include "dbTexts.h" #include "dbEdgePairs.h" #include "dbEdgePairRelations.h" #include "tlUniqueId.h" @@ -294,12 +295,15 @@ public: 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_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 TextsDelegate *pull_interacting (const Texts &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 3214fa747..6748fc954 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -350,6 +350,61 @@ region_to_edge_interaction_filter_base::fill_output () template class region_to_edge_interaction_filter_base; 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) +{ + // .. nothing yet .. +} + +template +void +region_to_text_interaction_filter_base::preset (const OutputType *s) +{ + m_seen.insert (s); +} + +template +void +region_to_text_interaction_filter_base::add (const db::Polygon *p, size_t, const db::Text *t, size_t) +{ + const OutputType *o = 0; + tl::select (o, p, t); + + if ((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 + db::Point pt; + pt += t->trans ().disp (); + if (p->box ().contains (pt) && db::inside_poly (p->begin_edge (), pt) >= 0) { + if (m_inverse) { + m_seen.erase (o); + } else { + m_seen.insert (o); + put (*o); + } + } + + } +} + +template +void +region_to_text_interaction_filter_base::fill_output () +{ + for (typename std::set::const_iterator s = m_seen.begin (); s != m_seen.end (); ++s) { + put (**s); + } +} + +// explicit instantiations +template class region_to_text_interaction_filter_base; +template class region_to_text_interaction_filter_base; + // ------------------------------------------------------------------------------------- // Polygon snapping diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 46ef4d9cc..4229e087b 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -524,6 +524,52 @@ private: OutputContainer *mp_output; }; +/** + * @brief A helper class for the region to text interaction functionality + */ +template +class DB_PUBLIC region_to_text_interaction_filter_base + : public db::box_scanner_receiver2 +{ +public: + region_to_text_interaction_filter_base (bool inverse); + + void preset (const OutputType *s); + void add (const db::Polygon *p, size_t, const db::Text *e, size_t); + void fill_output (); + +protected: + virtual void put (const OutputType &s) const = 0; + +private: + std::set m_seen; + bool m_inverse; +}; + +/** + * @brief A helper class for the region to text interaction functionality + */ +template +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) + { + // .. nothing yet .. + } + +protected: + virtual void put (const OutputType &poly) const + { + mp_output->insert (poly); + } + +private: + OutputContainer *mp_output; +}; + template static inline C snap_to_grid (C c, C g) { diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 54b210363..099ee25d4 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1509,6 +1509,42 @@ Class decl_Region ("db", "Region", "\n" "This method has been introduced in version 0.25\n" ) + + method ("interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_interacting, gsi::arg ("other"), + "@brief Returns the polygons of this region which overlap or touch texts\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"), + "@brief Returns the polygons of this region which do not overlap or touch texts\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"), + "@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" + "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"), + "@brief Selects the polygons of this region which do not overlap or touch texts\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.27\n" + ) + method ("overlapping", &db::Region::selected_overlapping, gsi::arg ("other"), "@brief Returns the polygons of this region which overlap polygons from the other region\n" "\n" @@ -1580,6 +1616,16 @@ Class decl_Region ("db", "Region", "\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 texts 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 text collection after the texts 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.27\n" + ) + method ("is_box?", &db::Region::is_box, "@brief Returns true, if the region is a simple box\n" "\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 10d95ea3a..22b4e6ef3 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1598,6 +1598,59 @@ TEST(28b_snap) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds"); } +TEST(29_InteractionsWithTexts) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_texts_l2.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l8 = ly.get_layer (db::LayerProperties (8, 0)); + + db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Region polygons8 (db::RecursiveShapeIterator (ly, top_cell, l8), dss); + + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + db::Region polygons; + polygons = polygons8.selected_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons); + + polygons = polygons8.selected_not_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), polygons); + + { + db::Region polygons8_copy = polygons8; + polygons8_copy.select_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), polygons8_copy); + } + + { + db::Region polygons8_copy = polygons8; + polygons8_copy.select_not_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), polygons8_copy); + } + + { + db::Texts t = polygons8.pull_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), t); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au29.gds"); +} + TEST(100_Integration) { db::Layout ly; diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 86f52f6db..6addaa424 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -1495,6 +1495,84 @@ TEST(33b_snap) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds"); } +TEST(34a) +{ + db::Region r; + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + 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 (false); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (r.selected_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + 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 (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))))); + EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + rr.select_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10))))); + EXPECT_EQ (rr.to_string (), "(0,0;0,200;100,200;100,0)"); + + r.clear (); + r.insert(db::Box (db::Point (1000, 0), db::Point (6000, 4000))); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000))))).to_string (), ""); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 2000))))).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)"); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000)))).selected_interacting (r).to_string (), ""); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 2000)))).selected_interacting (r).to_string (), "('abc',r0 2000,2000)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000))))).to_string (), ""); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000)))).selected_interacting (r).to_string (), ""); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (1000, 2000))))).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)"); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (1000, 2000)))).selected_interacting (r).to_string (), "('abc',r0 1000,2000)"); +} + +TEST(34b) +{ + db::Region r; + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + 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 (true); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)"); + 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 (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)"); +} + +TEST(34c) +{ + db::Region r; + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + 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); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (0, 0))))).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;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,200;100,200;100,0;0,0;0,-100)"); +} + +TEST(34d) +{ + db::Region r; + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + 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); + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "('abc',r0 30,30)"); + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (0, 0))))).to_string (), "('abc',r0 0,0)"); + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), ""); +} + TEST(100_Processors) { db::Region r; diff --git a/testdata/algo/deep_region_au29.gds b/testdata/algo/deep_region_au29.gds new file mode 100644 index 000000000..96a5c0c0f Binary files /dev/null and b/testdata/algo/deep_region_au29.gds differ