diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index 968988311..d3b67790d 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -26,8 +26,11 @@ #include "dbFlatRegion.h" #include "dbFlatEdges.h" #include "dbEmptyTexts.h" +#include "dbEmptyRegion.h" #include "dbTexts.h" #include "dbBoxConvert.h" +#include "dbRegion.h" +#include "dbTextsUtils.h" #include @@ -273,5 +276,99 @@ AsIfFlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into } } +TextsDelegate * +AsIfFlatTexts::selected_interacting_generic (const Region &other, bool inverse) const +{ + // shortcuts + if (other.empty () || empty ()) { + return new EmptyTexts (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableTextDelivery e (begin (), has_valid_texts ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert1 (e.operator-> (), 0); + } + + AddressablePolygonDelivery p = other.addressable_polygons (); + + for ( ; ! p.at_end (); ++p) { + scanner.insert2 (p.operator-> (), 1); + } + + std::auto_ptr output (new FlatTexts (true)); + + if (! inverse) { + + text_to_region_interaction_filter filter (*output); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } else { + + std::set interacting; + text_to_region_interaction_filter > filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (TextsIterator o (begin ()); ! o.at_end (); ++o) { + if (interacting.find (*o) == interacting.end ()) { + output->insert (*o); + } + } + + } + + return output.release (); +} + +RegionDelegate * +AsIfFlatTexts::pull_generic (const Region &other) const +{ + // shortcuts + if (other.empty () || empty ()) { + return new EmptyRegion (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableTextDelivery e (begin (), true); + + for ( ; ! e.at_end (); ++e) { + scanner.insert1 (e.operator-> (), 0); + } + + AddressablePolygonDelivery p = other.addressable_merged_polygons (); + + for ( ; ! p.at_end (); ++p) { + scanner.insert2 (p.operator-> (), 1); + } + + std::auto_ptr output (new FlatRegion (true)); + + text_to_region_interaction_filter filter (*output); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + return output.release (); +} + +RegionDelegate * +AsIfFlatTexts::pull_interacting (const Region &other) const +{ + return pull_generic (other); +} + +TextsDelegate * +AsIfFlatTexts::selected_interacting (const Region &other) const +{ + return selected_interacting_generic (other, false); +} + +TextsDelegate * +AsIfFlatTexts::selected_not_interacting (const Region &other) const +{ + return selected_interacting_generic (other, true); +} + } diff --git a/src/db/db/dbAsIfFlatTexts.h b/src/db/db/dbAsIfFlatTexts.h index a2236cc7f..f10d7bdea 100644 --- a/src/db/db/dbAsIfFlatTexts.h +++ b/src/db/db/dbAsIfFlatTexts.h @@ -30,6 +30,8 @@ namespace db { +class Region; + /** * @brief Provides default flat implementations */ @@ -69,6 +71,10 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; + virtual RegionDelegate *pull_interacting (const Region &) const; + virtual TextsDelegate *selected_interacting (const Region &other) const; + virtual TextsDelegate *selected_not_interacting (const Region &other) const; + protected: void update_bbox (const db::Box &box); void invalidate_bbox (); @@ -80,6 +86,8 @@ private: mutable db::Box m_bbox; virtual db::Box compute_bbox () const; + virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const; + virtual RegionDelegate *pull_generic (const Region &other) const; }; } diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 5f556ad5a..fd99ab58a 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -1285,7 +1285,7 @@ public: } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 0); } @@ -1302,7 +1302,7 @@ public: edge_to_region_interaction_filter > filter (interacting); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); if (interacting.find (subject) == interacting.end ()) { result.insert (subject); @@ -1381,7 +1381,7 @@ public: } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 1); } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 2dc7f6a0c..e1cdc57c3 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -176,6 +176,7 @@ protected: private: friend class DeepEdges; + friend class DeepTexts; DeepRegion &operator= (const DeepRegion &other); diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 4878f95a1..3145b2bf3 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -27,8 +27,13 @@ #include "dbDeepRegion.h" #include "dbCellMapping.h" #include "dbLayoutUtils.h" +#include "dbLocalOperation.h" +#include "dbTextsUtils.h" +#include "dbHierProcessor.h" +#include "dbRegion.h" #include +#include namespace db { @@ -384,5 +389,210 @@ void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type int m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl); } +namespace { + +class Text2PolygonInteractingLocalOperation + : public local_operation +{ +public: + Text2PolygonInteractingLocalOperation (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; + + 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::Text &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 0); + } + + std::list heap; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + heap.push_back (o->obj ().transformed (o->trans ())); + scanner.insert2 (& heap.back (), 1); + } + + if (m_inverse) { + + std::unordered_set interacting; + text_to_region_interaction_filter > filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::Text &subject = interactions.subject_shape (i->first); + if (interacting.find (subject) == interacting.end ()) { + result.insert (subject); + } + } + + } else { + + text_to_region_interaction_filter > filter (result); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + if (m_inverse) { + return Copy; + } else { + return Drop; + } + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select interacting texts")); + } + +private: + bool m_inverse; +}; + +struct ResultInserter +{ + typedef db::Polygon value_type; + + ResultInserter (db::Layout *layout, std::unordered_set &result) + : mp_layout (layout), mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Polygon &p) + { + (*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ())); + } + +private: + db::Layout *mp_layout; + std::unordered_set *mp_result; +}; + +class Text2PolygonPullLocalOperation + : public local_operation +{ +public: + Text2PolygonPullLocalOperation () + { + // .. 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; + + 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::Text &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 1); + } + + std::list heap; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + heap.push_back (o->obj ().transformed (o->trans ())); + scanner.insert2 (& heap.back (), 0); + } + + ResultInserter inserter (layout, result); + text_to_region_interaction_filter filter (inserter); + 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 interacting regions")); + } +}; + +} + +TextsDelegate * +DeepTexts::selected_interacting_generic (const Region &other, bool inverse) const +{ + std::auto_ptr dr_holder; + const db::DeepRegion *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::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &texts = deep_layer (); + + DeepLayer dl_out (texts.derived ()); + + db::Text2PolygonInteractingLocalOperation op (inverse); + + db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (other.base_verbosity ()); + proc.set_threads (texts.store ()->threads ()); + + proc.run (&op, texts.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + return new db::DeepTexts (dl_out); +} + +RegionDelegate *DeepTexts::pull_generic (const Region &other) const +{ + std::auto_ptr dr_holder; + const db::DeepRegion *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::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &texts = deep_layer (); + const db::DeepLayer &other_polygons = other_deep->merged_deep_layer (); + + DeepLayer dl_out (other_polygons.derived ()); + + db::Text2PolygonPullLocalOperation op; + + db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ()); + proc.set_base_verbosity (other.base_verbosity ()); + proc.set_threads (texts.store ()->threads ()); + + proc.run (&op, texts.layer (), other_polygons.layer (), dl_out.layer ()); + + return new db::DeepRegion (dl_out); +} } diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index 384febb33..21da58c39 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -95,6 +95,9 @@ private: void init (); DeepTexts *apply_filter (const TextFilterBase &filter) const; + + virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const; + virtual RegionDelegate *pull_generic (const Region &other) const; }; } diff --git a/src/db/db/dbEmptyTexts.cc b/src/db/db/dbEmptyTexts.cc index 1037a078b..9ef48abc2 100644 --- a/src/db/db/dbEmptyTexts.cc +++ b/src/db/db/dbEmptyTexts.cc @@ -84,5 +84,23 @@ EmptyTexts::less (const Texts &other) const return other.empty () ? false : true; } +RegionDelegate * +EmptyTexts::pull_interacting (const Region &) const +{ + return new EmptyRegion (); +} + +TextsDelegate * +EmptyTexts::selected_interacting (const Region &) const +{ + return new EmptyTexts (); +} + +TextsDelegate * +EmptyTexts::selected_not_interacting (const Region &) const +{ + return new EmptyTexts (); +} + } diff --git a/src/db/db/dbEmptyTexts.h b/src/db/db/dbEmptyTexts.h index 59520928b..99b1623ac 100644 --- a/src/db/db/dbEmptyTexts.h +++ b/src/db/db/dbEmptyTexts.h @@ -75,6 +75,10 @@ public: virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { } virtual void insert_into_as_polygons (Layout *, db::cell_index_type, unsigned int, db::Coord) const { } + virtual RegionDelegate *pull_interacting (const Region &) const; + virtual TextsDelegate *selected_interacting (const Region &) const; + virtual TextsDelegate *selected_not_interacting (const Region &) const; + private: EmptyTexts &operator= (const EmptyTexts &other); }; diff --git a/src/db/db/dbFlatTexts.h b/src/db/db/dbFlatTexts.h index 38a249fbe..90b3e9b24 100644 --- a/src/db/db/dbFlatTexts.h +++ b/src/db/db/dbFlatTexts.h @@ -80,6 +80,8 @@ class DB_PUBLIC FlatTexts : public AsIfFlatTexts { public: + typedef db::Text value_type; + typedef db::layer text_layer_type; typedef text_layer_type::iterator text_iterator_type; diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index c3adf6449..23870f6d9 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -635,6 +635,8 @@ 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; // --------------------------------------------------------------------------------------------- // Helper classes for the LocalProcessor @@ -656,6 +658,12 @@ inline unsigned int shape_flags () return db::ShapeIterator::Edges; } +template <> +inline unsigned int shape_flags () +{ + return db::ShapeIterator::Texts; +} + template struct interaction_registration_shape2shape : db::box_scanner_receiver2 @@ -850,8 +858,11 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u // not very strong, but already useful: the cells interact if there is a layer1 in cell1 // in the common box and a layer2 in the cell2 in the common box - if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, tni1 * cbox, true).at_end () && - ! db::RecursiveShapeIterator (*layout2, cell2, layer2, tni2 * cbox, true).at_end ()) { + // NOTE: don't use overlap mode for the RecursiveShapeIterator as this would not capture dot-like + // objects like texts. Instead safe-shrink the search box and use touching mode ("false" for the last + // argument) + if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, safe_box_enlarged (tni1 * cbox, -1, -1), false).at_end () && + ! db::RecursiveShapeIterator (*layout2, cell2, layer2, safe_box_enlarged (tni2 * cbox, -1, -1), false).at_end ()) { return true; } @@ -929,7 +940,9 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins // not very strong, but already useful: the cells interact if there is a layer in cell // in the common box - if (! db::RecursiveShapeIterator (*layout, cell, layer, tni * cbox, true).at_end ()) { + // NOTE: don't use overlapping mode here, because this will not select point-like objects as texts or + // dot edges. Instead safe-shrink the search box and use touching mode. + if (! db::RecursiveShapeIterator (*layout, cell, layer, safe_box_enlarged (tni * cbox, -1, -1), false).at_end ()) { return true; } @@ -1748,6 +1761,8 @@ 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/dbPolygonTools.h b/src/db/db/dbPolygonTools.h index 2300bde6d..0b5719f65 100644 --- a/src/db/db/dbPolygonTools.h +++ b/src/db/db/dbPolygonTools.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbPolygon.h" +#include "dbText.h" #include #include @@ -346,6 +347,18 @@ bool interact_pe (const Polygon &poly, const Edge &edge) return false; } +/** + * @brief Determines whether the text is inside the polygon + */ +template +bool interact_pt (const Polygon &poly, const Text &text) +{ + typedef typename Text::point_type point_type; + point_type p; + p += text.trans ().disp (); + return (poly.box ().contains (p) && db::inside_poly (poly.begin_edge (), p) >= 0); +} + // Some specializations that map all combinations to template versions inline bool interact (const db::Box &box1, const db::Box &box2) { return box1.touches (box2); } inline bool interact (const db::DBox &box1, const db::DBox &box2) { return box1.touches (box2); } @@ -365,6 +378,10 @@ inline bool interact (const db::DPolygon &poly1, const db::DPolygon &poly inline bool interact (const db::DSimplePolygon &poly1, const db::DPolygon &poly2) { return interact_pp (poly1, poly2); } inline bool interact (const db::DPolygon &poly1, const db::DSimplePolygon &poly2) { return interact_pp (poly1, poly2); } inline bool interact (const db::DSimplePolygon &poly1, const db::DSimplePolygon &poly2) { return interact_pp (poly1, poly2); } +inline bool interact (const db::Polygon &poly, const db::Text &text) { return interact_pt (poly, text); } +inline bool interact (const db::SimplePolygon &poly, const db::Text &text) { return interact_pt (poly, text); } +inline bool interact (const db::DPolygon &poly, const db::DText &text) { return interact_pt (poly, text); } +inline bool interact (const db::DSimplePolygon &poly, const db::DText &text) { return interact_pt (poly, text); } /** * @brief Extract a corner radius from a contour diff --git a/src/db/db/dbTexts.cc b/src/db/db/dbTexts.cc index 1ab956aa0..7683633d5 100644 --- a/src/db/db/dbTexts.cc +++ b/src/db/db/dbTexts.cc @@ -176,6 +176,11 @@ FlatTexts *Texts::flat_texts () return texts; } +void Texts::pull_interacting (Region &output, const Region &other) const +{ + output = Region (mp_delegate->pull_interacting (other)); +} + } namespace tl diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index 173ce1e25..e087b3432 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -447,6 +447,52 @@ public: return Texts (mp_delegate->filtered (filter)); } + /** + * @brief Selects all polygons of the other region set which include the texts of this text collection + * + * Merged semantics applies for the other region. Merged polygons will be selected from the other region + * if merged semantics is enabled. + */ + void pull_interacting (Region &output, const Region &other) const; + + /** + * @brief Selects all texts of this text set which are inside the polygons from the region + */ + Texts &select_interacting (const Region &other) + { + set_delegate (mp_delegate->selected_interacting (other)); + return *this; + } + + /** + * @brief Returns all texts of this text set which are inside the polygons from the region + * + * This method is an out-of-place version of select_interacting. + */ + Texts selected_interacting (const Region &other) const + { + return Texts (mp_delegate->selected_interacting (other)); + } + + /** + * @brief Selects all texts of this text set which are not inside the polygons from the region + */ + Texts &select_not_interacting (const Region &other) + { + set_delegate (mp_delegate->selected_not_interacting (other)); + return *this; + } + + /** + * @brief Returns all texts of this text set which are not inside the polygons from the region + * + * This method is an out-of-place version of select_not_interacting. + */ + Texts selected_not_interacting (const Region &other) const + { + return Texts (mp_delegate->selected_not_interacting (other)); + } + /** * @brief Transforms the text set */ diff --git a/src/db/db/dbTextsDelegate.h b/src/db/db/dbTextsDelegate.h index d25eef6a3..29f9a2c72 100644 --- a/src/db/db/dbTextsDelegate.h +++ b/src/db/db/dbTextsDelegate.h @@ -33,6 +33,7 @@ namespace db { class RecursiveShapeIterator; class Texts; +class Region; class TextFilterBase; class RegionDelegate; class EdgesDelegate; @@ -118,6 +119,10 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const = 0; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const = 0; + virtual RegionDelegate *pull_interacting (const Region &) const = 0; + virtual TextsDelegate *selected_interacting (const Region &other) const = 0; + virtual TextsDelegate *selected_not_interacting (const Region &other) const = 0; + protected: const std::string &progress_desc () const { diff --git a/src/db/db/dbTextsUtils.h b/src/db/db/dbTextsUtils.h index 5b604f89f..4f72c23c9 100644 --- a/src/db/db/dbTextsUtils.h +++ b/src/db/db/dbTextsUtils.h @@ -25,7 +25,10 @@ #include "dbCommon.h" #include "dbTexts.h" +#include "dbBoxScanner.h" +#include "dbPolygonTools.h" #include "tlGlobPattern.h" +#include "tlSelect.h" namespace db { @@ -149,6 +152,44 @@ private: bool m_inverse; }; +/** + * @brief A helper class for the text to region interaction functionality which acts as an text receiver + * + * Note: This special scanner uses pointers to two different objects: texts and polygons. + * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate + * pointers to edges. + * + * There is a special box converter which is able to sort that out as well. + */ +template +class text_to_region_interaction_filter + : public db::box_scanner_receiver2 +{ +public: + text_to_region_interaction_filter (OutputContainer &output) + : mp_output (&output) + { + // .. nothing yet .. + } + + void add (const db::Text *t, size_t, const db::Polygon *p, size_t) + { + const OutputType *tt = 0; + tl::select (tt, t, p); + + if (m_seen.find (tt) == m_seen.end ()) { + if (db::interact (*p, *t)) { + m_seen.insert (tt); + mp_output->insert (*tt); + } + } + } + +private: + OutputContainer *mp_output; + std::set m_seen; +}; + } // namespace db #endif diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 2d375fc40..0eaf6dcff 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -426,13 +426,13 @@ Class dec_Edges ("db", "Edges", constructor ("new", &new_a1, gsi::arg ("array"), "@brief Constructor from a polygon array\n" "\n" - "This constructor creates a region from an array of polygons.\n" + "This constructor creates an edge collection from an array of polygons.\n" "The edges form the contours of the polygons.\n" ) + constructor ("new", &new_a2, gsi::arg ("array"), "@brief Constructor from an edge array\n" "\n" - "This constructor creates a region from an array of edges.\n" + "This constructor creates an edge collection from an array of edges.\n" ) + constructor ("new", &new_b, gsi::arg ("box"), "@brief Box constructor\n" @@ -859,7 +859,7 @@ Class dec_Edges ("db", "Edges", method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"), "@brief Returns the edges of this edge collection which overlap or touch edges from the other edge collection\n" "\n" - "@return A new edge collection containing the edges overlapping or touching edges from the other region\n" + "@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n" "\n" "This method does not merge the edges before they are selected. If you want to select coherent " "edges, make sure the edge collection is merged before this method is used.\n" @@ -867,7 +867,7 @@ Class dec_Edges ("db", "Edges", method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), "@brief Returns the edges of this edge collection which do not overlap or touch edges from the other edge collection\n" "\n" - "@return A new edge collection containing the edges not overlapping or touching edges from the other region\n" + "@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n" "\n" "This method does not merge the edges before they are selected. If you want to select coherent " "edges, make sure the edge collection is merged before this method is used.\n" @@ -889,7 +889,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"), - "@brief Returns the edges from this region which overlap or touch polygons from the region\n" + "@brief Returns the edges from this edge collection which overlap or touch polygons from the region\n" "\n" "@return A new edge collection containing the edges overlapping or touching polygons from the region\n" "\n" @@ -897,7 +897,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), - "@brief Returns the edges from this region which do not overlap or touch polygons from the region\n" + "@brief Returns the edges from this edge collection which do not overlap or touch polygons from the region\n" "\n" "@return A new edge collection containing the edges not overlapping or touching polygons from the region\n" "\n" @@ -905,7 +905,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"), - "@brief Selects the edges from this region which overlap or touch polygons from the region\n" + "@brief Selects the edges from this edge collection which overlap or touch polygons from the region\n" "\n" "@return The edge collection after the edges have been selected (self)\n" "\n" @@ -913,7 +913,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"), - "@brief Selects the edges from this region which do not overlap or touch polygons from the region\n" + "@brief Selects the edges from this edge collection which do not overlap or touch polygons from the region\n" "\n" "@return The edge collection after the edges have been selected (self)\n" "\n" diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 749bcfbc3..9ea593ac3 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -165,6 +165,13 @@ static db::Texts with_match (const db::Texts *r, const std::string &pattern, boo return r->filtered (f); } +static db::Region pull_interacting (const db::Texts *r, const db::Region &other) +{ + db::Region out; + r->pull_interacting (out, other); + return out; +} + Class decl_Texts ("db", "Texts", constructor ("new", &new_v, "@brief Default constructor\n" @@ -397,6 +404,41 @@ Class decl_Texts ("db", "Texts", "If \"inverse\" is false, this method returns the texts matching the pattern.\n" "If \"inverse\" is true, this method returns the texts not matching the pattern.\n" ) + + method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"), + "@brief Returns the texts from this text collection which are inside or on the edge of polygons from the given region\n" + "\n" + "@return A new text collection containing the texts inside or on the edge of polygons from the region\n" + ) + + method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), + "@brief Returns the texts from this text collection which are not inside or on the edge of polygons from the given region\n" + "\n" + "@return A new text collection containing the texts not inside or on the edge of polygons from the region\n" + ) + + method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"), + "@brief Selects the texts from this text collection which are inside or on the edge of polygons from the given region\n" + "\n" + "@return A text collection after the texts have been selected (self)\n" + "\n" + "In contrast to \\interacting, this method will modify self.\n" + ) + + method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"), + "@brief Selects the texts from this text collection which are not inside or on the edge of polygons from the given region\n" + "\n" + "@return A text collection after the texts have been selected (self)\n" + "\n" + "In contrast to \\interacting, this method will modify self.\n" + ) + + method_ext ("pull_interacting", &pull_interacting, gsi::arg ("other"), + "@brief Returns all polygons of \"other\" which are including texts of this text set\n" + "The \"pull_...\" method is similar to \"select_...\" but works the opposite way: it " + "selects 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_...\" method " + "provide a way for rehierarchisation.\n" + "\n" + "@return The region after the polygons have been selected (from other)\n" + "\n" + "Merged semantics applies for the polygon region.\n" + ) + method ("clear", &db::Texts::clear, "@brief Clears the text collection\n" ) + diff --git a/src/db/unit_tests/dbDeepTextsTests.cc b/src/db/unit_tests/dbDeepTextsTests.cc index 78586ed3e..0c30659ab 100644 --- a/src/db/unit_tests/dbDeepTextsTests.cc +++ b/src/db/unit_tests/dbDeepTextsTests.cc @@ -83,3 +83,63 @@ TEST(1_Basics) CHECKPOINT(); db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au1.gds"); } + +TEST(2_Interactions) +{ + 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; + texts2.selected_interacting (polygons8).polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons); + + polygons.clear (); + texts2.selected_not_interacting (polygons8).polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), polygons); + + { + db::Texts texts2_copy = texts2; + texts2_copy.select_interacting (polygons8); + polygons.clear (); + texts2_copy.polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), polygons); + } + + { + db::Texts texts2_copy = texts2; + texts2_copy.select_not_interacting (polygons8); + polygons.clear (); + texts2_copy.polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), polygons); + } + + { + db::Texts texts2_copy = texts2; + db::Region polygons; + texts2_copy.pull_interacting (polygons, polygons8); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), polygons); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au2.gds"); +} diff --git a/testdata/algo/deep_texts_au1.gds b/testdata/algo/deep_texts_au1.gds index ed1dcab44..6efbcec79 100644 Binary files a/testdata/algo/deep_texts_au1.gds and b/testdata/algo/deep_texts_au1.gds differ diff --git a/testdata/algo/deep_texts_au2.gds b/testdata/algo/deep_texts_au2.gds new file mode 100644 index 000000000..9adb95c95 Binary files /dev/null and b/testdata/algo/deep_texts_au2.gds differ diff --git a/testdata/algo/deep_texts_l2.gds b/testdata/algo/deep_texts_l2.gds new file mode 100644 index 000000000..4db693c1a Binary files /dev/null and b/testdata/algo/deep_texts_l2.gds differ