From b0fc2be96ef662dbad0a30181a3d87c1b332c4ad Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 Feb 2019 01:07:32 +0100 Subject: [PATCH] Deep regions: some more operations implemented hierarchically - snap (!) - but only for gx == gy - filtering - interact/inside/outside/overlap + not_... variants - edges --- src/db/db/dbAsIfFlatRegion.cc | 93 ++++--- src/db/db/dbAsIfFlatRegion.h | 3 + src/db/db/dbCellVariants.h | 59 +++- src/db/db/dbDeepEdgePairs.cc | 4 +- src/db/db/dbDeepEdges.cc | 4 +- src/db/db/dbDeepRegion.cc | 297 +++++++++++++++++---- src/db/db/dbDeepRegion.h | 5 + src/db/db/dbDeepShapeStore.cc | 7 - src/db/db/dbDeepShapeStore.h | 5 - src/db/db/dbEdges.h | 66 ++++- src/db/unit_tests/dbDeepRegionTests.cc | 173 ++++++++++++ testdata/algo/deep_region_area_peri_l1.gds | Bin 760 -> 1016 bytes testdata/algo/deep_region_au12.gds | Bin 0 -> 4888 bytes testdata/algo/deep_region_au13.gds | Bin 0 -> 2488 bytes testdata/algo/deep_region_au14.gds | Bin 0 -> 2778 bytes testdata/algo/deep_region_au15a.gds | Bin 0 -> 1322 bytes testdata/algo/deep_region_au15b.gds | Bin 0 -> 1664 bytes 17 files changed, 597 insertions(+), 119 deletions(-) create mode 100644 testdata/algo/deep_region_au12.gds create mode 100644 testdata/algo/deep_region_au13.gds create mode 100644 testdata/algo/deep_region_au14.gds create mode 100644 testdata/algo/deep_region_au15a.gds create mode 100644 testdata/algo/deep_region_au15b.gds diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 20be32979..7b249ef60 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -619,6 +619,40 @@ static inline db::Coord snap_to_grid (db::Coord c, db::Coord g) return c; } +db::Polygon +AsIfFlatRegion::snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector &heap) +{ + db::Polygon pnew; + + for (size_t i = 0; i < poly.holes () + 1; ++i) { + + heap.clear (); + + db::Polygon::polygon_contour_iterator b, e; + + if (i == 0) { + b = poly.begin_hull (); + e = poly.end_hull (); + } else { + b = poly.begin_hole ((unsigned int) (i - 1)); + e = poly.end_hole ((unsigned int) (i - 1)); + } + + for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { + heap.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy))); + } + + if (i == 0) { + pnew.assign_hull (heap.begin (), heap.end ()); + } else { + pnew.insert_hole (heap.begin (), heap.end ()); + } + + } + + return pnew; +} + RegionDelegate * AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) { @@ -627,40 +661,10 @@ AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) gx = std::max (db::Coord (1), gx); gy = std::max (db::Coord (1), gy); - std::vector pts; + std::vector heap; for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - - db::Polygon pnew; - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - pts.clear (); - - db::Polygon::polygon_contour_iterator b, e; - - if (i == 0) { - b = p->begin_hull (); - e = p->end_hull (); - } else { - b = p->begin_hole ((unsigned int) (i - 1)); - e = p->end_hole ((unsigned int) (i - 1)); - } - - for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { - pts.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy))); - } - - if (i == 0) { - pnew.assign_hull (pts.begin (), pts.end ()); - } else { - pnew.insert_hole (pts.begin (), pts.end ()); - } - - } - - new_region->raw_polygons ().insert (pnew); - + new_region->raw_polygons ().insert (snapped_polygon (*p, gx, gy, heap)); } return new_region.release (); @@ -677,22 +681,25 @@ struct DB_PUBLIC StrangePolygonInsideFunc } }; +void +AsIfFlatRegion::produce_shape_for_strange_polygon (const db::Polygon &poly, db::Shapes &shapes) +{ + EdgeProcessor ep; + ep.insert (poly); + + StrangePolygonInsideFunc inside; + db::GenericMerge op (inside); + db::ShapeGenerator pc (shapes, false); + db::PolygonGenerator pg (pc, false, false); + ep.process (pg, op); +} + RegionDelegate * AsIfFlatRegion::strange_polygon_check () const { - EdgeProcessor ep; std::auto_ptr new_region (new FlatRegion (merged_semantics ())); - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - - ep.clear (); - ep.insert (*p); - - StrangePolygonInsideFunc inside; - db::GenericMerge op (inside); - db::ShapeGenerator pc (new_region->raw_polygons (), false); - db::PolygonGenerator pg (pc, false, false); - ep.process (pg, op); + produce_shape_for_strange_polygon (*p, new_region->raw_polygons ()); } return new_region.release (); diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index c8d5cf92e..7235781e5 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -212,6 +212,9 @@ protected: RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; + static void produce_shape_for_strange_polygon (const db::Polygon &poly, db::Shapes &shapes); + static db::Polygon snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector &heap); + private: AsIfFlatRegion &operator= (const AsIfFlatRegion &other); diff --git a/src/db/db/dbCellVariants.h b/src/db/db/dbCellVariants.h index 94e11a34f..11f2fde8d 100644 --- a/src/db/db/dbCellVariants.h +++ b/src/db/db/dbCellVariants.h @@ -87,6 +87,28 @@ struct DB_PUBLIC MagnificationReducer } }; +/** + * @brief A magnification and orientation reducer + * + * This reducer incarnation reduces the transformation to it's rotation/mirror/magnification part (2d matrix) + */ +struct DB_PUBLIC MagnificationAndOrientationReducer +{ + typedef tl::true_tag is_translation_invariant; + + db::ICplxTrans operator () (const db::ICplxTrans &trans) const + { + db::ICplxTrans res (trans); + res.disp (db::Vector ()); + return res; + } + + db::Trans operator () (const db::Trans &trans) const + { + return db::Trans (trans.fp_trans ()); + } +}; + /** * @brief A grid reducer * @@ -125,13 +147,32 @@ private: inline db::Coord mod (db::Coord c) const { if (c < 0) { - return m_grid - (-c) % m_grid; + c = m_grid - (-c) % m_grid; + if (c == m_grid) { + return 0; + } else { + return c; + } } else { return c % m_grid; } } }; +/** + * @brief A base class for the variants collector + */ +class DB_PUBLIC VariantsCollectorBase +{ +public: + VariantsCollectorBase () { } + virtual ~VariantsCollectorBase () { } + + virtual void collect (const db::Layout &layout, const db::Cell &top_cell) = 0; + virtual void separate_variants (db::Layout &layout, db::Cell &top_cell, std::map > *var_table = 0) = 0; + virtual const std::map &variants (db::cell_index_type ci) const = 0; +}; + /** * @brief A class computing variants for cells according to a given criterion * @@ -149,10 +190,20 @@ private: */ template class DB_PUBLIC cell_variants_collector + : public VariantsCollectorBase { public: typedef cell_variants_reduce_traits compare_traits; + /** + * @brief Creates a variant extractor + */ + cell_variants_collector () + : m_red () + { + // .. nothing yet .. + } + /** * @brief Creates a variant extractor */ @@ -165,7 +216,7 @@ public: /** * @brief Collects cell variants for the given layout starting from the top cell */ - void collect (const db::Layout &layout, const db::Cell &top_cell) + virtual void collect (const db::Layout &layout, const db::Cell &top_cell) { // The top cell gets a "variant" with unit transformation m_variants [top_cell.cell_index ()].insert (std::make_pair (db::ICplxTrans (), 1)); @@ -207,7 +258,7 @@ public: * If given, *var_table will be filled with a map giving the new cell and variant against * the old cell for all cells with more than one variant. */ - void separate_variants (db::Layout &layout, db::Cell &top_cell, std::map > *var_table = 0) + virtual void separate_variants (db::Layout &layout, db::Cell &top_cell, std::map > *var_table = 0) { db::LayoutLocker locker (&layout); @@ -309,7 +360,7 @@ public: * The keys of the map are the variants, the values is the instance count of the variant * (as seen from the top cell). */ - const std::map &variants (db::cell_index_type ci) const + virtual const std::map &variants (db::cell_index_type ci) const { std::map >::const_iterator v = m_variants.find (ci); static std::map empty_set; diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc index a07449d89..62f95a4f2 100644 --- a/src/db/db/dbDeepEdgePairs.cc +++ b/src/db/db/dbDeepEdgePairs.cc @@ -243,7 +243,7 @@ EdgePairsDelegate *DeepEdgePairs::filtered (const EdgePairFilterBase &filter) co RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const { - db::DeepLayer new_layer = m_deep_layer.new_layer (); + db::DeepLayer new_layer = m_deep_layer.derived (); db::Layout &layout = const_cast (m_deep_layer.layout ()); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { @@ -261,7 +261,7 @@ RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const EdgesDelegate *DeepEdgePairs::generic_edges (bool first, bool second) const { - db::DeepLayer new_layer = m_deep_layer.new_layer (); + db::DeepLayer new_layer = m_deep_layer.derived (); db::Layout &layout = const_cast (m_deep_layer.layout ()); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 8ecaef032..e7d1eea13 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -354,7 +354,7 @@ DeepEdges::ensure_merged_edges_valid () const { if (! m_merged_edges_valid) { - m_merged_edges = m_deep_layer.new_layer (); + m_merged_edges = m_deep_layer.derived (); tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); @@ -480,7 +480,7 @@ EdgesDelegate *DeepEdges::merged () const db::Layout &layout = const_cast (m_merged_edges.layout ()); - std::auto_ptr res (new db::DeepEdges (m_merged_edges.new_layer ())); + std::auto_ptr res (new db::DeepEdges (m_merged_edges.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { c->shapes (res->deep_layer ().layer ()) = c->shapes (m_merged_edges.layer ()); } diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 14516effb..133e45c2a 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -25,6 +25,7 @@ #include "dbDeepShapeStore.h" #include "dbEmptyRegion.h" #include "dbRegion.h" +#include "dbDeepEdges.h" #include "dbShapeProcessor.h" #include "dbFlatRegion.h" #include "dbHierProcessor.h" @@ -367,7 +368,7 @@ DeepRegion::ensure_merged_polygons_valid () const { if (! m_merged_polygons_valid) { - m_merged_polygons = m_deep_layer.new_layer (); + m_merged_polygons = m_deep_layer.derived (); tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); @@ -598,8 +599,7 @@ DeepRegion::area (const db::Box &box) const ensure_merged_polygons_valid (); - db::MagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_collector vars; vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); DeepRegion::area_type a = 0; @@ -632,8 +632,7 @@ DeepRegion::perimeter (const db::Box &box) const ensure_merged_polygons_valid (); - db::MagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_collector vars; vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); DeepRegion::perimeter_type p = 0; @@ -688,50 +687,148 @@ DeepRegion::angle_check (double min, double max, bool inverse) const RegionDelegate * DeepRegion::snapped (db::Coord gx, db::Coord gy) { - // NOTE: snap be optimized by forming grid variants etc. - return db::AsIfFlatRegion::snapped (gx, gy); + if (gx <= 0 || gy <= 0) { + throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value"))); + } + + if (gx != gy) { + // no way doing this hierarchically ? + return db::AsIfFlatRegion::snapped (gx, gy); + } + + ensure_merged_polygons_valid (); + + db::cell_variants_collector vars (gx); + + vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); + + // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? + const_cast (m_merged_polygons).separate_variants (vars); + + db::Layout &layout = m_merged_polygons.layout (); + std::vector heap; + + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const std::map &v = vars.variants (c->cell_index ()); + tl_assert (v.size () == size_t (1)); + const db::ICplxTrans &tr = v.begin ()->first; + db::ICplxTrans trinv = tr.inverted (); + + const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + + db::Polygon poly; + si->polygon (poly); + poly.transform (tr); + st.insert (snapped_polygon (poly, gx, gy, heap).transformed (trinv)); + + } + + } + + return res.release (); } Edges DeepRegion::edges (const EdgeFilterBase *filter) const { - // NOTE: needs a deep edge set for optimizing for hierarchy. - // At least the length filter is easy to optimize in the hierarchical case. - return db::AsIfFlatRegion::edges (filter); -} + ensure_merged_polygons_valid (); -RegionDelegate * -DeepRegion::filtered (const PolygonFilterBase &filter) const -{ - if (filter.isotropic ()) { + std::auto_ptr vars; - ensure_merged_polygons_valid (); + if (filter) { - // @@@ scaled instances! + if (filter->isotropic ()) { + vars.reset (new db::cell_variants_collector ()); + } else { + vars.reset (new db::cell_variants_collector ()); + } - db::Layout &layout = m_merged_polygons.layout (); + vars->collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? + const_cast (m_merged_polygons).separate_variants (*vars); - const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); - db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + } - for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - db::Polygon poly; - si->polygon (poly); - if (filter.selected (poly)) { - st.insert (poly); + db::Layout &layout = m_merged_polygons.layout (); + + std::auto_ptr res (new db::DeepEdges (m_merged_polygons.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + db::ICplxTrans tr; + if (vars.get ()) { + const std::map &v = vars->variants (c->cell_index ()); + tl_assert (v.size () == size_t (1)); + tr = v.begin ()->first; + } + + const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + + db::Polygon poly; + si->polygon (poly); + + for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { + if (! filter || filter->selected ((*e).transformed (tr))) { + st.insert (*e); } } } - return res.release (); - - } else { - return db::AsIfFlatRegion::filtered (filter); } + + return db::Edges (res.release ()); +} + +RegionDelegate * +DeepRegion::filtered (const PolygonFilterBase &filter) const +{ + ensure_merged_polygons_valid (); + + std::auto_ptr vars; + + if (filter.isotropic ()) { + vars.reset (new db::cell_variants_collector ()); + } else { + vars.reset (new db::cell_variants_collector ()); + } + + vars->collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); + + // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? + const_cast (m_merged_polygons).separate_variants (*vars); + + db::Layout &layout = m_merged_polygons.layout (); + + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const std::map &v = vars->variants (c->cell_index ()); + tl_assert (v.size () == size_t (1)); + const db::ICplxTrans &tr = v.begin ()->first; + + const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + db::Polygon poly; + si->polygon (poly); + if (filter.selected (poly.transformed (tr))) { + st.insert (poly); + } + } + + } + + return res.release (); } RegionDelegate * @@ -759,7 +856,7 @@ DeepRegion::merged () const db::Layout &layout = const_cast (m_merged_polygons.layout ()); - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { c->shapes (res->deep_layer ().layer ()) = c->shapes (m_merged_polygons.layer ()); } @@ -779,8 +876,7 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const RegionDelegate * DeepRegion::strange_polygon_check () const { - // TODO: can probably be optimized - return db::AsIfFlatRegion::strange_polygon_check (); + throw tl::Exception (tl::to_string (tr ("A strange polygon check does not make sense on a processed region - polygons are already normalized"))); } RegionDelegate * @@ -790,14 +886,13 @@ DeepRegion::sized (coord_type d, unsigned int mode) const db::Layout &layout = m_merged_polygons.layout (); - db::MagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_collector vars; vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? const_cast (m_merged_polygons).separate_variants (vars); - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { const std::map &v = vars.variants (c->cell_index ()); @@ -858,14 +953,13 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const db::Layout &layout = m_merged_polygons.layout (); - db::XYAnisotropyAndMagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_collector vars; vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? const_cast (m_merged_polygons).separate_variants (vars); - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { const std::map &v = vars.variants (c->cell_index ()); @@ -907,7 +1001,7 @@ DeepRegion::holes () const std::vector pts; - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); @@ -940,7 +1034,7 @@ DeepRegion::hulls () const std::vector pts; - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); @@ -974,8 +1068,7 @@ DeepRegion::rounded_corners (double rinner, double router, unsigned int n) const { ensure_merged_polygons_valid (); - db::MagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_collector vars; vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? @@ -983,7 +1076,7 @@ DeepRegion::rounded_corners (double rinner, double router, unsigned int n) const db::Layout &layout = m_merged_polygons.layout (); - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { const std::map &v = vars.variants (c->cell_index ()); @@ -1012,8 +1105,7 @@ DeepRegion::smoothed (coord_type d) const { ensure_merged_polygons_valid (); - db::MagnificationReducer red; - db::cell_variants_collector vars (red); + db::cell_variants_collector vars; vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? @@ -1021,7 +1113,7 @@ DeepRegion::smoothed (coord_type d) const db::Layout &layout = m_merged_polygons.layout (); - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.new_layer ())); + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { const std::map &v = vars.variants (c->cell_index ()); @@ -1058,11 +1150,116 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, b return db::AsIfFlatRegion::run_single_polygon_check (rel, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); } +namespace +{ + +class InteractingLocalOperation + : public local_operation +{ +public: + InteractingLocalOperation (int mode, bool touching, bool inverse) + : m_mode (mode), m_touching (touching), m_inverse (inverse) + { + // .. nothing yet .. + } + + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + m_ep.clear (); + + 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)); + } + } + + size_t n = 1; + 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) { + m_ep.insert (*e, n); + } + } + + 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) { + m_ep.insert (*e, 0); + } + } + + db::InteractionDetector id (m_mode, 0); + id.set_include_touching (m_touching); + db::EdgeSink es; + m_ep.process (es, id); + id.finish (); + + n = 0; + std::set selected; + for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { + ++n; + selected.insert (i->second); + } + + n = 1; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { + if ((selected.find (n) == selected.end ()) == 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; + mutable db::EdgeProcessor m_ep; +}; + +} + RegionDelegate * DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const { - // TODO: implement hierarchically - return db::AsIfFlatRegion::selected_interacting_generic (other, mode, touching, inverse); + const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + return db::AsIfFlatRegion::selected_interacting_generic (other, mode, touching, inverse); + } + + ensure_merged_polygons_valid (); + + DeepLayer dl_out (m_deep_layer.derived ()); + + db::InteractingLocalOperation op (mode, touching, inverse); + + db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (m_deep_layer.store ()->threads ()); +#if 0 + // with these settings, the resulting polygons are broken again ... + proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); + proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); +#endif + + proc.run (&op, m_merged_polygons.layer (), other_deep->merged_deep_layer ().layer (), dl_out.layer ()); + + // TODO: mark the results as merged (unless we split - see above) + return new db::DeepRegion (dl_out); } RegionDelegate * diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 3b686d9f7..8eec5ab51 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -241,6 +241,11 @@ private: EdgePairs run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; + + const DeepLayer &merged_deep_layer () const + { + return m_merged_polygons; + } }; } diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 9dfe32119..fa4f9d355 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -174,13 +174,6 @@ bool DeepLayer::operator== (const DeepLayer &other) const return true; } -DeepLayer -DeepLayer::new_layer() const -{ - db::DeepShapeStore *store = const_cast (mp_store.get ()); - return DeepLayer (store, m_layout, store->layout (m_layout).insert_layer ()); -} - db::Layout & DeepLayer::layout () { diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index d7b792e0f..96dc17af3 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -93,11 +93,6 @@ public: */ bool operator== (const DeepLayer &other) const; - /** - * @brief Creates a new empty layer based on this one - */ - DeepLayer new_layer () const; - /** * @brief Gets the layout object * The return value is guaranteed to be non-null. diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index ee7a5385c..e4cac3b67 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -209,6 +209,7 @@ public: virtual ~EdgeFilterBase () { } virtual bool selected (const db::Edge &edge) const = 0; + virtual bool isotropic () const = 0; }; /** @@ -251,6 +252,11 @@ struct DB_PUBLIC EdgeLengthFilter } } + bool isotropic () const + { + return true; + } + private: length_type m_lmin, m_lmax; bool m_inverse; @@ -274,7 +280,7 @@ struct DB_PUBLIC EdgeOrientationFilter * * @param amin The minimum angle (measured against the x axis) * @param amax The maximum angle (measured against the x axis) - * @param inverse If set to true, only polygons not matching this criterion will be filtered + * @param inverse If set to true, only edges not matching this criterion will be filtered * * This filter will filter out all edges whose angle against x axis * is larger or equal to amin and less than amax. @@ -290,7 +296,7 @@ struct DB_PUBLIC EdgeOrientationFilter * @brief Constructor * * @param a The angle (measured against the x axis) - * @param inverse If set to true, only polygons not matching this criterion will be filtered + * @param inverse If set to true, only edges not matching this criterion will be filtered * * This filter will filter out all edges whose angle against x axis * is equal to a. @@ -323,6 +329,11 @@ struct DB_PUBLIC EdgeOrientationFilter } } + bool isotropic () const + { + return false; + } + private: db::DVector m_emin, m_emax; bool m_inverse; @@ -387,12 +398,55 @@ public: Edges &operator= (const Edges &other); /** - * @brief Constructor from an object + * @brief Constructor from a box * - * Creates an edge set representing a single instance of that object + * Creates an edge set representing the contour of the box */ - template - explicit Edges (const Sh &s) + explicit Edges (const db::Box &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from a simple polygon + * + * Creates an edge set representing the contour of the polygon + */ + explicit Edges (const db::SimplePolygon &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from a polygon + * + * Creates an edge set representing the contour of the polygon + */ + explicit Edges (const db::Polygon &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from a path + * + * Creates an edge set representing the contour of the path + */ + explicit Edges (const db::Path &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from an edge + * + * Creates an edge set representing the single edge + */ + explicit Edges (const db::Edge &s) : mp_delegate (0) { insert (s); diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 4130f5d3c..648c39d24 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -25,6 +25,7 @@ #include "dbReader.h" #include "dbTestSupport.h" #include "dbRegion.h" +#include "dbEdges.h" #include "dbDeepShapeStore.h" #include "tlUnitTest.h" #include "tlStream.h" @@ -652,6 +653,178 @@ TEST(11_RoundAndSmoothed) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au11.gds"); } +TEST(12_GridSnap) +{ + 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 l3 = ly.get_layer (db::LayerProperties (3, 0)); + + db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); + db::Region r3snapped = r3.snapped (50, 50); + + 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 (10, 0)), r3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r3snapped); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au12.gds"); +} + +TEST(13_Edges) +{ + 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 l3 = ly.get_layer (db::LayerProperties (3, 0)); + + db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); + db::Edges r3edges = r3.edges (); + + db::EdgeLengthFilter f (0, 500, true); + db::Edges r3edges_filtered = r3.edges (f); + + 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 (10, 0)), r3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r3edges); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r3edges_filtered); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au13.gds"); +} + +TEST(14_Interacting) +{ + 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 l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l6 = ly.get_layer (db::LayerProperties (6, 0)); + + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Region r6 (db::RecursiveShapeIterator (ly, top_cell, l6), dss); + + 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 (10, 0)), r2.selected_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.selected_not_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.selected_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.selected_not_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r2.selected_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r2.selected_not_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (16, 0)), r2.selected_overlapping (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (17, 0)), r2.selected_not_overlapping (r1)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r6.selected_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r6.selected_not_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r6.selected_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r6.selected_not_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r6.selected_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r6.selected_not_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r6.selected_overlapping (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), r6.selected_not_overlapping (r1)); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14.gds"); +} + +TEST(15_Filtered) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_area_peri_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 l1 = ly.get_layer (db::LayerProperties (1, 0)); + + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + db::RegionAreaFilter af1 (0, 1000000000, false); + db::Region af1_filtered = r1.filtered (af1); + db::RegionAreaFilter af1inv (0, 1000000000, true); + db::Region af1_else = r1.filtered (af1inv); + + { + 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 (10, 0)), r1); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), af1_filtered); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), af1_else); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au15a.gds"); + } + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::RegionBBoxFilter bwf (0, 50000, false, db::RegionBBoxFilter::BoxWidth); + db::RegionBBoxFilter bhf (0, 50000, false, db::RegionBBoxFilter::BoxHeight); + db::Region r2_bwf = r2.filtered (bwf); + db::Region r2_bhf = r2.filtered (bhf); + + { + 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 (10, 0)), r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2_bwf); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2_bhf); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au15b.gds"); + } +} + TEST(100_Integration) { db::Layout ly; diff --git a/testdata/algo/deep_region_area_peri_l1.gds b/testdata/algo/deep_region_area_peri_l1.gds index e56fc403ea4e642129dfd8400ad59b24e6a1a19c..a4064f66a48f50e2d12a4db81fac1807f163f3f9 100644 GIT binary patch delta 229 zcmeyt`h#7GfsKKQDS|WQnIC9oLCz{bYrIB~xC ZNsP|eY@ftvk4<><4n`|RgyvmLb^tnEAg%xa delta 167 zcmeyt{)1JCfsKKQDS|S+pY5>{ajh3;kIxn5(ciB&*8kJE0CpK18^W5yW-%snmlD!VZPhMcpjPFi^k61t0RihIAKj->J z+3rsmKP#U->^G`)UH|N}M+vQ0US!GSClaK|6A1#@E`&mvOdmy5h0yz!P$=iI->BAg z{ktc$oFsIrOF|QIN>>}9)0u=eMQ9DXf-U#MOHb%2?=T2GwPY?k6*6I06+(|Kp~sr% z2(jziIzxxWPu{R4^S4tW6LwW0bI=kB6+)Ms3YoAQ)w-^K_k>O+2`zU?Xd+JOY9q9g zNoZ4q*0>^6-r$rVIpxoN-eH{Hz9qBfl*wefst|f+2|d$1M@TB6W8x=o%#wNJRLF!~ zRR|righGYTs?!|LP}q%XUDrQ@&_WpUDKF=H(cVDuV>{kHJH{waZA?yPGT9WNHLjRU zVX~k16zug|7B`#J8Iz`|fE#G5kCo5ukqEiH3exye6Syse@Jr{u$4+8oJ@Pd9$ literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_au13.gds b/testdata/algo/deep_region_au13.gds new file mode 100644 index 0000000000000000000000000000000000000000..ade409f90a01666a0a934d521d35d059aff5f1c7 GIT binary patch literal 2488 zcmbW3K`%o=5Xb+0eYVd-6+MXvZW0MWA`S$R(2$a9M8t>i1tbzDH+K$hzJi0ZgOd;7 zAaRy7agt!o?7sE1y8E_znPz8yyR$R@*?kZQf&+}?g2D>|^Z{7F#P9!z0F+?$-9i~coDdm}zAJ1%o{1}a% z7;DDaA{-#T0OwAT5S8lwEW#Lw2hFa%yvx@ytxPNMD($^-qm5S#=S~4y0mxlgR%n@H z)@gUv&o?@!kn-~lh#n}aS7XgMTOG$=o?;kMezME~0o6%cGw$Z`M7f=(bC3BR2qXn z)f~BRgiP`IIKsl6FQsQ|s#xlTDweb+{3%wDrqV9S&ivP_$-FOp^sJJwMC5i<3wUp>#&(%l_Ud>8PZ z{`E>`6V-{LlG*BBGk1Ja<=%hY8&1l4Z#XE&4d9?0H-Lk3^s<$5cBPZjiel}zsMkR` z)SE$RMWx!vc**ITp;oDG>`;*OT1SKWU03h0dOv79dC8l6@vic=^_8#fzR`x=H@RZ> d%{6}$G{v&?Z09y-?7rHm-FNhu`Y3~8h;OYrTXFyZ literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_au14.gds b/testdata/algo/deep_region_au14.gds new file mode 100644 index 0000000000000000000000000000000000000000..7a3109d5096d0607c891b2d9c6b1c3717d95b9f3 GIT binary patch literal 2778 zcmc&$zfapx5dQM)yd_! zgSqx=WQDAhmw|$lez){tVeR{u=9`t%*^^H@b&RK@d7hN@+ER5Ba5K2~&a9N>>ed`w z5AcSW3)NzEufA_FX7La)X4{|^db6RI{eF5Z( z2K^tDN{Pe+WP7e?@(B3PY(727q~WK28@@rdYqa>j&5s>FZ}T}0)#GvT2cF1(Zu4X3 zKlnuckj;<%{DpvD(fz-fCVoRB^?g^V+m9i-p8>H#Jq^&AH-3Z6(`faV^>_7*3evng z(n$R|0GzKO%DS;L`gD);OUE~uIRnxKfDv@9{RUaLg{`+Jm`{%1nr~I1{_HEIQS0Jc zh-}a8Tlp8;>#HhS-|%(*ns1Qp9q~tOe(d-!dfXq@?^k~~e$XGTBiEIY?H%=fY1fzU zV;&>hJNTnLt}pBNtG*mR>HL>^Tp!l&SA95s()x@goxcZm1==cV9k{d)WQWb> z;OkQ~`0=h_`Miymx2vyk678F4M*F4~qkXUKt;5RY?Vo7g`&ZGv+F`V>@iX*wJK--I owAR#>(wI3@>gqg1w$m4;{R?58KneKP8^WOX3dkYT6BKQ_-c?LrUz&M8DXLyV+%oc%e z+noyc$L8#&q8HN;iJEI7LSzCykBOrgFaWMem zud(MZ;B+8~4-7wQ?(kzHcQG(_g>inm7Jo8pH}dQ8lJaT3uLVC=&N-i^tW!X$(`dkZ zEvh{2yTwaF`J`nQR3Wy?y2{^gr7rvzE!+N1%P_HODWMP#fkgd09T+rrg=zwR(bnU< zw6v^y#ydGhRNcu%Kwm+3hq@W_^c95IebJsa};4b@$75uF}$W(`@)US9or`DdiHe8r0uMD zLfmc&Q6cBtIIvzdXzUUj_+}z#yQOMEM8vJ>WLfu0FNMZVn6#Y>^6&6{eAN-WzZewa kwJh_iqt3f2KePQRKiQof;z@if!#WN0v0`U$ObpQYW literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_au15b.gds b/testdata/algo/deep_region_au15b.gds new file mode 100644 index 0000000000000000000000000000000000000000..da172280c352ae0f84267f4a9fe72c4b673a4086 GIT binary patch literal 1664 zcmd5+zb`{k6#m|A-|f?u)Q^QWX$ONrh^0tG+OnW2L8MF_Ee4~1K-k12EH=gt1_mQD zgTyE-Mw5-}+&5WpjK zm*$sJPLXPHAl}6ukbMp*pUk+WGeZ3&wF;y#HfmPoZ?;NR$%X&LOFyj7=VAUpf1TxuzQrpiqli-Zk zE$B{iku> z3!7nHioNTf;_wPVH;YZ$VDFCY9Cqj3c}iWaD|JW7*)d@Co{{4koA~UDvc5B0^UYrI z_ROf%OHJ2rpzYhT{vhvoi+Fn1uQfP_0}bRjVc4B&_*%s(&E~7=I5$RBgB&Mh2Sua! E0ND;?Bme*a literal 0 HcmV?d00001