diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 64a94e144..c0fc78fc4 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -21,7 +21,9 @@ */ #include "dbEdges.h" +#include "dbRegion.h" #include "dbDeepEdges.h" +#include "dbDeepRegion.h" #include "dbHierNetworkProcessor.h" #include "dbCellGraphUtils.h" #include "dbCellVariants.h" @@ -527,6 +529,24 @@ DeepEdges::and_or_not_with (const DeepEdges *other, bool and_op) const return dl_out; } +DeepLayer +DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const +{ + DeepLayer dl_out (m_deep_layer.derived ()); + + db::EdgeToPolygonLocalOperation op (outside, include_borders); + + db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (m_deep_layer.store ()->threads ()); + proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); + proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + + proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ()); + + return dl_out; +} + EdgesDelegate *DeepEdges::and_with (const Edges &other) const { const DeepEdges *other_deep = dynamic_cast (other.delegate ()); @@ -549,8 +569,27 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const EdgesDelegate *DeepEdges::and_with (const Region &other) const { - // TODO: implement - return AsIfFlatEdges::and_with (other); + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + // Nothing to do + return new EmptyEdges (); + + } else if (other.empty ()) { + + // Nothing to do + return clone (); + + } else if (! other_deep) { + + return AsIfFlatEdges::not_with (other); + + } else { + + return new DeepEdges (edge_region_op (other_deep, false /*outside*/, true /*include borders*/)); + + } } EdgesDelegate *DeepEdges::not_with (const Edges &other) const @@ -580,8 +619,27 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const EdgesDelegate *DeepEdges::not_with (const Region &other) const { - // TODO: implement - return AsIfFlatEdges::not_with (other); + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + // Nothing to do + return new EmptyEdges (); + + } else if (other.empty ()) { + + // Nothing to do + return clone (); + + } else if (! other_deep) { + + return AsIfFlatEdges::not_with (other); + + } else { + + return new DeepEdges (edge_region_op (other_deep, true /*outside*/, true /*include borders*/)); + + } } EdgesDelegate *DeepEdges::xor_with (const Edges &other) const @@ -663,14 +721,52 @@ EdgesDelegate *DeepEdges::add (const Edges &other) const EdgesDelegate *DeepEdges::inside_part (const Region &other) const { - // TODO: implement - return AsIfFlatEdges::inside_part (other); + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + // Nothing to do + return new EmptyEdges (); + + } else if (other.empty ()) { + + // Nothing to do + return clone (); + + } else if (! other_deep) { + + return AsIfFlatEdges::not_with (other); + + } else { + + return new DeepEdges (edge_region_op (other_deep, false /*outside*/, false /*include borders*/)); + + } } EdgesDelegate *DeepEdges::outside_part (const Region &other) const { - // TODO: implement - return AsIfFlatEdges::outside_part (other); + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + // Nothing to do + return new EmptyEdges (); + + } else if (other.empty ()) { + + // Nothing to do + return clone (); + + } else if (! other_deep) { + + return AsIfFlatEdges::not_with (other); + + } else { + + return new DeepEdges (edge_region_op (other_deep, true /*outside*/, false /*include borders*/)); + + } } RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 8189f5d20..bdc7a67bc 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -33,6 +33,7 @@ namespace db { class Edges; +class DeepRegion; /** * @brief Provides hierarchical edges implementation @@ -170,6 +171,7 @@ private: void init (); void ensure_merged_edges_valid () const; DeepLayer and_or_not_with(const DeepEdges *other, bool and_op) const; + DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const; EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; }; diff --git a/src/db/db/dbLocalOperation.cc b/src/db/db/dbLocalOperation.cc index 6ac7341d0..b219d5ca4 100644 --- a/src/db/db/dbLocalOperation.cc +++ b/src/db/db/dbLocalOperation.cc @@ -241,5 +241,70 @@ EdgeBoolAndOrNotLocalOperation::compute_local (db::Layout * /*layout*/, const sh } } +// --------------------------------------------------------------------------------------------- +// EdgeToPolygonLocalOperation implementation + +EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (bool outside, bool include_borders) + : m_outside (outside), m_include_borders (include_borders) +{ + // .. nothing yet .. +} + +local_operation::on_empty_intruder_mode +EdgeToPolygonLocalOperation::on_empty_intruder_hint () const +{ + return m_outside ? local_operation::Copy : local_operation::Drop; +} + +std::string +EdgeToPolygonLocalOperation::description () const +{ + return tl::to_string (m_outside ? tr ("Edge to polygon AND/INSIDE") : tr ("Edge to polygons NOT/OUTSIDE")); +} + +void +EdgeToPolygonLocalOperation::compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const +{ + 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)); + } + } + + bool any_subject = false; + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::Edge &subject = interactions.subject_shape (i->first); + if (i->second.empty ()) { + // shortcut (outside: keep, otherwise: drop) + if (m_outside) { + result.insert (subject); + } + } else { + ep.insert (subject, 1); + any_subject = true; + } + + } + + if (! others.empty () || any_subject) { + + 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, 0); + } + } + + db::EdgeToEdgeSetGenerator cc (result); + db::EdgePolygonOp op (m_outside, m_include_borders); + ep.process (cc, op); + + } +} + } diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index 294a29f3e..499704b29 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -164,6 +164,30 @@ private: bool m_is_and; }; +/** + * @brief Implements a boolean AND or NOT operation between edges and polygons (polygons as intruders) + * + * "AND" is implemented by "outside == false", "NOT" by "outside == true" with "include_borders == true". + * With "include_borders == false" the operations are "INSIDE" and "OUTSIDE". + */ +class DB_PUBLIC EdgeToPolygonLocalOperation + : public local_operation +{ +public: + EdgeToPolygonLocalOperation (bool outside, bool include_borders); + + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t max_vertex_count, double area_ratio) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + + // edge interaction distance is 1 to force overlap between edges and edge/boxes + virtual db::Coord dist () const { return m_include_borders ? 1 : 0; } + +private: + bool m_outside; + bool m_include_borders; +}; + } #endif diff --git a/src/db/db/dbLocalOperationUtils.cc b/src/db/db/dbLocalOperationUtils.cc index 045efeaf1..4c478743e 100644 --- a/src/db/db/dbLocalOperationUtils.cc +++ b/src/db/db/dbLocalOperationUtils.cc @@ -42,6 +42,20 @@ void PolygonRefGenerator::put (const db::Polygon &polygon) mp_polyrefs->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); } +// ----------------------------------------------------------------------------------------------- +// class EdgeToEdgeSetGenerator + +EdgeToEdgeSetGenerator::EdgeToEdgeSetGenerator (std::unordered_set &edges) + : mp_edges (&edges) +{ + // .. nothing yet .. +} + +void EdgeToEdgeSetGenerator::put (const db::Edge &edge) +{ + mp_edges->insert (edge); +} + // ----------------------------------------------------------------------------------------------- // class PolygonRefGenerator diff --git a/src/db/db/dbLocalOperationUtils.h b/src/db/db/dbLocalOperationUtils.h index 17cff886c..8665eec2c 100644 --- a/src/db/db/dbLocalOperationUtils.h +++ b/src/db/db/dbLocalOperationUtils.h @@ -41,7 +41,7 @@ class PolygonRefGenerator { public: /** - * @brief Constructor specifying an external vector for storing the polygons + * @brief Constructor */ PolygonRefGenerator (db::Layout *layout, std::unordered_set &polyrefs); @@ -55,6 +55,24 @@ private: std::unordered_set *mp_polyrefs; }; +class EdgeToEdgeSetGenerator + : public EdgeSink +{ +public: + /** + * @brief Constructor + */ + EdgeToEdgeSetGenerator (std::unordered_set &edges); + + /** + * @brief Implementation of the PolygonSink interface + */ + virtual void put (const db::Edge &edge); + +private: + std::unordered_set *mp_edges; +}; + class PolygonRefToShapesGenerator : public PolygonSink { diff --git a/src/db/unit_tests/dbDeepEdgesTests.cc b/src/db/unit_tests/dbDeepEdgesTests.cc index a3f518232..f1ea9b6bd 100644 --- a/src/db/unit_tests/dbDeepEdgesTests.cc +++ b/src/db/unit_tests/dbDeepEdgesTests.cc @@ -148,3 +148,48 @@ TEST(3_Edge2EdgeBooleans) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au3.gds"); } +TEST(4_Edge2PolygonBooleans) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); + + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); + db::Region r2and3 = r2 & r3; + + db::Edges e3 = r3.edges (); + + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (3, 0)), r3); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e3 & r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e3 & r2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e3 - r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e3 - r2and3); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3.inside_part (r2)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3.inside_part (r2and3)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3.outside_part (r2)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3.outside_part (r2and3)); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_edges_au4.gds"); +} + diff --git a/testdata/algo/deep_edges_au4.gds b/testdata/algo/deep_edges_au4.gds new file mode 100644 index 000000000..f91ff8526 Binary files /dev/null and b/testdata/algo/deep_edges_au4.gds differ