diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 9955d9486..459a0088d 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -294,16 +294,31 @@ public: m_ep.set_base_verbosity (vb); } - db::Shapes &merged (size_t cid, db::cell_index_type ci, bool initial = true) + db::Shapes &merged (size_t cid, db::cell_index_type ci, unsigned int min_wc = 0) + { + return compute_merged (cid, ci, true, min_wc); + } + + void erase (size_t cid, db::cell_index_type ci) + { + m_merged_cluster.erase (std::make_pair (cid, ci)); + } + +private: + std::map, db::Shapes> m_merged_cluster; + unsigned int m_layer; + db::Layout *mp_layout; + const db::hier_clusters *mp_hc; + bool m_min_coherence; + db::EdgeProcessor m_ep; + + db::Shapes &compute_merged (size_t cid, db::cell_index_type ci, bool initial, unsigned int min_wc) { std::map, db::Shapes>::iterator s = m_merged_cluster.find (std::make_pair (cid, ci)); // some sanity checks: initial clusters are single-use, are never generated twice and cannot be retrieved again if (initial) { tl_assert (s == m_merged_cluster.end ()); - m_done.insert (std::make_pair (cid, ci)); - } else { - tl_assert (m_done.find (std::make_pair (cid, ci)) == m_done.end ()); } if (s != m_merged_cluster.end ()) { @@ -315,51 +330,60 @@ public: const db::connected_clusters &cc = mp_hc->clusters_per_cell (ci); const db::local_cluster &c = cc.cluster_by_id (cid); - std::list > merged_child_clusters; + if (min_wc > 0) { - const db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); - for (db::connected_clusters::connections_type::const_iterator i = conn.begin (); i != conn.end (); ++i) { - const db::Shapes &cc_shapes = merged (i->id (), i->inst ().inst_ptr.cell_index (), false); - merged_child_clusters.push_back (std::make_pair (&cc_shapes, i->inst ().complex_trans ())); - } + // We cannot merge bottom-up in min_wc mode, so we just use the recursive cluster iterator - m_ep.clear (); + m_ep.clear (); - size_t pi = 0; + size_t pi = 0; - for (std::list >::const_iterator i = merged_child_clusters.begin (); i != merged_child_clusters.end (); ++i) { - for (db::Shapes::shape_iterator s = i->first->begin (db::ShapeIterator::All); ! s.at_end (); ++s) { - if (s->is_polygon ()) { - db::Polygon poly; - s->polygon (poly); - m_ep.insert (poly.transformed (i->second), pi++); + for (db::recursive_cluster_shape_iterator s = db::recursive_cluster_shape_iterator (*mp_hc, m_layer, ci, cid); !s.at_end (); ++s) { + db::Polygon poly = s->obj (); + poly.transform (s.trans () * db::ICplxTrans (s->trans ())); + m_ep.insert (poly, pi++); + } + + } else { + + std::list > merged_child_clusters; + + const db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); + for (db::connected_clusters::connections_type::const_iterator i = conn.begin (); i != conn.end (); ++i) { + const db::Shapes &cc_shapes = compute_merged (i->id (), i->inst ().inst_ptr.cell_index (), false, min_wc); + merged_child_clusters.push_back (std::make_pair (&cc_shapes, i->inst ().complex_trans ())); + } + + m_ep.clear (); + + size_t pi = 0; + + for (std::list >::const_iterator i = merged_child_clusters.begin (); i != merged_child_clusters.end (); ++i) { + for (db::Shapes::shape_iterator s = i->first->begin (db::ShapeIterator::All); ! s.at_end (); ++s) { + if (s->is_polygon ()) { + db::Polygon poly; + s->polygon (poly); + m_ep.insert (poly.transformed (i->second), pi++); + } } } - } - for (db::local_cluster::shape_iterator s = c.begin (m_layer); !s.at_end (); ++s) { - db::Polygon poly = s->obj (); - poly.transform (s->trans ()); - m_ep.insert (poly, pi++); + for (db::local_cluster::shape_iterator s = c.begin (m_layer); !s.at_end (); ++s) { + db::Polygon poly = s->obj (); + poly.transform (s->trans ()); + m_ep.insert (poly, pi++); + } + } // and run the merge step - db::MergeOp op (0); + db::MergeOp op (min_wc); db::PolygonRefToShapesGenerator pr (mp_layout, &s->second); db::PolygonGenerator pg (pr, false /*don't resolve holes*/, m_min_coherence); m_ep.process (pg, op); return s->second; } - -private: - std::map, db::Shapes> m_merged_cluster; - std::set > m_done; - unsigned int m_layer; - db::Layout *mp_layout; - const db::hier_clusters *mp_hc; - bool m_min_coherence; - db::EdgeProcessor m_ep; }; } @@ -402,7 +426,7 @@ DeepRegion::ensure_merged_polygons_valid () const if (cc.is_root (*cl)) { db::Shapes &s = cm.merged (*cl, c->cell_index ()); c->shapes (m_merged_polygons.layer ()).insert (s); - s.clear (); // not needed anymore + cm.erase (*cl, c->cell_index ()); // not needed anymore } } } @@ -873,8 +897,7 @@ DeepRegion::merged_in_place () RegionDelegate * DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc) { - // TODO: can probably be optimized - return db::AsIfFlatRegion::merged_in_place (min_coherence, min_wc); + return merged (min_coherence, min_wc); } RegionDelegate * @@ -898,8 +921,39 @@ DeepRegion::merged () const RegionDelegate * DeepRegion::merged (bool min_coherence, unsigned int min_wc) const { - // TODO: can probably be optimized - return db::AsIfFlatRegion::merged (min_coherence, min_wc); + tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); + + db::Layout &layout = const_cast (m_deep_layer.layout ()); + + db::hier_clusters hc; + db::Connectivity conn; + conn.connect (m_deep_layer); + // TODO: this uses the wrong verbosity inside ... + hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn); + + // collect the clusters and merge them into big polygons + // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is + // hopefully more efficient that collecting everything and will lead to reuse of parts. + + DeepLayer dl_out (m_deep_layer.derived ()); + + ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence, report_progress (), progress_desc ()); + cm.set_base_verbosity (base_verbosity ()); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + const db::connected_clusters &cc = hc.clusters_per_cell (c->cell_index ()); + for (db::connected_clusters::all_iterator cl = cc.begin_all (); ! cl.at_end (); ++cl) { + if (cc.is_root (*cl)) { + db::Shapes &s = cm.merged (*cl, c->cell_index (), min_wc); + c->shapes (dl_out.layer ()).insert (s); + cm.erase (*cl, c->cell_index ()); // not needed anymore + } + } + } + + db::DeepRegion *res = new db::DeepRegion (dl_out); + res->set_is_merged (true); + return res; } RegionDelegate * diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index fb976cd9d..01b5392d9 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -60,7 +60,7 @@ Region::~Region () Region &Region::operator= (const Region &other) { if (this != &other) { - set_delegate (other.mp_delegate->clone ()); + set_delegate (other.mp_delegate->clone (), false); } return *this; } @@ -94,9 +94,13 @@ Region::iter () const } void -Region::set_delegate (RegionDelegate *delegate) +Region::set_delegate (RegionDelegate *delegate, bool keep_attributes) { if (delegate != mp_delegate) { + if (keep_attributes && delegate && mp_delegate) { + // copy the basic attributes like #threads etc. + delegate->RegionDelegate::operator= (*mp_delegate); + } delete mp_delegate; mp_delegate = delegate; } @@ -159,7 +163,6 @@ Region::flat_region () if (! region) { region = new FlatRegion (); if (mp_delegate) { - region->RegionDelegate::operator= (*mp_delegate); region->insert_seq (begin ()); } if (mp_delegate) { diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 77da2d894..4ac0cda62 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1786,7 +1786,7 @@ private: RegionDelegate *mp_delegate; - void set_delegate (RegionDelegate *delegate); + void set_delegate (RegionDelegate *delegate, bool keep_attributes = true); FlatRegion *flat_region (); }; diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 2126434eb..bd72575fb 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -868,6 +868,46 @@ TEST(15_Filtered) } } +TEST(16_MergeWithMinWC) +{ + 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::Region r1_merged_wc0 = r1.merged (true, 0); + db::Region r1_merged_wc1 = r1.merged (true, 1); + db::Region r1_merged_wc2 = r1.merged (true, 2); + EXPECT_EQ (r1_merged_wc0.is_merged (), true); + EXPECT_EQ (r1_merged_wc1.is_merged (), true); + EXPECT_EQ (r1_merged_wc2.is_merged (), true); + + + { + 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_merged_wc0); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1_merged_wc1); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r1_merged_wc2); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au16.gds"); + } +} + TEST(100_Integration) { db::Layout ly; diff --git a/testdata/algo/deep_region_au16.gds b/testdata/algo/deep_region_au16.gds new file mode 100644 index 000000000..eea9b6161 Binary files /dev/null and b/testdata/algo/deep_region_au16.gds differ diff --git a/testdata/algo/deep_region_au7.gds b/testdata/algo/deep_region_au7.gds index 2c7a8f312..4d0741a36 100644 Binary files a/testdata/algo/deep_region_au7.gds and b/testdata/algo/deep_region_au7.gds differ