From c23c4045ba53f212c9f12d58a9c499d328c49f3b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Aug 2024 17:57:50 +0200 Subject: [PATCH] Basic implementation --- src/db/db/db.pro | 4 + src/db/db/dbAsIfFlatEdgePairs.cc | 255 +++++++++++++++- src/db/db/dbAsIfFlatEdgePairs.h | 7 + src/db/db/dbDeepEdgePairs.cc | 217 ++++++++++---- src/db/db/dbDeepEdgePairs.h | 24 +- src/db/db/dbEdgePairs.cc | 4 +- src/db/db/dbEdgePairs.h | 20 ++ src/db/db/dbEdgePairsDelegate.cc | 7 + src/db/db/dbEdgePairsDelegate.h | 7 + src/db/db/dbEdgePairsLocalOperations.cc | 377 ++++++++++++++++++++++++ src/db/db/dbEdgePairsLocalOperations.h | 111 +++++++ src/db/db/dbEdgePairsUtils.cc | 92 ++++++ src/db/db/dbEdgePairsUtils.h | 261 ++++++++++++++++ src/db/db/dbEdgesLocalOperations.cc | 2 +- 14 files changed, 1297 insertions(+), 91 deletions(-) create mode 100644 src/db/db/dbEdgePairsLocalOperations.cc create mode 100644 src/db/db/dbEdgePairsLocalOperations.h create mode 100644 src/db/db/dbEdgePairsUtils.cc create mode 100644 src/db/db/dbEdgePairsUtils.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index b6aac64f3..d0fa394b3 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -27,6 +27,8 @@ SOURCES = \ dbEdgePairFilters.cc \ dbEdgePairRelations.cc \ dbEdgePairs.cc \ + dbEdgePairsLocalOperations.cc \ + dbEdgePairsUtils.cc \ dbEdgeProcessor.cc \ dbEdges.cc \ dbEdgesLocalOperations.cc \ @@ -250,6 +252,8 @@ HEADERS = \ dbEdgePairFilters.h \ dbEdgePairRelations.h \ dbEdgePairs.h \ + dbEdgePairsLocalOperations.h \ + dbEdgePairsUtils.h \ dbEdgeProcessor.h \ dbEdges.h \ dbEdgesLocalOperations.h \ diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc index 789322e69..70c853734 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.cc +++ b/src/db/db/dbAsIfFlatEdgePairs.cc @@ -26,8 +26,13 @@ #include "dbFlatRegion.h" #include "dbFlatEdges.h" #include "dbEmptyEdgePairs.h" +#include "dbEmptyEdges.h" +#include "dbEmptyRegion.h" #include "dbEdgePairs.h" +#include "dbEdgePairsLocalOperations.h" #include "dbBoxConvert.h" +#include "dbRegion.h" +#include "dbHierProcessor.h" #include @@ -242,87 +247,305 @@ AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const } RegionDelegate * -AsIfFlatEdgePairs::pull_interacting (const Region &) const +AsIfFlatEdgePairs::pull_interacting (const Region &other) const { - // @@@ + return pull_generic (other); } EdgesDelegate * -AsIfFlatEdgePairs::pull_interacting (const Edges &) const +AsIfFlatEdgePairs::pull_interacting (const Edges &other) const { - // @@@ + return pull_generic (other); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_interacting (const Region &other, size_t min_count, size_t max_count) const { - // @@@ + return selected_interacting_generic (other, EdgePairsInteract, false, min_count, max_count); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const { - // @@@ + return selected_interacting_generic (other, EdgePairsInteract, true, min_count, max_count); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_interacting (const Edges &other, size_t min_count, size_t max_count) const { - // @@@ + return selected_interacting_generic (other, false, min_count, max_count); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const { - // @@@ + return selected_interacting_generic (other, true, min_count, max_count); } std::pair AsIfFlatEdgePairs::selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const { - // @@@ + return selected_interacting_pair_generic (other, EdgePairsInteract, min_count, max_count); } std::pair AsIfFlatEdgePairs::selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const { - // @@@ + return selected_interacting_pair_generic (other, min_count, max_count); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_outside (const Region &other) const { - // @@@ + return selected_interacting_generic (other, EdgePairsOutside, false, size_t (1), std::numeric_limits::max ()); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_not_outside (const Region &other) const { - // @@@ + return selected_interacting_generic (other, EdgePairsOutside, true, size_t (1), std::numeric_limits::max ()); } std::pair AsIfFlatEdgePairs::selected_outside_pair (const Region &other) const { - // @@@ + return selected_interacting_pair_generic (other, EdgePairsOutside, size_t (1), std::numeric_limits::max ()); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_inside (const Region &other) const { - // @@@ + return selected_interacting_generic (other, EdgePairsInside, false, size_t (1), std::numeric_limits::max ()); } EdgePairsDelegate * AsIfFlatEdgePairs::selected_not_inside (const Region &other) const { - // @@@ + return selected_interacting_generic (other, EdgePairsInside, true, size_t (1), std::numeric_limits::max ()); } std::pair AsIfFlatEdgePairs::selected_inside_pair (const Region &other) const { - // @@@ + return selected_interacting_pair_generic (other, EdgePairsInside, size_t (1), std::numeric_limits::max ()); +} + +namespace { + +class OutputPairHolder +{ +public: + OutputPairHolder (int inverse, bool merged_semantics) + { + m_e1.reset (new FlatEdgePairs (merged_semantics)); + m_results.push_back (& m_e1->raw_edge_pairs ()); + + if (inverse == 0) { + m_e2.reset (new FlatEdgePairs (merged_semantics)); + m_results.push_back (& m_e2->raw_edge_pairs ()); + } + } + + std::pair region_pair () + { + return std::make_pair (m_e1.release (), m_e2.release ()); + } + + const std::vector &results () { return m_results; } + +private: + std::unique_ptr m_e1, m_e2; + std::vector m_results; +}; + +} + +EdgesDelegate * +AsIfFlatEdgePairs::pull_generic (const Edges &other) const +{ + // shortcuts + if (other.empty () || empty ()) { + return new EmptyEdges (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableEdgePairDelivery e (begin ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert1 (e.operator-> (), 0); + } + + AddressableEdgeDelivery p = other.addressable_merged_edges (); + + for ( ; ! p.at_end (); ++p) { + scanner.insert2 (p.operator-> (), 1); + } + + std::unique_ptr output (new FlatEdges (true)); + + edge_pair_to_edge_interaction_filter filter (output.get (), size_t (1), std::numeric_limits::max ()); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + return output.release (); +} + +RegionDelegate * +AsIfFlatEdgePairs::pull_generic (const Region &other) const +{ + // shortcuts + if (other.empty () || empty ()) { + return new EmptyRegion (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableEdgePairDelivery e (begin ()); + + 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::unique_ptr output (new FlatRegion (true)); + + edge_pair_to_polygon_interaction_filter filter (output.get (), EdgePairsInteract, size_t (1), std::numeric_limits::max ()); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + return output.release (); +} + +EdgePairsDelegate * +AsIfFlatEdgePairs::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const +{ + min_count = std::max (size_t (1), min_count); + + // shortcuts + if (max_count < min_count || other.empty () || empty ()) { + return inverse ? clone () : new EmptyEdgePairs (); + } + + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + OutputPairHolder oph (inverse ? 1 : -1, merged_semantics () || is_merged ()); + + db::EdgePairsIterator edges (begin ()); + + db::EdgePair2EdgeInteractingLocalOperation op (inverse ? db::EdgePair2EdgeInteractingLocalOperation::Inverse : db::EdgePair2EdgeInteractingLocalOperation::Normal, min_count, max_count); + + db::local_processor proc; + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + + std::vector > others; + // NOTE: with counting the other edge collection needs to be merged + others.push_back (counting ? other.begin_merged () : other.begin ()); + + proc.run_flat (edges, others, std::vector (), &op, oph.results ()); + + return oph.region_pair ().first; +} + +EdgePairsDelegate * +AsIfFlatEdgePairs::selected_interacting_generic (const Region &other, EdgePairInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const +{ + min_count = std::max (size_t (1), min_count); + + // shortcuts + if (max_count < min_count || other.empty () || empty ()) { + return ((mode == EdgePairsOutside) == inverse) ? new EmptyEdgePairs () : clone (); + } + + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + OutputPairHolder oph (inverse ? 1 : -1, merged_semantics () || is_merged ()); + + db::EdgePairsIterator edges (begin ()); + + db::edge_pair_to_polygon_interacting_local_operation op (mode, inverse ? db::edge_pair_to_polygon_interacting_local_operation::Inverse : db::edge_pair_to_polygon_interacting_local_operation::Normal, min_count, max_count); + + db::local_processor proc; + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + + std::vector > others; + // NOTE: with counting the other region needs to be merged + others.push_back (counting || mode != EdgePairsInteract ? other.begin_merged () : other.begin ()); + + proc.run_flat (edges, others, std::vector (), &op, oph.results ()); + + return oph.region_pair ().first; +} + +std::pair +AsIfFlatEdgePairs::selected_interacting_pair_generic (const Edges &other, size_t min_count, size_t max_count) const +{ + min_count = std::max (size_t (1), min_count); + + // shortcuts + if (max_count < min_count || other.empty () || empty ()) { + return std::make_pair (new EmptyEdgePairs (), clone ()); + } + + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + OutputPairHolder oph (0, merged_semantics () || is_merged ()); + + db::EdgePairsIterator edges (begin ()); + + db::EdgePair2EdgeInteractingLocalOperation op (db::EdgePair2EdgeInteractingLocalOperation::Both, min_count, max_count); + + db::local_processor proc; + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + + std::vector > others; + // NOTE: with counting the other region needs to be merged + others.push_back (counting ? other.begin_merged () : other.begin ()); + + proc.run_flat (edges, others, std::vector (), &op, oph.results ()); + + return oph.region_pair (); +} + +std::pair +AsIfFlatEdgePairs::selected_interacting_pair_generic (const Region &other, EdgePairInteractionMode mode, size_t min_count, size_t max_count) const +{ + min_count = std::max (size_t (1), min_count); + + // shortcuts + if (max_count < min_count || other.empty () || empty ()) { + if (mode != EdgePairsOutside) { + return std::make_pair (new EmptyEdgePairs (), clone ()); + } else { + return std::make_pair (clone (), new EmptyEdgePairs ()); + } + } + + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + OutputPairHolder oph (0, merged_semantics () || is_merged ()); + + db::EdgePairsIterator edges (begin ()); + + db::edge_pair_to_polygon_interacting_local_operation op (mode, db::edge_pair_to_polygon_interacting_local_operation::Both, min_count, max_count); + + db::local_processor proc; + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + + std::vector > others; + // NOTE: with counting the other region needs to be merged + others.push_back (counting || mode != EdgePairsInteract ? other.begin_merged () : other.begin ()); + + proc.run_flat (edges, others, std::vector (), &op, oph.results ()); + + return oph.region_pair (); } RegionDelegate * diff --git a/src/db/db/dbAsIfFlatEdgePairs.h b/src/db/db/dbAsIfFlatEdgePairs.h index 9387aa03c..fe6152419 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.h +++ b/src/db/db/dbAsIfFlatEdgePairs.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbEdgePairsDelegate.h" +#include "dbEdgePairsUtils.h" namespace db { @@ -101,6 +102,12 @@ public: protected: void update_bbox (const db::Box &box); void invalidate_bbox (); + virtual EdgesDelegate *pull_generic (const Edges &other) const; + virtual RegionDelegate *pull_generic (const Region &other) const; + virtual EdgePairsDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_pair_generic (const Edges &other, size_t min_count, size_t max_count) const; + virtual EdgePairsDelegate *selected_interacting_generic (const Region &other, EdgePairInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_pair_generic (const Region &other, EdgePairInteractionMode mode, size_t min_count, size_t max_count) const; private: friend class DeepEdgePairs; diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc index 4900d5e0e..bc4be7bb5 100644 --- a/src/db/db/dbDeepEdgePairs.cc +++ b/src/db/db/dbDeepEdgePairs.cc @@ -27,6 +27,9 @@ #include "dbDeepRegion.h" #include "dbCellMapping.h" #include "dbLayoutUtils.h" +#include "dbEdgePairsLocalOperations.h" +#include "dbHierProcessor.h" +#include "dbRegion.h" #include @@ -497,88 +500,190 @@ RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const return new db::DeepRegion (new_layer); } -RegionDelegate * -DeepEdgePairs::pull_interacting (const Region &) const -{ - // @@@ -} - EdgesDelegate * -DeepEdgePairs::pull_interacting (const Edges &) const +DeepEdgePairs::pull_generic (const Edges &other) const { - // @@@ + std::unique_ptr dr_holder; + const db::DeepEdges *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-hierarchization + dr_holder.reset (new db::DeepEdges (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &edge_pairs = deep_layer (); + const db::DeepLayer &other_edges = other_deep->merged_deep_layer (); + + DeepLayer dl_out (other_edges.derived ()); + + db::EdgePair2EdgePullLocalOperation op; + + db::local_processor proc (const_cast (&edge_pairs.layout ()), const_cast (&edge_pairs.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell (), edge_pairs.breakout_cells (), other_edges.breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edge_pairs.store ()->threads ()); + + proc.run (&op, edge_pairs.layer (), other_edges.layer (), dl_out.layer ()); + + return new db::DeepEdges (dl_out); +} + +RegionDelegate * +DeepEdgePairs::pull_generic (const Region &other) const +{ + std::unique_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-hierarchization + dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &edge_pairs = deep_layer (); + const db::DeepLayer &other_polygons = other_deep->merged_deep_layer (); + + DeepLayer dl_out (other_polygons.derived ()); + + db::EdgePair2PolygonPullLocalOperation op; + + db::local_processor proc (const_cast (&edge_pairs.layout ()), const_cast (&edge_pairs.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), edge_pairs.breakout_cells (), other_polygons.breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edge_pairs.store ()->threads ()); + + proc.run (&op, edge_pairs.layer (), other_polygons.layer (), dl_out.layer ()); + + return new db::DeepRegion (dl_out); } EdgePairsDelegate * -DeepEdgePairs::selected_interacting (const Region &other, size_t min_count, size_t max_count) const +DeepEdgePairs::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const { - // @@@ + std::unique_ptr dr_holder; + const db::DeepEdges *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-hierarchization + dr_holder.reset (new db::DeepEdges (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + min_count = std::max (size_t (1), min_count); + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + + const db::DeepLayer &edge_pairs = deep_layer (); + + DeepLayer dl_out (edge_pairs.derived ()); + + db::EdgePair2EdgeInteractingLocalOperation op (inverse ? db::EdgePair2EdgeInteractingLocalOperation::Inverse : db::EdgePair2EdgeInteractingLocalOperation::Normal, min_count, max_count); + + db::local_processor proc (const_cast (&edge_pairs.layout ()), const_cast (&edge_pairs.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edge_pairs.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edge_pairs.store ()->threads ()); + + // NOTE: with counting the other region needs to be merged + proc.run (&op, edge_pairs.layer (), (counting ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ()); + + return new db::DeepEdgePairs (dl_out); } EdgePairsDelegate * -DeepEdgePairs::selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const +DeepEdgePairs::selected_interacting_generic (const Region &other, EdgePairInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const { - // @@@ -} + std::unique_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-hierarchization + dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } -EdgePairsDelegate * -DeepEdgePairs::selected_interacting (const Edges &other, size_t min_count, size_t max_count) const -{ - // @@@ -} + min_count = std::max (size_t (1), min_count); + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); -EdgePairsDelegate * -DeepEdgePairs::selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const -{ - // @@@ + const db::DeepLayer &edge_pairs = deep_layer (); + + DeepLayer dl_out (edge_pairs.derived ()); + + db::edge_pair_to_polygon_interacting_local_operation op (mode, inverse ? db::edge_pair_to_polygon_interacting_local_operation::Inverse : db::edge_pair_to_polygon_interacting_local_operation::Normal, min_count, max_count); + + db::local_processor proc (const_cast (&edge_pairs.layout ()), const_cast (&edge_pairs.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edge_pairs.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edge_pairs.store ()->threads ()); + + // NOTE: with counting the other region needs to be merged + proc.run (&op, edge_pairs.layer (), (counting || mode != EdgePairsInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ()); + + return new db::DeepEdgePairs (dl_out); } std::pair -DeepEdgePairs::selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const +DeepEdgePairs::selected_interacting_pair_generic (const Edges &other, size_t min_count, size_t max_count) const { - // @@@ + std::unique_ptr dr_holder; + const db::DeepEdges *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-hierarchization + dr_holder.reset (new db::DeepEdges (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + min_count = std::max (size_t (1), min_count); + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + + const db::DeepLayer &edge_pairs = deep_layer (); + + DeepLayer dl_out (edge_pairs.derived ()); + DeepLayer dl_out2 (edge_pairs.derived ()); + + std::vector output_layers; + output_layers.reserve (2); + output_layers.push_back (dl_out.layer ()); + output_layers.push_back (dl_out2.layer ()); + + db::EdgePair2EdgeInteractingLocalOperation op (db::EdgePair2EdgeInteractingLocalOperation::Both, min_count, max_count); + + db::local_processor proc (const_cast (&edge_pairs.layout ()), const_cast (&edge_pairs.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edge_pairs.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edge_pairs.store ()->threads ()); + + // NOTE: with counting the other region needs to be merged + proc.run (&op, edge_pairs.layer (), (counting ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), output_layers); + + return std::make_pair (new db::DeepEdgePairs (dl_out), new db::DeepEdgePairs (dl_out2)); } std::pair -DeepEdgePairs::selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const +DeepEdgePairs::selected_interacting_pair_generic (const Region &other, EdgePairInteractionMode mode, size_t min_count, size_t max_count) const { - // @@@ -} + std::unique_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-hierarchization + dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } -EdgePairsDelegate * -DeepEdgePairs::selected_outside (const Region &other) const -{ - // @@@ -} + min_count = std::max (size_t (1), min_count); + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); -EdgePairsDelegate * -DeepEdgePairs::selected_not_outside (const Region &other) const -{ - // @@@ -} + const db::DeepLayer &edge_pairs = deep_layer (); -std::pair -DeepEdgePairs::selected_outside_pair (const Region &other) const -{ - // @@@ -} + DeepLayer dl_out (edge_pairs.derived ()); + DeepLayer dl_out2 (edge_pairs.derived ()); -EdgePairsDelegate * -DeepEdgePairs::selected_inside (const Region &other) const -{ - // @@@ -} + std::vector output_layers; + output_layers.reserve (2); + output_layers.push_back (dl_out.layer ()); + output_layers.push_back (dl_out2.layer ()); -EdgePairsDelegate * -DeepEdgePairs::selected_not_inside (const Region &other) const -{ - // @@@ -} + db::edge_pair_to_polygon_interacting_local_operation op (mode, db::edge_pair_to_polygon_interacting_local_operation::Both, min_count, max_count); -std::pair -DeepEdgePairs::selected_inside_pair (const Region &other) const -{ - // @@@ + db::local_processor proc (const_cast (&edge_pairs.layout ()), const_cast (&edge_pairs.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edge_pairs.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (edge_pairs.store ()->threads ()); + + // NOTE: with counting the other region needs to be merged + proc.run (&op, edge_pairs.layer (), (counting || mode != EdgePairsInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), output_layers); + + return std::make_pair (new db::DeepEdgePairs (dl_out), new db::DeepEdgePairs (dl_out2)); } EdgesDelegate *DeepEdgePairs::generic_edges (bool first, bool second) const diff --git a/src/db/db/dbDeepEdgePairs.h b/src/db/db/dbDeepEdgePairs.h index ae0e7a5e5..c9417dfe0 100644 --- a/src/db/db/dbDeepEdgePairs.h +++ b/src/db/db/dbDeepEdgePairs.h @@ -83,22 +83,6 @@ public: virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const; virtual EdgesDelegate *processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const; - virtual RegionDelegate *pull_interacting (const Region &) const; - virtual EdgesDelegate *pull_interacting (const Edges &) const; - virtual EdgePairsDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const; - virtual EdgePairsDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const; - virtual EdgePairsDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const; - virtual EdgePairsDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const; - virtual std::pair selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const; - virtual std::pair selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const; - - virtual EdgePairsDelegate *selected_outside (const Region &other) const; - virtual EdgePairsDelegate *selected_not_outside (const Region &other) const; - virtual std::pair selected_outside_pair (const Region &other) const; - virtual EdgePairsDelegate *selected_inside (const Region &other) const; - virtual EdgePairsDelegate *selected_not_inside (const Region &other) const; - virtual std::pair selected_inside_pair (const Region &other) const; - virtual EdgePairsDelegate *add_in_place (const EdgePairs &other); virtual EdgePairsDelegate *add (const EdgePairs &other) const; @@ -120,6 +104,14 @@ public: return this; } +protected: + virtual EdgesDelegate *pull_generic (const Edges &other) const; + virtual RegionDelegate *pull_generic (const Region &other) const; + virtual EdgePairsDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_pair_generic (const Edges &other, size_t min_count, size_t max_count) const; + virtual EdgePairsDelegate *selected_interacting_generic (const Region &other, EdgePairInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_pair_generic (const Region &other, EdgePairInteractionMode mode, size_t min_count, size_t max_count) const; + private: DeepEdgePairs &operator= (const DeepEdgePairs &other); diff --git a/src/db/db/dbEdgePairs.cc b/src/db/db/dbEdgePairs.cc index 600d5c709..61e6f9bf6 100644 --- a/src/db/db/dbEdgePairs.cc +++ b/src/db/db/dbEdgePairs.cc @@ -226,12 +226,12 @@ void EdgePairs::second_edges (Edges &output) const void EdgePairs::pull_interacting (Region &output, const Region &other) const { - // @@@ + output = Region (mp_delegate->pull_interacting (other)); } void EdgePairs::pull_interacting (Edges &output, const Edges &other) const { - // @@@ + output = Edges (mp_delegate->pull_interacting (other)); } void EdgePairs::set_delegate (EdgePairsDelegate *delegate) diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index dd5211a1c..24d305359 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -767,6 +767,26 @@ public: */ void second_edges (Edges &output) const; + /** + * @brief Sets the base verbosity + * + * Setting this value will make timing measurements appear at least at + * the given verbosity level and more detailed timing at the given level + * plus 10. The default level is 30. + */ + void set_base_verbosity (int vb) + { + mp_delegate->set_base_verbosity (vb); + } + + /** + * @brief Gets the base verbosity + */ + unsigned int base_verbosity () const + { + return mp_delegate->base_verbosity (); + } + /** * @brief Enable progress reporting * diff --git a/src/db/db/dbEdgePairsDelegate.cc b/src/db/db/dbEdgePairsDelegate.cc index b34ba9c19..710ea4bf5 100644 --- a/src/db/db/dbEdgePairsDelegate.cc +++ b/src/db/db/dbEdgePairsDelegate.cc @@ -30,6 +30,7 @@ namespace db EdgePairsDelegate::EdgePairsDelegate () { + m_base_verbosity = 30; m_report_progress = false; } @@ -43,6 +44,7 @@ EdgePairsDelegate & EdgePairsDelegate::operator= (const EdgePairsDelegate &other) { if (this != &other) { + m_base_verbosity = other.m_base_verbosity; m_report_progress = other.m_report_progress; } return *this; @@ -53,6 +55,11 @@ EdgePairsDelegate::~EdgePairsDelegate () // .. nothing yet .. } +void EdgePairsDelegate::set_base_verbosity (int vb) +{ + m_base_verbosity = vb; +} + void EdgePairsDelegate::enable_progress (const std::string &progress_desc) { m_report_progress = true; diff --git a/src/db/db/dbEdgePairsDelegate.h b/src/db/db/dbEdgePairsDelegate.h index c786838fa..d58ba7661 100644 --- a/src/db/db/dbEdgePairsDelegate.h +++ b/src/db/db/dbEdgePairsDelegate.h @@ -173,6 +173,12 @@ public: return this; } + void set_base_verbosity (int vb); + int base_verbosity () const + { + return m_base_verbosity; + } + void enable_progress (const std::string &progress_desc); void disable_progress (); @@ -254,6 +260,7 @@ protected: private: bool m_report_progress; std::string m_progress_desc; + int m_base_verbosity; }; } diff --git a/src/db/db/dbEdgePairsLocalOperations.cc b/src/db/db/dbEdgePairsLocalOperations.cc new file mode 100644 index 000000000..dc9899f55 --- /dev/null +++ b/src/db/db/dbEdgePairsLocalOperations.cc @@ -0,0 +1,377 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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 "dbEdgePairsLocalOperations.h" +#include "dbHierProcessor.h" +#include "dbLocalOperationUtils.h" + +namespace db +{ + +// --------------------------------------------------------------------------------------------- +// EdgePair2EdgeInteractingLocalOperation implementation + +EdgePair2EdgeInteractingLocalOperation::EdgePair2EdgeInteractingLocalOperation (output_mode_t output_mode, size_t min_count, size_t max_count) + : m_output_mode (output_mode), m_min_count (min_count), m_max_count (max_count) +{ + // .. nothing yet .. +} + +db::Coord EdgePair2EdgeInteractingLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void EdgePair2EdgeInteractingLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const +{ + tl_assert (results.size () == size_t (m_output_mode == Both ? 2 : 1)); + + std::unordered_set &result = results.front (); + + std::unordered_set *result2 = 0; + if (m_output_mode == Both) { + result2 = &results[1]; + } + + db::box_scanner2 scanner; + + std::set others; + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (typename shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j).second); + } + } + + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::EdgePair &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 0); + } + + for (typename std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + scanner.insert2 (o.operator-> (), 1); + } + + if (m_output_mode == Inverse || m_output_mode == Both) { + + std::unordered_set interacting; + edge_pair_to_edge_interaction_filter > filter (&interacting, m_min_count, m_max_count); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::EdgePair &subject = interactions.subject_shape (i->first); + + if (interacting.find (subject) == interacting.end ()) { + if (m_output_mode != Both) { + result.insert (subject); + } else { + result2->insert (subject); + } + } else if (m_output_mode == Both) { + result.insert (subject); + } + + } + + } else { + + edge_pair_to_edge_interaction_filter > filter (&result, m_min_count, m_max_count); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } +} + +OnEmptyIntruderHint EdgePair2EdgeInteractingLocalOperation::on_empty_intruder_hint () const +{ + return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop); +} + +std::string EdgePair2EdgeInteractingLocalOperation::description () const +{ + return tl::to_string (tr ("Select edge pairs interacting edges")); +} + +// --------------------------------------------------------------------------------------------- +// Edge2EdgePullLocalOperation implementation + +EdgePair2EdgePullLocalOperation::EdgePair2EdgePullLocalOperation () +{ + // .. nothing yet .. +} + +db::Coord EdgePair2EdgePullLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void EdgePair2EdgePullLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + 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).second); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::EdgePair &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 1); + } + + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + scanner.insert2 (o.operator-> (), 0); + } + + edge_pair_to_edge_interaction_filter > filter (&result, size_t (1), std::numeric_limits::max ()); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); +} + +OnEmptyIntruderHint EdgePair2EdgePullLocalOperation::on_empty_intruder_hint () const +{ + return Drop; +} + +std::string EdgePair2EdgePullLocalOperation::description () const +{ + return tl::to_string (tr ("Select interacting edges from other")); +} + +// --------------------------------------------------------------------------------------------- +// edge_to_polygon_interacting_local_operation implementation + +template +edge_pair_to_polygon_interacting_local_operation::edge_pair_to_polygon_interacting_local_operation (EdgePairInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count) + : m_mode (mode), m_output_mode (output_mode), m_min_count (min_count), m_max_count (max_count) +{ + // .. nothing yet .. +} + +template +db::Coord edge_pair_to_polygon_interacting_local_operation::dist () const +{ + // touching is sufficient + return 1; +} + +static const db::Polygon *deref (const db::Polygon &poly, std::list &) +{ + return &poly; +} + +static const db::Polygon *deref (const db::PolygonRef &pref, std::list &heap) +{ + heap.push_back (pref.obj ().transformed (pref.trans ())); + return & heap.back (); +} + +template +void edge_pair_to_polygon_interacting_local_operation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const +{ + tl_assert (results.size () == size_t (m_output_mode == Both ? 2 : 1)); + + std::unordered_set &result = results.front (); + + std::unordered_set *result2 = 0; + if (m_output_mode == Both) { + result2 = &results[1]; + } + + db::box_scanner2 scanner; + + std::set others; + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (typename shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j).second); + } + } + + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::EdgePair &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 0); + } + + std::list heap; + for (typename std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + scanner.insert2 (deref (*o, heap), 1); + } + + if (m_output_mode == Inverse || m_output_mode == Both) { + + std::unordered_set interacting; + edge_pair_to_polygon_interaction_filter > filter (&interacting, m_mode, m_min_count, m_max_count); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::EdgePair &subject = interactions.subject_shape (i->first); + + if (interacting.find (subject) == interacting.end ()) { + if (m_output_mode != Both) { + result.insert (subject); + } else { + result2->insert (subject); + } + } else if (m_output_mode == Both) { + result.insert (subject); + } + + } + + } else { + + edge_pair_to_polygon_interaction_filter > filter (&result, m_mode, m_min_count, m_max_count); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } +} + +template +OnEmptyIntruderHint edge_pair_to_polygon_interacting_local_operation::on_empty_intruder_hint () const +{ + if (m_mode == EdgePairsOutside) { + return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy); + } else { + return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop); + } +} + +template +std::string edge_pair_to_polygon_interacting_local_operation::description () const +{ + if (m_mode == EdgePairsInteract) { + if (m_output_mode == Inverse) { + return tl::to_string (tr ("Select non-interacting edge pairs")); + } else if (m_output_mode == Normal) { + return tl::to_string (tr ("Select interacting edge pairs")); + } else { + return tl::to_string (tr ("Select interacting and non-interacting edge pairs")); + } + } else if (m_mode == EdgePairsInside) { + if (m_output_mode == Inverse) { + return tl::to_string (tr ("Select non-inside edge pairs")); + } else if (m_output_mode == Normal) { + return tl::to_string (tr ("Select inside edge pairs")); + } else { + return tl::to_string (tr ("Select inside and non-inside edge pairs")); + } + } else if (m_mode == EdgePairsOutside) { + if (m_output_mode == Inverse) { + return tl::to_string (tr ("Select non-outside edge pairs")); + } else if (m_output_mode == Normal) { + return tl::to_string (tr ("Select outside edge pairs")); + } else { + return tl::to_string (tr ("Select outside and non-outside edge pairs")); + } + } + return std::string (); +} + +template class edge_pair_to_polygon_interacting_local_operation; +template class edge_pair_to_polygon_interacting_local_operation; + +// --------------------------------------------------------------------------------------------- +// EdgePair2PolygonPullLocalOperation implementation + +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; +}; + +} + +EdgePair2PolygonPullLocalOperation::EdgePair2PolygonPullLocalOperation () +{ + // .. nothing yet .. +} + +db::Coord EdgePair2PolygonPullLocalOperation::dist () const +{ + // touching is sufficient + return 1; +} + +void EdgePair2PolygonPullLocalOperation::do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const +{ + tl_assert (results.size () == 1); + std::unordered_set &result = results.front (); + + 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).second); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::EdgePair &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); + edge_pair_to_polygon_interaction_filter filter (&inserter, EdgePairsInteract, size_t (1), std::numeric_limits::max ()); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); +} + +OnEmptyIntruderHint EdgePair2PolygonPullLocalOperation::on_empty_intruder_hint () const +{ + return Drop; +} + +std::string EdgePair2PolygonPullLocalOperation::description () const +{ + return tl::to_string (tr ("Select interacting polygons")); +} + +} + diff --git a/src/db/db/dbEdgePairsLocalOperations.h b/src/db/db/dbEdgePairsLocalOperations.h new file mode 100644 index 000000000..a7f6679e5 --- /dev/null +++ b/src/db/db/dbEdgePairsLocalOperations.h @@ -0,0 +1,111 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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_dbEdgePairsLocalOperation +#define HDR_dbEdgePairsLocalOperation + +#include "dbCommon.h" + +#include "dbLayout.h" +#include "dbLocalOperation.h" +#include "dbEdgePairsUtils.h" + +namespace db +{ + +/** + * @brief Implements edge pair-to-edge interactions + */ +class DB_PUBLIC EdgePair2EdgeInteractingLocalOperation + : public local_operation +{ +public: + enum output_mode_t { Normal, Inverse, Both }; + + EdgePair2EdgeInteractingLocalOperation (output_mode_t output_mode, size_t min_count, size_t max_count); + + virtual db::Coord dist () const; + virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const; + virtual OnEmptyIntruderHint on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + output_mode_t m_output_mode; + size_t m_min_count, m_max_count; +}; + +/** + * @brief Implements edge pair-to-edge interactions (pull mode) + */ +class DB_PUBLIC EdgePair2EdgePullLocalOperation + : public local_operation +{ +public: + EdgePair2EdgePullLocalOperation (); + + virtual db::Coord dist () const; + virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const; + virtual OnEmptyIntruderHint on_empty_intruder_hint () const; + virtual std::string description () const; +}; + +/** + * @brief Implements edge-to-polygon interactions + */ +template +class DB_PUBLIC edge_pair_to_polygon_interacting_local_operation + : public local_operation +{ +public: + enum output_mode_t { Normal, Inverse, Both }; + + edge_pair_to_polygon_interacting_local_operation (EdgePairInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count); + + virtual db::Coord dist () const; + virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const; + virtual OnEmptyIntruderHint on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + EdgePairInteractionMode m_mode; + output_mode_t m_output_mode; + size_t m_min_count, m_max_count; +}; + +/** + * @brief Implements edge-to-polygon interactions (pull mode) + */ +class DB_PUBLIC EdgePair2PolygonPullLocalOperation + : public local_operation +{ +public: + EdgePair2PolygonPullLocalOperation (); + + virtual db::Coord dist () const; + virtual void do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase * /*proc*/) const; + virtual OnEmptyIntruderHint on_empty_intruder_hint () const; + virtual std::string description () const; +}; + +} + +#endif diff --git a/src/db/db/dbEdgePairsUtils.cc b/src/db/db/dbEdgePairsUtils.cc new file mode 100644 index 000000000..a9bf089a9 --- /dev/null +++ b/src/db/db/dbEdgePairsUtils.cc @@ -0,0 +1,92 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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 "dbEdgePairsUtils.h" +#include "dbEdgesUtils.h" +#include "dbEdgeProcessor.h" + +namespace db +{ + +static void insert_into_ep (const db::EdgePair &ep, db::EdgeProcessor &proc, size_t prop_id) +{ + proc.insert (db::Edge (ep.first ().p1 (), ep.first ().p2 ()), prop_id); + proc.insert (db::Edge (ep.first ().p2 (), ep.second ().p1 ()), prop_id); + proc.insert (db::Edge (ep.second ().p1 (), ep.second ().p2 ()), prop_id); + proc.insert (db::Edge (ep.second ().p2 (), ep.first ().p1 ()), prop_id); +} + +// NOTE: these predicates are based on the "polygon" interpretation of edge pairs. +// Edge pairs are considered connected and filled. +// This is different from the interpretation of edge pairs as two edges. + +bool edge_pair_interacts (const db::EdgePair &a, const db::Polygon &b) +{ + db::EdgeProcessor ep; + insert_into_ep (a, ep, 1); + ep.insert (b, 0); + + db::InteractionDetector id (0, 0); + id.set_include_touching (true); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + return id.begin () != id.end (); +} + +bool edge_pair_is_inside (const db::EdgePair &a, const db::Polygon &b) +{ + db::EdgeProcessor ep; + insert_into_ep (a, ep, 1); + ep.insert (b, 0); + + db::InteractionDetector id (-1, 0); + id.set_include_touching (true); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + return id.begin () != id.end (); +} + +bool edge_pair_is_outside (const db::EdgePair &a, const db::Polygon &b) +{ + db::EdgeProcessor ep; + insert_into_ep (a, ep, 1); + ep.insert (b, 0); + + db::InteractionDetector id (1, 0); + id.set_include_touching (false); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + return id.begin () != id.end (); +} + +bool edge_pair_interacts (const db::EdgePair &a, const db::Edge &b) +{ + return edge_interacts (a.first (), b) || edge_interacts (a.second (), b); +} + +} diff --git a/src/db/db/dbEdgePairsUtils.h b/src/db/db/dbEdgePairsUtils.h new file mode 100644 index 000000000..1c4ffe9a0 --- /dev/null +++ b/src/db/db/dbEdgePairsUtils.h @@ -0,0 +1,261 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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_dbEdgePairsUtils +#define HDR_dbEdgePairsUtils + +#include "dbCommon.h" +#include "dbHash.h" +#include "dbEdgePairs.h" +#include "dbBoxScanner.h" +#include "tlSelect.h" + +#include + +namespace db { + +/** + * @brief The operation mode for the interaction filters + */ +enum EdgePairInteractionMode { EdgePairsInteract, EdgePairsInside, EdgePairsOutside }; + +/** + * @brief A predicate defining edge pair a interacts with polygon b + */ +DB_PUBLIC bool edge_pair_interacts (const db::EdgePair &a, const db::Polygon &b); + +/** + * @brief A predicate defining edge pair a is "inside" polygon b + */ +DB_PUBLIC bool edge_pair_is_inside (const db::EdgePair &a, const db::Polygon &b); + +/** + * @brief A predicate defining edge pair a is "outside" polygon b + */ +DB_PUBLIC bool edge_pair_is_outside (const db::EdgePair &a, const db::Polygon &b); + +/** + * @brief A helper class for the edge pair to region interaction functionality which acts as an edge pair receiver + * + * Note: This special scanner uses pointers to two different objects: edge pairs and polygons. + * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate + * pointers to edge pairs. + * + * There is a special box converter which is able to sort that out as well. + */ +template +class edge_pair_to_polygon_interaction_filter + : public db::box_scanner_receiver2 +{ +public: + edge_pair_to_polygon_interaction_filter (OutputContainer *output, EdgePairInteractionMode mode, size_t min_count, size_t max_count) + : mp_output (output), m_mode (mode), m_min_count (min_count), m_max_count (max_count) + { + // NOTE: "counting" does not really make much sense in Outside mode ... + m_counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + tl_assert (!m_counting || mode != EdgePairsOutside); + } + + void finish (const OutputType *o) + { + if (m_counting) { + + size_t count = 0; + auto i = m_counts.find (o); + if (i != m_counts.end ()) { + count = i->second; + } + + bool match = (count >= m_min_count && count <= m_max_count); + if (match == (m_mode != EdgePairsOutside)) { + mp_output->insert (*o); + } + + } else { + + if (m_mode == EdgePairsOutside && m_seen.find (o) == m_seen.end ()) { + mp_output->insert (*o); + } + + } + } + + void finish1 (const db::EdgePair *o, size_t /*p*/) + { + const OutputType *ep = 0; + tl::select (ep, o, (const db::Polygon *) 0); + if (ep) { + finish (ep); + } + } + + void finish2 (const db::Polygon *o, size_t /*p*/) + { + const OutputType *ep = 0; + tl::select (ep, (const db::EdgePair *) 0, o); + if (ep) { + finish (ep); + } + } + + void add (const db::EdgePair *e, size_t, const db::Polygon *p, size_t) + { + const OutputType *ep = 0; + tl::select (ep, e, p); + + if (m_counting) { + + if ((m_mode == EdgePairsInteract && db::edge_pair_interacts (*e, *p)) || + (m_mode == EdgePairsInside && db::edge_pair_is_inside (*e, *p)) || + (m_mode == EdgePairsOutside && ! db::edge_pair_is_outside (*e, *p))) { + + // we report the result on "finish" here. + m_counts[ep] += 1; + + } + + } else if (m_seen.find (ep) == m_seen.end ()) { + + if ((m_mode == EdgePairsInteract && db::edge_pair_interacts (*e, *p)) || + (m_mode == EdgePairsInside && db::edge_pair_is_inside (*e, *p))) { + + m_seen.insert (ep); + mp_output->insert (*ep); + + } else if (m_mode == EdgePairsOutside && ! db::edge_pair_is_outside (*e, *p)) { + + // In this case we need to collect edges which are outside always - we report those on "finished". + m_seen.insert (ep); + + } + + } + } + +private: + OutputContainer *mp_output; + std::map m_counts; + std::set m_seen; + EdgePairInteractionMode m_mode; + size_t m_min_count, m_max_count; + bool m_counting; +}; + +/** + * @brief A predicate defining edge pair a interacts with edge b + */ +DB_PUBLIC bool edge_pair_interacts (const db::EdgePair &a, const db::Edge &b); + +/** + * @brief A helper class for the edge pair to region interaction functionality which acts as an edge pair receiver + * + * Note: This special scanner uses pointers to two different objects: edge pairs and polygons. + * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate + * pointers to edge pairs. + * + * There is a special box converter which is able to sort that out as well. + */ +template +class edge_pair_to_edge_interaction_filter + : public db::box_scanner_receiver2 +{ +public: + edge_pair_to_edge_interaction_filter (OutputContainer *output, size_t min_count, size_t max_count) + : mp_output (output), m_min_count (min_count), m_max_count (max_count) + { + m_counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); + } + + void finish (const OutputType *o) + { + if (m_counting) { + + size_t count = 0; + auto i = m_counts.find (o); + if (i != m_counts.end ()) { + count = i->second; + } + + bool match = (count >= m_min_count && count <= m_max_count); + if (match) { + mp_output->insert (*o); + } + + } + } + + void finish1 (const db::EdgePair *o, size_t /*p*/) + { + const OutputType *ep = 0; + tl::select (ep, o, (const db::Edge *) 0); + if (ep) { + finish (ep); + } + } + + void finish2 (const db::Edge *o, size_t /*p*/) + { + const OutputType *ep = 0; + tl::select (ep, (const db::EdgePair *) 0, o); + if (ep) { + finish (ep); + } + } + + void add (const db::EdgePair *e, size_t, const db::Edge *p, size_t) + { + const OutputType *ep = 0; + tl::select (ep, e, p); + + if (m_counting) { + + if (db::edge_pair_interacts (*e, *p)) { + + // we report the result on "finish" here. + m_counts[ep] += 1; + + } + + } else if (m_seen.find (ep) == m_seen.end ()) { + + if (db::edge_pair_interacts (*e, *p)) { + + m_seen.insert (ep); + mp_output->insert (*ep); + + } + + } + } + +private: + OutputContainer *mp_output; + std::map m_counts; + std::set m_seen; + EdgePairInteractionMode m_mode; + size_t m_min_count, m_max_count; + bool m_counting; +}; + +} // namespace db + +#endif diff --git a/src/db/db/dbEdgesLocalOperations.cc b/src/db/db/dbEdgesLocalOperations.cc index 3572b131c..544758948 100644 --- a/src/db/db/dbEdgesLocalOperations.cc +++ b/src/db/db/dbEdgesLocalOperations.cc @@ -344,7 +344,7 @@ std::string Edge2EdgePullLocalOperation::description () const // --------------------------------------------------------------------------------------------- -// Edge2EdgePullLocalOperation implementation +// edge_to_polygon_interacting_local_operation implementation template edge_to_polygon_interacting_local_operation::edge_to_polygon_interacting_local_operation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count)