diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 89b1eccde..512094c23 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -60,6 +60,7 @@ SOURCES = \ dbReader.cc \ dbRecursiveShapeIterator.cc \ dbRegion.cc \ + dbRegionLocalOperations.cc \ dbSaveLayoutOptions.cc \ dbShape.cc \ dbShapes2.cc \ @@ -259,6 +260,7 @@ HEADERS = \ dbReader.h \ dbRecursiveShapeIterator.h \ dbRegion.h \ + dbRegionLocalOperations.h \ dbSaveLayoutOptions.h \ dbShape.h \ dbShapeRepository.h \ diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index e2a789294..925e5a6c6 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -38,6 +38,7 @@ #include "dbCellGraphUtils.h" #include "dbPolygonTools.h" #include "dbCellVariants.h" +#include "dbRegionLocalOperations.h" #include "dbLocalOperationUtils.h" #include "tlTimer.h" @@ -1305,103 +1306,6 @@ DeepRegion::in (const Region &other, bool invert) const return db::AsIfFlatRegion::in (other, invert); } -namespace -{ - -class CheckLocalOperation - : public local_operation -{ -public: - CheckLocalOperation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool shielded) - : m_check (check), m_different_polygons (different_polygons), m_has_other (has_other), m_shielded (shielded) - { - // .. nothing yet .. - } - - virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - edge2edge_check > edge_check (m_check, result, m_different_polygons, m_has_other, m_shielded); - poly2poly_check > poly_check (edge_check); - - std::list heap; - db::box_scanner scanner; - - if (m_has_other) { - - 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).second); - } - } - - size_t n = 0; - 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.insert (& heap.back (), n); - n += 2; - } - - n = 1; - for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { - heap.push_back (o->obj ().transformed (o->trans ())); - scanner.insert (& heap.back (), n); - n += 2; - } - - } else { - - std::set polygons; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - polygons.insert (interactions.subject_shape (i->first)); - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { - polygons.insert (interactions.intruder_shape (*j).second); - } - } - - size_t n = 0; - for (std::set::const_iterator o = polygons.begin (); o != polygons.end (); ++o) { - heap.push_back (o->obj ().transformed (o->trans ())); - scanner.insert (& heap.back (), n); - n += 2; - } - - } - - do { - scanner.process (poly_check, m_check.distance (), db::box_convert ()); - } while (edge_check.prepare_next_pass ()); - } - - virtual db::Coord dist () const - { - // TODO: will the distance be sufficient? Or should we take somewhat more? - return m_check.distance (); - } - - virtual on_empty_intruder_mode on_empty_intruder_hint () const - { - return m_different_polygons ? Drop : Ignore; - } - - virtual std::string description () const - { - return tl::to_string (tr ("Generic DRC check")); - } - -private: - EdgeRelationFilter m_check; - bool m_different_polygons; - bool m_has_other; - bool m_shielded; -}; - -} - EdgePairsDelegate * DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection, bool shielded) const { @@ -1480,569 +1384,6 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, b return res.release (); } -namespace -{ - -class InteractingLocalOperation - : public local_operation -{ -public: - InteractingLocalOperation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count) - : m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) - { - // .. nothing yet .. - } - - virtual db::Coord dist () const - { - return m_touching ? 1 : 0; - } - - virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - db::EdgeProcessor ep; - - 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).second); - } - } - - size_t nstart = 0; - - if (m_min_count == size_t (1) && m_max_count == std::numeric_limits::max ()) { - - for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { - for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { - ep.insert (*e, nstart); - } - } - nstart++; - - } else { - - tl_assert (m_mode == 0); - - for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { - for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { - ep.insert (*e, nstart); - } - nstart++; - } - - } - - size_t n = nstart; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { - const db::PolygonRef &subject = interactions.subject_shape (i->first); - for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { - ep.insert (*e, n); - } - } - - db::InteractionDetector id (m_mode, 0); - id.set_include_touching (m_touching); - db::EdgeSink es; - ep.process (es, id); - id.finish (); - - std::map interaction_counts; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) { - if (i->first < nstart && i->second >= nstart) { - interaction_counts[i->second] += 1; - } - } - - n = nstart; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { - size_t count = 0; - std::map ::const_iterator c = interaction_counts.find (n); - if (c != interaction_counts.end ()) { - count = c->second; - } - if ((count >= m_min_count && count <= m_max_count) != m_inverse) { - const db::PolygonRef &subject = interactions.subject_shape (i->first); - result.insert (subject); - } - } - } - - virtual on_empty_intruder_mode on_empty_intruder_hint () const - { - if ((m_mode <= 0) != m_inverse) { - return Drop; - } else { - return Copy; - } - } - - virtual std::string description () const - { - return tl::to_string (tr ("Select regions by their geometric relation (interacting, inside, outside ..)")); - } - -private: - int m_mode; - bool m_touching; - bool m_inverse; - size_t m_min_count, m_max_count; -}; - -class PullLocalOperation - : public local_operation -{ -public: - PullLocalOperation (int mode, bool touching) - : m_mode (mode), m_touching (touching) - { - // .. nothing yet .. - } - - virtual db::Coord dist () const - { - return m_touching ? 1 : 0; - } - - virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - db::EdgeProcessor ep; - - 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).second); - } - } - - 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) { - 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) { - ep.insert (*e, n); - } - } - - db::InteractionDetector id (m_mode, 0); - id.set_include_touching (m_touching); - db::EdgeSink es; - ep.process (es, id); - id.finish (); - - std::set selected; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { - 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 geometrical relation to first")); - } - -private: - int m_mode; - bool m_touching; -}; - -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; -}; - -struct ResultCountingInserter -{ - typedef db::Polygon value_type; - - ResultCountingInserter (db::Layout *layout, std::unordered_map &result) - : mp_layout (layout), mp_result (&result) - { - // .. nothing yet .. - } - - void insert (const db::Polygon &p) - { - (*mp_result)[db::PolygonRef (p, mp_layout->shape_repository ())] += 1; - } - - void init (const db::Polygon &p) - { - (*mp_result)[db::PolygonRef (p, mp_layout->shape_repository ())] = 0; - } - -private: - db::Layout *mp_layout; - std::unordered_map *mp_result; -}; - -struct EdgeResultInserter -{ - typedef db::Edge value_type; - - 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 -{ -public: - InteractingWithEdgeLocalOperation (bool inverse, size_t min_count, size_t max_count) - : m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) - { - // .. nothing yet .. - } - - virtual db::Coord dist () const - { - // touching is sufficient - return 1; - } - - virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - std::unordered_map counted_results; - bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); - - db::box_scanner2 scanner; - - ResultCountingInserter inserter (layout, counted_results); - region_to_edge_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); - - std::set intruder_ids; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { - intruder_ids.insert (*j); - } - } - - for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { - scanner.insert2 (& interactions.intruder_shape (*j).second, 0); - } - - std::list heap; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - - 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) { - inserter.init (heap.back ()); - } - - } - - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - - // select hits based on their count - - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - for (std::unordered_map::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { - bool hit = r->second >= m_min_count && r->second <= m_max_count; - if (hit != m_inverse) { - result.insert (r->first); - } - } - } - - 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 edges")); - } - -private: - bool m_inverse; - size_t m_min_count, m_max_count; -}; - -class PullWithEdgeLocalOperation - : public local_operation -{ -public: - PullWithEdgeLocalOperation () - { - // .. nothing yet .. - } - - virtual db::Coord dist () const - { - // touching is sufficient - return 1; - } - - virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - db::box_scanner2 scanner; - - 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) { - scanner.insert2 (& interactions.intruder_shape (*j).second, 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 edges from second by their geometric relation to first")); - } -}; - -struct TextResultInserter -{ - typedef db::TextRef value_type; - - TextResultInserter (std::unordered_set &result) - : mp_result (&result) - { - // .. nothing yet .. - } - - void insert (const db::TextRef &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::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - 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).second, 0); - } - } - - std::set intruder_ids; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { - intruder_ids.insert (*j); - } - } - - for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { - scanner.insert2 (& interactions.intruder_shape (*j).second, 0); - } - - std::list heap; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - - 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, size_t min_count, size_t max_count) - : m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) - { - // .. nothing yet .. - } - - virtual db::Coord dist () const - { - // touching is sufficient - return 1; - } - - virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const - { - std::unordered_map counted_results; - bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); - - db::box_scanner2 scanner; - - ResultCountingInserter inserter (layout, counted_results); - region_to_text_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); - - std::set intruder_ids; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { - intruder_ids.insert (*j); - } - } - - for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { - scanner.insert2 (& interactions.intruder_shape (*j).second, 0); - } - - std::list heap; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - - 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) { - inserter.init (heap.back ()); - } - - } - - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - - // select hits based on their count - - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - - for (std::unordered_map::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { - bool hit = r->second >= m_min_count && r->second <= m_max_count; - if (hit != m_inverse) { - result.insert (r->first); - } - } - } - - 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; - size_t m_min_count, m_max_count; -}; - -} - RegionDelegate * DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const { diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc new file mode 100644 index 000000000..368968bfd --- /dev/null +++ b/src/db/db/dbRegionLocalOperations.cc @@ -0,0 +1,649 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbRegionUtils.h" +#include "dbRegionLocalOperations.h" +#include "dbLocalOperationUtils.h" +#include "dbHierProcessor.h" + +namespace db +{ + +namespace +{ + +// --------------------------------------------------------------------------------------------------------------- + +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; +}; + +struct ResultCountingInserter +{ + typedef db::Polygon value_type; + + ResultCountingInserter (db::Layout *layout, std::unordered_map &result) + : mp_layout (layout), mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Polygon &p) + { + (*mp_result)[db::PolygonRef (p, mp_layout->shape_repository ())] += 1; + } + + void init (const db::Polygon &p) + { + (*mp_result)[db::PolygonRef (p, mp_layout->shape_repository ())] = 0; + } + +private: + db::Layout *mp_layout; + std::unordered_map *mp_result; +}; + +struct EdgeResultInserter +{ + typedef db::Edge value_type; + + 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; +}; + +struct TextResultInserter +{ + typedef db::TextRef value_type; + + TextResultInserter (std::unordered_set &result) + : mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::TextRef &e) + { + (*mp_result).insert (e); + } + +private: + std::unordered_set *mp_result; +}; + +} + +// --------------------------------------------------------------------------------------------------------------- + +CheckLocalOperation::CheckLocalOperation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool shielded) + : m_check (check), m_different_polygons (different_polygons), m_has_other (has_other), m_shielded (shielded) +{ + // .. nothing yet .. +} + +void +CheckLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + edge2edge_check > edge_check (m_check, result, m_different_polygons, m_has_other, m_shielded); + poly2poly_check > poly_check (edge_check); + + std::list heap; + db::box_scanner scanner; + + if (m_has_other) { + + 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).second); + } + } + + size_t n = 0; + 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.insert (& heap.back (), n); + n += 2; + } + + n = 1; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + heap.push_back (o->obj ().transformed (o->trans ())); + scanner.insert (& heap.back (), n); + n += 2; + } + + } else { + + std::set polygons; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + polygons.insert (interactions.subject_shape (i->first)); + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + polygons.insert (interactions.intruder_shape (*j).second); + } + } + + size_t n = 0; + for (std::set::const_iterator o = polygons.begin (); o != polygons.end (); ++o) { + heap.push_back (o->obj ().transformed (o->trans ())); + scanner.insert (& heap.back (), n); + n += 2; + } + + } + + do { + scanner.process (poly_check, m_check.distance (), db::box_convert ()); + } while (edge_check.prepare_next_pass ()); +} + +db::Coord +CheckLocalOperation::dist () const +{ + // TODO: will the distance be sufficient? Or should we take somewhat more? + return m_check.distance (); +} + +CheckLocalOperation::on_empty_intruder_mode +CheckLocalOperation::on_empty_intruder_hint () const +{ + return m_different_polygons ? Drop : Ignore; +} + +std::string +CheckLocalOperation::description () const +{ + return tl::to_string (tr ("Generic DRC check")); +} + +// --------------------------------------------------------------------------------------------------------------- + +InteractingLocalOperation::InteractingLocalOperation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count) + : m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) +{ + // .. nothing yet .. +} + +db::Coord InteractingLocalOperation::dist () const +{ + return m_touching ? 1 : 0; +} + +void InteractingLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + db::EdgeProcessor ep; + + 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).second); + } + } + + size_t nstart = 0; + + if (m_min_count == size_t (1) && m_max_count == std::numeric_limits::max ()) { + + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, nstart); + } + } + nstart++; + + } else { + + tl_assert (m_mode == 0); + + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, nstart); + } + nstart++; + } + + } + + size_t n = nstart; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { + const db::PolygonRef &subject = interactions.subject_shape (i->first); + for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, n); + } + } + + db::InteractionDetector id (m_mode, 0); + id.set_include_touching (m_touching); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + std::map interaction_counts; + for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) { + if (i->first < nstart && i->second >= nstart) { + interaction_counts[i->second] += 1; + } + } + + n = nstart; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { + size_t count = 0; + std::map ::const_iterator c = interaction_counts.find (n); + if (c != interaction_counts.end ()) { + count = c->second; + } + if ((count >= m_min_count && count <= m_max_count) != m_inverse) { + const db::PolygonRef &subject = interactions.subject_shape (i->first); + result.insert (subject); + } + } +} + +InteractingLocalOperation::on_empty_intruder_mode +InteractingLocalOperation::on_empty_intruder_hint () const +{ + if ((m_mode <= 0) != m_inverse) { + return Drop; + } else { + return Copy; + } +} + +std::string InteractingLocalOperation::description () const +{ + return tl::to_string (tr ("Select regions by their geometric relation (interacting, inside, outside ..)")); +} + +// --------------------------------------------------------------------------------------------------------------- + +PullLocalOperation::PullLocalOperation (int mode, bool touching) + : m_mode (mode), m_touching (touching) +{ + // .. nothing yet .. +} + +db::Coord PullLocalOperation::dist () const +{ + return m_touching ? 1 : 0; +} + +void PullLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + db::EdgeProcessor ep; + + 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).second); + } + } + + 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) { + 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) { + ep.insert (*e, n); + } + } + + db::InteractionDetector id (m_mode, 0); + id.set_include_touching (m_touching); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + std::set selected; + for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { + 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); + } + } +} + +PullLocalOperation::on_empty_intruder_mode PullLocalOperation::on_empty_intruder_hint () const +{ + return Drop; +} + +std::string PullLocalOperation::description () const +{ + return tl::to_string (tr ("Pull regions by their geometrical relation to first")); +} + +// --------------------------------------------------------------------------------------------------------------- + +InteractingWithEdgeLocalOperation::InteractingWithEdgeLocalOperation (bool inverse, size_t min_count, size_t max_count) + : m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) +{ + // .. nothing yet .. +} + +db::Coord InteractingWithEdgeLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void InteractingWithEdgeLocalOperation::compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + std::unordered_map counted_results; + bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); + + db::box_scanner2 scanner; + + ResultCountingInserter inserter (layout, counted_results); + region_to_edge_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); + + std::set intruder_ids; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + intruder_ids.insert (*j); + } + } + + for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + 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) { + inserter.init (heap.back ()); + } + + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + // select hits based on their count + + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + for (std::unordered_map::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { + bool hit = r->second >= m_min_count && r->second <= m_max_count; + if (hit != m_inverse) { + result.insert (r->first); + } + } +} + +InteractingWithEdgeLocalOperation::on_empty_intruder_mode InteractingWithEdgeLocalOperation::on_empty_intruder_hint () const +{ + if (!m_inverse) { + return Drop; + } else { + return Copy; + } +} + +std::string InteractingWithEdgeLocalOperation::description () const +{ + return tl::to_string (tr ("Select regions by their geometric relation to edges")); +} + +// --------------------------------------------------------------------------------------------------------------- + +PullWithEdgeLocalOperation::PullWithEdgeLocalOperation () +{ + // .. nothing yet .. +} + +db::Coord PullWithEdgeLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void PullWithEdgeLocalOperation::compute_local (db::Layout *, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + db::box_scanner2 scanner; + + 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) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 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 ()); +} + +PullWithEdgeLocalOperation::on_empty_intruder_mode PullWithEdgeLocalOperation::on_empty_intruder_hint () const +{ + return Drop; +} + +std::string PullWithEdgeLocalOperation::description () const +{ + return tl::to_string (tr ("Pull edges from second by their geometric relation to first")); +} + +// --------------------------------------------------------------------------------------------------------------- + +PullWithTextLocalOperation::PullWithTextLocalOperation () +{ + // .. nothing yet .. +} + +db::Coord PullWithTextLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void PullWithTextLocalOperation::compute_local (db::Layout *, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + 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).second, 0); + } + } + + std::set intruder_ids; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + intruder_ids.insert (*j); + } + } + + for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + 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 ()); +} + +PullWithTextLocalOperation::on_empty_intruder_mode PullWithTextLocalOperation::on_empty_intruder_hint () const +{ + return Drop; +} + +std::string PullWithTextLocalOperation::description () const +{ + return tl::to_string (tr ("Pull texts from second by their geometric relation to first")); +} + +// --------------------------------------------------------------------------------------------------------------- + +InteractingWithTextLocalOperation::InteractingWithTextLocalOperation (bool inverse, size_t min_count, size_t max_count) + : m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) +{ + // .. nothing yet .. +} + +db::Coord InteractingWithTextLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void InteractingWithTextLocalOperation::compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + std::unordered_map counted_results; + bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); + + db::box_scanner2 scanner; + + ResultCountingInserter inserter (layout, counted_results); + region_to_text_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); + + std::set intruder_ids; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + intruder_ids.insert (*j); + } + } + + for (std::set::const_iterator j = intruder_ids.begin (); j != intruder_ids.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j).second, 0); + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + 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) { + inserter.init (heap.back ()); + } + + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + // select hits based on their count + + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + for (std::unordered_map::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { + bool hit = r->second >= m_min_count && r->second <= m_max_count; + if (hit != m_inverse) { + result.insert (r->first); + } + } +} + +InteractingWithTextLocalOperation::on_empty_intruder_mode InteractingWithTextLocalOperation::on_empty_intruder_hint () const +{ + if (!m_inverse) { + return Drop; + } else { + return Copy; + } +} + +std::string InteractingWithTextLocalOperation::description () const +{ + return tl::to_string (tr ("Select regions by their geometric relation to texts")); +} + +} diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h new file mode 100644 index 000000000..96d5b0b03 --- /dev/null +++ b/src/db/db/dbRegionLocalOperations.h @@ -0,0 +1,146 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbRegionLocalOperations +#define HDR_dbRegionLocalOperations + +#include "dbCommon.h" +#include "dbEdgePairRelations.h" +#include "dbLocalOperation.h" + +namespace db +{ + +class CheckLocalOperation + : public local_operation +{ +public: + CheckLocalOperation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool shielded); + + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + + virtual db::Coord dist () const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + EdgeRelationFilter m_check; + bool m_different_polygons; + bool m_has_other; + bool m_shielded; +}; + +class InteractingLocalOperation + : public local_operation +{ +public: + InteractingLocalOperation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count); + + virtual db::Coord dist () const; + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + int m_mode; + bool m_touching; + bool m_inverse; + size_t m_min_count, m_max_count; +}; + +class PullLocalOperation + : public local_operation +{ +public: + PullLocalOperation (int mode, bool touching); + + virtual db::Coord dist () const; + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + int m_mode; + bool m_touching; +}; + +class InteractingWithEdgeLocalOperation + : public local_operation +{ +public: + InteractingWithEdgeLocalOperation (bool inverse, size_t min_count, size_t max_count); + + virtual db::Coord dist () const; + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + bool m_inverse; + size_t m_min_count, m_max_count; +}; + +class PullWithEdgeLocalOperation + : public local_operation +{ +public: + PullWithEdgeLocalOperation (); + + virtual db::Coord dist () const; + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; +}; + +class PullWithTextLocalOperation + : public local_operation +{ +public: + PullWithTextLocalOperation (); + + virtual db::Coord dist () const; + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; +}; + +class InteractingWithTextLocalOperation + : public local_operation +{ +public: + InteractingWithTextLocalOperation (bool inverse, size_t min_count, size_t max_count); + + virtual db::Coord dist () const; + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + bool m_inverse; + size_t m_min_count, m_max_count; +}; + +} // namespace db + +#endif +