diff --git a/src/db/db/dbCellVariants.h b/src/db/db/dbCellVariants.h index 11f2fde8d..8e6210ceb 100644 --- a/src/db/db/dbCellVariants.h +++ b/src/db/db/dbCellVariants.h @@ -28,6 +28,7 @@ #include "dbLayout.h" #include "dbTrans.h" #include "tlTypeTraits.h" +#include "tlUtils.h" namespace db { @@ -354,6 +355,123 @@ public: } } + /** + * @brief Commits the shapes for different variants to the current cell hierarchy + * + * This is an alternative approach and will push the variant shapes into the parent hierarchy. + * "to_commit" initially is a set of shapes to commit for the given cell and variant. + * This map is modified during the algorithm and should be discarded later. + */ + virtual void commit_shapes (db::Layout &layout, db::Cell &top_cell, unsigned int layer, std::map > &to_commit) + { + if (to_commit.empty ()) { + return; + } + + // NOTE: this implementation suffers from accumulation of propagated shapes: we add more levels of propagated + // shapes if required. We don't clean up, because we do not know when a shape collection stops being required. + + db::LayoutLocker locker (&layout); + + std::set called; + top_cell.collect_called_cells (called); + called.insert (top_cell.cell_index ()); + + for (db::Layout::bottom_up_const_iterator c = layout.begin_bottom_up (); c != layout.end_bottom_up (); ++c) { + + if (called.find (*c) == called.end ()) { + continue; + } + + db::Cell &cell = layout.cell (*c); + + std::map &vvc = m_variants [*c]; + if (vvc.size () > 1) { + + for (std::map::const_iterator vc = vvc.begin (); vc != vvc.end (); ++vc) { + + for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) { + + std::map >::const_iterator tc = to_commit.find (i->cell_index ()); + if (tc != to_commit.end ()) { + + const std::map &vt = tc->second; + + // NOTE: this will add one more commit slot for propagation ... but we don't clean up. + // When would a cleanup happen? + std::map &propagated = to_commit [*c]; + + for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { + + db::ICplxTrans t = i->complex_trans (*ia); + db::ICplxTrans rt = m_red (vc->first * t); + std::map::const_iterator v = vt.find (rt); + if (v != vt.end ()) { + + db::Shapes &ps = propagated [vc->first]; + tl::ident_map pm; + + for (db::Shapes::shape_iterator si = v->second.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + ps.insert (*si, t, pm); + } + + } + + } + + } + + } + + } + + } else { + + // single variant -> we can commit any shapes we have kept for this cell directly to the cell + + std::map >::iterator l = to_commit.find (*c); + if (l != to_commit.end ()) { + tl_assert (l->second.size () == 1); + cell.shapes (layer).insert (l->second.begin ()->second); + to_commit.erase (l); + } + + // for child cells, pull everything that needs to be committed to the parent + + for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) { + + std::map >::const_iterator tc = to_commit.find (i->cell_index ()); + if (tc != to_commit.end ()) { + + const std::map &vt = tc->second; + + for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { + + db::ICplxTrans t = i->complex_trans (*ia); + db::ICplxTrans rt = m_red (vvc.begin ()->first * t); + std::map::const_iterator v = vt.find (rt); + + if (v != vt.end ()) { + + tl::ident_map pm; + + for (db::Shapes::shape_iterator si = v->second.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + cell.shapes (layer).insert (*si, t, pm); + } + + } + + } + + } + + } + + } + + } + } + /** * @brief Gets the variants for a given cell * @@ -371,6 +489,19 @@ public: } } + /** + * @brief Returns true, if variants have been built + */ + bool has_variants () const + { + for (std::map >::const_iterator i = m_variants.begin (); i != m_variants.end (); ++i) { + if (i->second.size () > 1) { + return true; + } + } + return false; + } + private: std::map > m_variants; Reduce m_red; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 3fe83e3c6..7ad2960b7 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -713,11 +713,82 @@ DeepRegion::to_string (size_t nmax) const return db::AsIfFlatRegion::to_string (nmax); } +static void produce_offgrid_markers (db::Shapes &markers, const db::Shapes &shapes, const db::ICplxTrans &tr, db::Coord g) +{ + for (db::Shapes::shape_iterator si = shapes.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + + db::Polygon poly; + si->polygon (poly); + + for (size_t i = 0; i < poly.holes () + 1; ++i) { + + 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 p = b; p != e; ++p) { + db::Point pt = tr * *p; + if ((pt.x () % g) != 0 || (pt.y () % g) != 0) { + markers.insert (EdgePair (db::Edge (pt, pt), db::Edge (pt, pt))); + } + } + + } + + } + +} + EdgePairs DeepRegion::grid_check (db::Coord gx, db::Coord gy) const { - // TODO: snap be optimized by forming grid variants etc. - return db::AsIfFlatRegion::grid_check (gx, gy); + if (gx <= 0 || gy <= 0) { + throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value"))); + } + + if (gx != gy) { + // no way doing this hierarchically ? + return db::AsIfFlatRegion::grid_check (gx, gy); + } + + ensure_merged_polygons_valid (); + + db::Layout &layout = m_merged_polygons.layout (); + + db::cell_variants_collector vars (gx); + vars.collect (layout, m_merged_polygons.initial_cell ()); + + std::map > to_commit; + std::auto_ptr res (new db::DeepEdgePairs (m_merged_polygons.derived ())); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const std::map &vv = vars.variants (c->cell_index ()); + for (std::map::const_iterator v = vv.begin (); v != vv.end (); ++v) { + + db::Shapes *markers; + if (vv.size () == 1) { + markers = & c->shapes (res->deep_layer ().layer ()); + } else { + markers = & to_commit [c->cell_index ()] [v->first]; + } + + produce_offgrid_markers (*markers, c->shapes (m_merged_polygons.layer ()), v->first, gx); + + } + + } + + // propagate the markers with a similar algorithm used for producing the variants + res->deep_layer ().commit_shapes (vars, to_commit); + + return db::EdgePairs (res.release ()); } EdgePairs diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 96dc17af3..b76d44510 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -159,6 +159,19 @@ public: template void separate_variants (VarCollector &collector); + /** + * @brief Commits shapes for variants to the existing cell hierarchy + * + * The "to_propagate" collection is a set of shapes per cell and variant. The + * algorithm will put these shapes into the existing hierarchy putting the + * shapes into the proper parent cells to resolve variants. + * + * This map will be modified by the algorithm and should be discarded + * later. + */ + template + void commit_shapes (VarCollector &collector, std::map > &to_propagate); + /** * @brief Gets the shape store object * This is a pure const version to prevent manipulation of the store. @@ -299,6 +312,21 @@ public: issue_variants (layout_index, var_map); } + /** + * @brief Commits shapes for variants to the existing cell hierarchy + * + * To use this method, first create a variant collector (db::cell_variant_collector) with the required + * reducer and collect the variants. Then call this method on the desired layout index to commit the shapes for the + * respective variants. + */ + template + void commit_shapes (unsigned int layout_index, VarCollector &coll, unsigned int layer, std::map > &to_commit) + { + tl_assert (is_valid_layout_index (layout_index)); + + coll.commit_shapes (layout (layout_index), initial_cell (layout_index), layer, to_commit); + } + /** * @brief For testing */ @@ -538,6 +566,13 @@ void DeepLayer::separate_variants (VarCollector &collector) mp_store->separate_variants (m_layout, collector); } +template +void DeepLayer::commit_shapes (VarCollector &collector, std::map > &to_commit) +{ + check_dss (); + mp_store->commit_shapes (m_layout, collector, layer (), to_commit); +} + } namespace tl diff --git a/src/db/unit_tests/dbCellVariantsTests.cc b/src/db/unit_tests/dbCellVariantsTests.cc index 8b207a252..f43cd7f1e 100644 --- a/src/db/unit_tests/dbCellVariantsTests.cc +++ b/src/db/unit_tests/dbCellVariantsTests.cc @@ -392,3 +392,47 @@ TEST(100_OrientationVariantsWithLayout) CHECKPOINT(); db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/cell_variants_au1.gds"); } + +TEST(101_Propagation) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/cell_variants_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + std::map > to_commit; + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.insert_layer (db::LayerProperties (2, 0)); + + db::cell_variants_collector vb; + vb.collect (ly, top_cell); + + for (db::Layout::const_iterator c = ly.begin (); c != ly.end (); ++c) { + + const std::map &vv = vb.variants (c->cell_index ()); + for (std::map::const_iterator v = vv.begin (); v != vv.end (); ++v) { + + db::Shapes &out = to_commit [c->cell_index ()][v->first]; + for (db::Shapes::shape_iterator s = c->shapes (l1).begin (db::ShapeIterator::All); ! s.at_end (); ++s) { + db::Box b = s->bbox ().transformed (v->first); + b.enlarge (db::Vector (-100, 0)); + out.insert (b.transformed (v->first.inverted ())); + } + + } + + } + + vb.commit_shapes (ly, top_cell, l2, to_commit); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/cell_variants_au2.gds"); +} diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 7597be1b2..16bb37458 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -969,7 +969,7 @@ TEST(17_SinglePolygonChecks) } } -TEST(18_Checks) +TEST(18_MultiPolygonChecks) { db::Layout ly; { @@ -1013,6 +1013,41 @@ TEST(18_Checks) } } +TEST(19_GridCheck) +{ + 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 r3_gc1; + r3.grid_check (25, 25).polygons (r3_gc1, 100); + db::Region r3_gc2; + r3.grid_check (40, 40).polygons (r3_gc2, 100); + + 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)), r3_gc1); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r3_gc2); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au19.gds"); +} + TEST(100_Integration) { db::Layout ly; diff --git a/testdata/algo/cell_variants_au2.gds b/testdata/algo/cell_variants_au2.gds new file mode 100644 index 000000000..c30651bb0 Binary files /dev/null and b/testdata/algo/cell_variants_au2.gds differ diff --git a/testdata/algo/cell_variants_l1.gds b/testdata/algo/cell_variants_l1.gds new file mode 100644 index 000000000..56c817fbc Binary files /dev/null and b/testdata/algo/cell_variants_l1.gds differ diff --git a/testdata/algo/deep_region_au14b.gds b/testdata/algo/deep_region_au14b.gds new file mode 100644 index 000000000..85b83f54e Binary files /dev/null and b/testdata/algo/deep_region_au14b.gds differ diff --git a/testdata/algo/deep_region_au17.gds b/testdata/algo/deep_region_au17.gds new file mode 100644 index 000000000..df3ab0872 Binary files /dev/null and b/testdata/algo/deep_region_au17.gds differ diff --git a/testdata/algo/deep_region_au18.gds b/testdata/algo/deep_region_au18.gds new file mode 100644 index 000000000..35edb6a15 Binary files /dev/null and b/testdata/algo/deep_region_au18.gds differ diff --git a/testdata/algo/deep_region_au19.gds b/testdata/algo/deep_region_au19.gds new file mode 100644 index 000000000..0383ee510 Binary files /dev/null and b/testdata/algo/deep_region_au19.gds differ