From 51676376e6de911dd7ea7df035fad14f5d8c9567 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 5 Nov 2019 00:46:12 +0100 Subject: [PATCH 1/8] WIP: Variant building bug fixed. Needs testing. --- src/db/db/dbCellMapping.cc | 28 +++++++++++++++-- src/db/db/dbCellMapping.h | 10 +++++++ src/db/db/dbCellVariants.cc | 2 +- src/db/db/dbCellVariants.h | 6 +++- src/db/db/dbDeepShapeStore.cc | 53 +++++++++++++++++++++++++++++---- src/db/db/dbHierarchyBuilder.cc | 35 ++++++++++++++++++++++ src/db/db/dbHierarchyBuilder.h | 28 +++++++++++++++++ 7 files changed, 152 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbCellMapping.cc b/src/db/db/dbCellMapping.cc index 0b10257b4..d84a72dde 100644 --- a/src/db/db/dbCellMapping.cc +++ b/src/db/db/dbCellMapping.cc @@ -295,9 +295,26 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type } std::vector -CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) +CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) { std::vector new_cells; + do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, &new_cells, 0); + return new_cells; +} + +std::vector > +CellMapping::create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) +{ + std::vector > cell_pairs; + do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, 0, &cell_pairs); + return cell_pairs; +} + +void +CellMapping::do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells, std::vector *new_cells_ptr, std::vector > *mapped_pairs) +{ + std::vector new_cells_int; + std::vector &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int); std::vector new_cells_b; std::set called_b; @@ -308,10 +325,17 @@ CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type / if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () && (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ()) && (! include_cells || include_cells->find (*b) != include_cells->end ())) { + db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b)); new_cells.push_back (new_cell); new_cells_b.push_back (*b); + + if (mapped_pairs) { + mapped_pairs->push_back (std::make_pair (*b, new_cell)); + } + map (*b, new_cell); + } } @@ -355,8 +379,6 @@ CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type / layout_a.end_changes (); } - - return new_cells; } void diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index 858028659..1d2f49146 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -197,6 +197,14 @@ public: */ std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); + /** + * @brief Like create_missing_mapping, but returns the newly mapped pairs + * + * The first cell index of the pair is the old cell in layout_a, the second cell index + * is the new cell in layout_b. + */ + std::vector > create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); + private: void extract_unique (std::map >::const_iterator cand, std::map &unique_mapping, @@ -205,6 +213,8 @@ private: void dump_mapping (const std::map > &candidates, const db::Layout &layout_a, const db::Layout &layout_b); + void do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells, std::vector *new_cells, std::vector > *mapped_pairs); + std::map m_b2a_mapping; }; diff --git a/src/db/db/dbCellVariants.cc b/src/db/db/dbCellVariants.cc index 1ff5c9f76..adb5b6e97 100644 --- a/src/db/db/dbCellVariants.cc +++ b/src/db/db/dbCellVariants.cc @@ -355,7 +355,7 @@ VariantsCollectorBase::product (const std::map &v1, cons } void -VariantsCollectorBase::copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from) const +VariantsCollectorBase::copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from) { db::Cell &to = layout.cell (ci_to); const db::Cell &from = layout.cell (ci_from); diff --git a/src/db/db/dbCellVariants.h b/src/db/db/dbCellVariants.h index f8333c6c3..f8aa9f588 100644 --- a/src/db/db/dbCellVariants.h +++ b/src/db/db/dbCellVariants.h @@ -225,6 +225,11 @@ public: */ bool has_variants () const; + /** + * @brief Utility: copy all shapes from one cell to another + */ + static void copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from); + private: std::map > m_variants; const TransformationReducer *mp_red; @@ -233,7 +238,6 @@ private: void add_variant_non_tl_invariant (std::map &variants, const db::CellInstArray &inst) const; void add_variant_tl_invariant (std::map &variants, const db::CellInstArray &inst) const; void product (const std::map &v1, const std::map &v2, std::map &prod) const; - void copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from) const; void create_var_instances (db::Cell &in_cell, std::vector &inst, const db::ICplxTrans &for_var, const std::map > &var_table, bool tl_invariant) const; void create_var_instances_non_tl_invariant (db::Cell &in_cell, std::vector &inst, const db::ICplxTrans &for_var, const std::map > &var_table) const; void create_var_instances_tl_invariant (db::Cell &in_cell, std::vector &inst, const db::ICplxTrans &for_var, const std::map > &var_table) const; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 726ba86eb..44c7f8ea0 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -889,7 +889,7 @@ DeepShapeStore::issue_variants (unsigned int layout_index, const std::map *excluded_cells, const std::set *included_cells) { - const db::Layout *source_layout = &m_layouts [layout_index]->layout; + db::Layout *source_layout = &m_layouts [layout_index]->layout; if (source_layout->begin_top_down () == source_layout->end_top_cells ()) { // empty source - nothing to do. static db::CellMapping cm; @@ -910,6 +910,9 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first; + // collects the cell mappings we skip because they are variants (variant building or box variants) + std::map > > cm_skipped_variants; + if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) { // This is the case of mapping back to the original. In this case we can use the information @@ -922,15 +925,19 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout HierarchyBuilder::cell_map_type::const_iterator mm = m; ++mm; bool skip = original_builder.is_variant (m->second); // skip variant cells - while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first && ! skip) { - // we have cell variants and cannot simply map + while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) { + // we have cell (box) variants and cannot simply map ++mm; - ++m; skip = true; } if (! skip) { cm->second.map (m->second, m->first.first); + } else { + for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) { + tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ()); + cm_skipped_variants [n->second] = n->first; + } } } @@ -948,7 +955,43 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout // Add new cells for the variants and (possible) devices which are cells added during the device // extraction process - cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells); + std::vector > new_pairs = cm->second.create_missing_mapping2 (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells); + + // the variant's originals we are going to delete + std::set cells_to_delete; + + // We now need to fix the cell map from the hierarchy builder, so we can import back from the modified layout. + // This is in particular important if we created new cells for known variants. + for (std::vector >::const_iterator np = new_pairs.begin (); np != new_pairs.end (); ++np) { + + db::cell_index_type var_org = original_builder.original_target_for_variant (np->first); + + std::map > >::const_iterator icm = cm_skipped_variants.find (var_org); + if (icm != cm_skipped_variants.end ()) { + + // create the variant clone in the original layout too and delete this cell + VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.first); + cells_to_delete.insert (icm->second.first); + + // forget the original cell (now separated into variants) and map the variants back into the + // DSS layout + original_builder.unmap (icm->second); + original_builder.map (std::make_pair (np->second, icm->second.second), np->first); + + // forget the variant as now it's a real cell in the source layout + original_builder.unregister_variant (np->first); + + // rename the cell because it may be a different one now + source_layout->rename_cell (np->first, into_layout->cell_name (np->second)); + + } + + } + + // delete the variant's original cell + if (! cells_to_delete.empty ()) { + into_layout->delete_cells (cells_to_delete); + } } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index c43685c4b..63646a5ad 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -185,6 +185,40 @@ HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_ m_variants_to_original_target_map.insert (std::make_pair (var, non_var)); } +void +HierarchyBuilder::unregister_variant (db::cell_index_type var) +{ + variant_to_original_target_map_type::const_iterator v = m_variants_to_original_target_map.find (var); + if (v == m_variants_to_original_target_map.end ()) { + return; + } + + original_target_to_variants_map_type::iterator rv = m_original_targets_to_variants_map.find (v->second); + tl_assert (rv != m_original_targets_to_variants_map.end ()); + + std::vector &vv = rv->second; + std::vector::iterator ri = std::find (vv.begin (), vv.end (), var); + tl_assert (ri != vv.end ()); + vv.erase (ri); + + if (vv.empty ()) { + m_original_targets_to_variants_map.erase (rv); + } + + m_variants_to_original_target_map.erase (v); +} + +db::cell_index_type +HierarchyBuilder::original_target_for_variant (db::cell_index_type ci) const +{ + variant_to_original_target_map_type::const_iterator v = m_variants_to_original_target_map.find (ci); + if (v != m_variants_to_original_target_map.end ()) { + return v->second; + } else { + return ci; + } +} + void HierarchyBuilder::begin (const RecursiveShapeIterator *iter) { @@ -269,6 +303,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn if (all) { std::pair > key (inst.object ().cell_index (), std::set ()); + m_cm_entry = m_cell_map.find (key); m_cm_new_entry = false; diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index a42e251bc..2286a7b12 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -284,6 +284,24 @@ public: return m_cell_map.end (); } + /** + * @brief Unmaps an original cell/clip box version from the original-to-working copy cell map + * + * An unmapped cell is never again considered. + */ + void unmap (const cell_map_type::key_type &k) + { + m_cell_map.erase (k); + } + + /** + * @brief Maps an original cell/clip box version to a original-to-working copy cell + */ + void map (const cell_map_type::key_type &k, db::cell_index_type ci) + { + m_cell_map [k] = ci; + } + /** * @brief Marks a cell as a variant of another * @@ -292,6 +310,11 @@ public: */ void register_variant (db::cell_index_type non_var, db::cell_index_type var); + /** + * @brief Unregisters a cell as a variant + */ + void unregister_variant (db::cell_index_type var); + /** * @brief Gets a value indicating whether the given cell is a variant cell */ @@ -300,6 +323,11 @@ public: return m_variants_to_original_target_map.find (ci) != m_variants_to_original_target_map.end (); } + /** + * @brief Gets the original target for a variant cell + */ + db::cell_index_type original_target_for_variant (db::cell_index_type ci) const; + private: tl::weak_ptr mp_target; HierarchyBuilderShapeReceiver *mp_pipe; From 895206dfa1ee80a91c5c7a2530b0c01081f4fdd6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 5 Nov 2019 01:10:29 +0100 Subject: [PATCH 2/8] WIP: bugfix in case of clip variants. --- src/db/db/dbDeepShapeStore.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 44c7f8ea0..6a1539e95 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -920,7 +920,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout // create from them. We need to consider however, that the hierarchy builder is allowed to create // variants which we cannot map. - for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ++m) { + for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ) { HierarchyBuilder::cell_map_type::const_iterator mm = m; ++mm; @@ -940,6 +940,8 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout } } + m = mm; + } } else if (into_layout->cells () == 1) { From 1e2a8b264d78a15e903f842daf315dc195932155 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 6 Nov 2019 00:56:33 +0100 Subject: [PATCH 3/8] WIP: because the fixed scheme works nicely, add a new scale_and_snap function. --- src/db/db/dbAsIfFlatRegion.cc | 72 +++++++++-------------- src/db/db/dbAsIfFlatRegion.h | 8 ++- src/db/db/dbCellVariants.h | 55 ++++++++++++++++++ src/db/db/dbEmptyRegion.h | 4 +- src/db/db/dbLayoutUtils.cc | 105 ++++++++++++++++++++++++++++++++++ src/db/db/dbLayoutUtils.h | 8 +++ src/db/db/dbRegion.cc | 12 ++++ src/db/db/dbRegion.h | 13 +++++ src/db/db/dbRegionDelegate.h | 2 + src/db/db/dbRegionUtils.cc | 87 ++++++++++++++++++++++++++++ src/db/db/dbRegionUtils.h | 31 ++++++++++ src/db/db/gsiDeclDbLayout.cc | 30 ++++++++++ src/db/db/gsiDeclDbRegion.cc | 20 ++++++- 13 files changed, 398 insertions(+), 49 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 0b8682b67..8e49a58b2 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -632,56 +632,11 @@ AsIfFlatRegion::angle_check (double min, double max, bool inverse) const return res.release (); } -static inline db::Coord snap_to_grid (db::Coord c, db::Coord g) -{ - // This form of snapping always snaps g/2 to right/top. - if (c < 0) { - c = -g * ((-c + (g - 1) / 2) / g); - } else { - c = g * ((c + g / 2) / 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) { if (gx < 0 || gy < 0) { - throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value"))); + throw tl::Exception (tl::to_string (tr ("Grid snap requires a positive grid value"))); } std::auto_ptr new_region (new FlatRegion (merged_semantics ())); @@ -698,6 +653,31 @@ AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) return new_region.release (); } +RegionDelegate * +AsIfFlatRegion::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) +{ + if (gx < 0 || gy < 0) { + throw tl::Exception (tl::to_string (tr ("Grid snap requires a positive grid value"))); + } + + if (mx <= 0 || dx <= 0 || my <= 0 || dy <= 0) { + throw tl::Exception (tl::to_string (tr ("Scale and snap requires positive and non-null magnification or divisor values"))); + } + + std::auto_ptr new_region (new FlatRegion (merged_semantics ())); + + gx = std::max (db::Coord (1), gx); + gy = std::max (db::Coord (1), gy); + + std::vector heap; + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + new_region->raw_polygons ().insert (scaled_and_snapped_polygon (*p, gx, mx, dx, 0, gy, my, dy, 0, heap)); + } + + return new_region.release (); +} + EdgePairsDelegate * AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *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/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index 712ebb851..07ccc9a7a 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -105,6 +105,13 @@ public: virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy); + virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) + { + return scaled_and_snapped (gx, mx, dx, gy, my, dy); + } + + virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy); + virtual EdgesDelegate *edges (const EdgeFilterBase *) const; virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) @@ -247,7 +254,6 @@ protected: static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes); template static void produce_markers_for_angle_check (const db::Polygon &poly, const Trans &tr, double min, double max, bool inverse, 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 f8aa9f588..34775bc4a 100644 --- a/src/db/db/dbCellVariants.h +++ b/src/db/db/dbCellVariants.h @@ -168,6 +168,61 @@ private: } }; +/** + * @brief A scale+grid reducer + * + * This reducer incarnation reduces the transformation to it's displacement modulo a grid + * after a specified scaling has been applied. + * The scaling is given by a divider and multiplier and is mult / div. + */ +struct DB_PUBLIC ScaleAndGridReducer + : public TransformationReducer +{ + ScaleAndGridReducer (db::Coord grid, db::Coord mult, db::Coord div) + : m_mult (mult), m_grid (int64_t (grid) * int64_t (div)) + { + // .. nothing yet .. + } + + db::ICplxTrans reduce (const db::ICplxTrans &trans) const + { + // NOTE: we need to keep magnification, angle and mirror so when combining the + // reduced transformations, the result will be equivalent to reducing the combined + // transformation. + db::ICplxTrans res (trans); + res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ()))); + return res; + } + + db::Trans reduce (const db::Trans &trans) const + { + db::Trans res (trans); + res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ()))); + return res; + } + + bool is_translation_invariant () const { return false; } + +private: + int64_t m_mult; + int64_t m_grid; + + inline db::Coord mod (db::Coord c) const + { + int64_t cc = int64_t (c) * m_mult; + if (cc < 0) { + cc = m_grid - (-cc) % m_grid; + if (cc == m_grid) { + return 0; + } else { + return db::Coord (cc); + } + } else { + return db::Coord (cc % m_grid); + } + } +}; + /** * @brief A class computing variants for cells according to a given criterion * diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 0ea403ebe..1e98b04ca 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -72,7 +72,9 @@ public: virtual EdgePairsDelegate *angle_check (double, double, bool) const; virtual RegionDelegate *snapped_in_place (db::Coord, db::Coord) { return this; } - virtual RegionDelegate *snapped (db::Coord, db::Coord) { return new EmptyRegion (); } + virtual RegionDelegate *snapped (db::Coord, db::Coord) { return new EmptyRegion (); } + virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return this; } + virtual RegionDelegate *scaled_and_snapped (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return new EmptyRegion (); } virtual EdgesDelegate *edges (const EdgeFilterBase *) const; virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; } diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index e0452ea43..0b8bc636c 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -22,6 +22,8 @@ #include "dbLayoutUtils.h" +#include "dbCellVariants.h" +#include "dbRegionUtils.h" #include "tlProgress.h" namespace db @@ -431,5 +433,108 @@ ContextCache::find_layout_context (db::cell_index_type from, db::cell_index_type return c->second; } +// ------------------------------------------------------------ +// Scale and snap a layout + +void +scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d) +{ + if (g < 0) { + throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value"))); + } + + if (m <= 0 || d <= 0) { + throw tl::Exception (tl::to_string (tr ("Scale and snap requires positive and non-null magnification or divisor values"))); + } + + if (! g && m == d) { + return; + } + + db::cell_variants_collector vars (db::ScaleAndGridReducer (g, m, d)); + + vars.collect (layout, cell); + vars.separate_variants (layout, cell); + + std::set called_cells; + cell.collect_called_cells (called_cells); + called_cells.insert (cell.cell_index ()); + + db::LayoutLocker layout_locker (&layout); + layout.update (); + + std::vector heap; + + unsigned int work_layer = layout.insert_layer (); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + if (called_cells.find (c->cell_index ()) == called_cells.end ()) { + continue; + } + + const std::map &v = vars.variants (c->cell_index ()); + tl_assert (v.size () == size_t (1)); + db::ICplxTrans tr = v.begin ()->first; + + // NOTE: tr_disp is already multiplied with mag, so it can be an integer + db::Vector tr_disp = tr.disp (); + + tr.disp (db::Vector ()); + db::ICplxTrans trinv = tr.inverted (); + + for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { + + db::Shapes &s = c->shapes ((*l).first); + db::Shapes &out = c->shapes (work_layer); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) { + + db::Polygon poly; + si->polygon (poly); + poly.transform (tr); + out.insert (scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap).transformed (trinv)); + + } + + s.swap (out); + out.clear (); + + } + + // Snap instance placements to grid and magnify + // NOTE: we can modify the instances because the ScaleAndGridReducer marked every cell with children + // as a variant cell (an effect of ScaleAndGridReducer::want_variants(cell) == true where cells have children). + // Variant cells are not copied blindly back to the original layout. + + std::list new_insts; + + for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) { + + const db::CellInstArray &ia = inst->cell_inst (); + for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) { + + db::Trans ti (*i); + ti.disp (scaled_and_snapped_vector (ti.disp (), g, m, d, g, m, d)); + + if (ia.is_complex ()) { + new_insts.push_back (db::CellInstArray (ia.object (), ia.complex_trans (ti))); + } else { + new_insts.push_back (db::CellInstArray (ia.object (), ti)); + } + + } + + } + + c->clear_insts (); + + for (std::list::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) { + c->insert (*i); + } + + } +} + } diff --git a/src/db/db/dbLayoutUtils.h b/src/db/db/dbLayoutUtils.h index 8e89f61d1..44e176ad6 100644 --- a/src/db/db/dbLayoutUtils.h +++ b/src/db/db/dbLayoutUtils.h @@ -223,6 +223,14 @@ private: const db::Layout *mp_layout; }; +/** + * @brief Scales and snaps the layout below the given cell + * + * This method will scale and snap all layers from the given cell and below to the + * specified grid. Scaling happens by the rational factor m / d. + */ +void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d); + } // namespace db #endif diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index 6a5ace5e7..749ddc704 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -389,6 +389,18 @@ Region::snapped (db::Coord gx, db::Coord gy) const return Region (mp_delegate->snapped (gx, gy)); } +void +Region::scale_and_snap (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) +{ + set_delegate (mp_delegate->scaled_and_snapped_in_place (gx, mx, dx, gy, my, dy)); +} + +Region +Region::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) const +{ + return Region (mp_delegate->scaled_and_snapped (gx, mx, dx, gy, my, dy)); +} + Region Region::strange_polygon_check () const { diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index b8f96c109..3ae069688 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -903,6 +903,19 @@ public: */ Region snapped (db::Coord gx, db::Coord gy) const; + /** + * @brief Scales and grid-snaps the region + * + * This method will scale the region by mx/dx in horizontal and by my/dy in vertical + * direction and then snape to gx and gy respectively. + */ + void scale_and_snap (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy); + + /** + * @brief Returns the scaled and snapped region + */ + Region scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) const; + /** * @brief Performs a check for "strange" polygons * diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 5bfea5e07..ffbc8d631 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -260,6 +260,8 @@ public: virtual RegionDelegate *snapped_in_place (db::Coord gx, db::Coord gy) = 0; virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy) = 0; + virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0; + virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0; virtual EdgesDelegate *edges (const EdgeFilterBase *filter) const = 0; virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0; diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index bfdda2990..98475d9a0 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -350,5 +350,92 @@ region_to_edge_interaction_filter_base::fill_output () template class region_to_edge_interaction_filter_base; template class region_to_edge_interaction_filter_base; +// ------------------------------------------------------------------------------------- +// Polygon snapping + +db::Polygon +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; } +db::Polygon +scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy, std::vector &heap) +{ + db::Polygon pnew; + + int64_t dgx = int64_t (gx) * int64_t (dx); + int64_t dgy = int64_t (gy) * int64_t (dy); + + 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) { + int64_t x = snap_to_grid (int64_t ((*pt).x ()) * mx + int64_t (ox), dgx) / int64_t (dx); + int64_t y = snap_to_grid (int64_t ((*pt).y ()) * my + int64_t (oy), dgy) / int64_t (dy); + heap.push_back (db::Point (db::Coord (x), db::Coord (y))); + } + + if (i == 0) { + pnew.assign_hull (heap.begin (), heap.end ()); + } else { + pnew.insert_hole (heap.begin (), heap.end ()); + } + + } + + return pnew; +} + +db::Vector +scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) +{ + int64_t dgx = int64_t (gx) * int64_t (dx); + int64_t dgy = int64_t (gy) * int64_t (dy); + + int64_t x = snap_to_grid (int64_t (v.x ()) * mx, dgx) / int64_t (dx); + int64_t y = snap_to_grid (int64_t (v.y ()) * my, dgy) / int64_t (dy); + + return db::Vector (db::Coord (x), db::Coord (y)); +} + +} diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 9e082f582..95fd8e5ea 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -524,6 +524,37 @@ private: OutputContainer *mp_output; }; +template +static inline C snap_to_grid (C c, C g) +{ + // This form of snapping always snaps g/2 to right/top. + if (c < 0) { + c = -g * ((-c + (g - 1) / 2) / g); + } else { + c = g * ((c + g / 2) / g); + } + return c; +} + +/** + * @brief Snaps a polygon to the given grid + * Heap is a vector of points reused for the point list + */ +DB_PUBLIC db::Polygon snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector &heap); + +/** + * @brief Scales and snaps a polygon to the given grid + * Heap is a vector of points reused for the point list + * The coordinate transformation is q = ((p * m + o) % (g * d)) / d. + */ +DB_PUBLIC db::Polygon scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy, std::vector &heap); + +/** + * @brief Scales and snaps a vector to the given grid + * The coordinate transformation is q = ((p * m) % (g * d)) / d. + */ +DB_PUBLIC db::Vector scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy); + } // namespace db #endif diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 4bbd4a941..2d6df3c87 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -33,6 +33,7 @@ #include "dbPCellDeclaration.h" #include "dbHash.h" #include "dbRegion.h" +#include "dbLayoutUtils.h" #include "tlStream.h" namespace gsi @@ -812,6 +813,16 @@ static const std::string &layout_meta_get_description (const db::MetaInfo *mi) return mi->description; } +static void scale_and_snap1 (db::Layout *layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d) +{ + scale_and_snap (*layout, cell, g, m, d); +} + +static void scale_and_snap2 (db::Layout *layout, db::cell_index_type ci, db::Coord g, db::Coord m, db::Coord d) +{ + scale_and_snap (*layout, layout->cell (ci), g, m, d); +} + Class decl_LayoutMetaInfo ("db", "LayoutMetaInfo", gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()), "@brief Creates a layout meta info object\n" @@ -1542,6 +1553,25 @@ Class decl_Layout ("db", "Layout", "an index in the range of 0 to layers-1 needs to be a valid layer. These layers can be either valid, " "special or unused. Use \\is_valid_layer? and \\is_special_layer? to test for the first two states.\n" ) + + gsi::method_ext ("scale_and_snap", &scale_and_snap1, gsi::arg ("cell"), gsi::arg ("grid"), gsi::arg ("mult"), gsi::arg ("div"), + "@brief Scales and snaps the layout below a given cell by the given rational factor and snaps to the given grid\n" + "\n" + "This method is useful to scale a layout by a non-integer factor. The " + "scale factor is given by the rational number mult / div. After scaling, the " + "layout will be snapped to the given grid.\n" + "\n" + "Snapping happens 'as-if-flat' - that is, touching edges will stay touching, regardless of their " + "hierarchy path. To achieve this, this method usually needs to produce cell variants.\n" + "\n" + "This method has been introduced in version 0.26.1.\n" + ) + + gsi::method_ext ("scale_and_snap", &scale_and_snap2, gsi::arg ("cell_index"), gsi::arg ("grid"), gsi::arg ("mult"), gsi::arg ("div"), + "@brief Scales and snaps the layout below a given cell by the given rational factor and snaps to the given grid\n" + "\n" + "Like the other version of \\scale_and_snap, but taking a cell index for the argument.\n" + "\n" + "This method has been introduced in version 0.26.1.\n" + ) + gsi::method ("transform", (void (db::Layout::*) (const db::Trans &t)) &db::Layout::transform, "@brief Transforms the layout with the given transformation\n" "@args trans\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 3fcc353da..9f0939bc8 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -949,10 +949,28 @@ Class decl_Region ("db", "Region", "This method will snap the region to the given grid - each x or y coordinate is brought on the gx or gy grid by rounding " "to the nearest value which is a multiple of gx or gy.\n" "\n" - "If gx or gy is 0 or less, no snapping happens in that direction.\n" + "If gx or gy is 0, no snapping happens in that direction.\n" "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" ) + + method ("scaled_and_snapped", &db::Region::scaled_and_snapped, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"), + "@brief Returns the scaled and snapped region\n" + "This method will scale and snap the region to the given grid and return the scaled and snapped region (see \\scale_and_snap). The original region is not modified.\n" + "\n" + "This method has been introduced in version 0.26.1." + ) + + method ("scale_and_snap", &db::Region::scale_and_snap, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"), + "@brief Scales and snaps the region to the given grid\n" + "This method will first scale the region by a rational factor of mx/dx horizontally and my/dy vertically and then " + "snap the region to the given grid - each x or y coordinate is brought on the gx or gy grid by rounding " + "to the nearest value which is a multiple of gx or gy.\n" + "\n" + "If gx or gy is 0, the result is brought on a grid of 1.\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.26.1." + ) + method ("grid_check", &db::Region::grid_check, gsi::arg ("gx"), gsi::arg ("gy"), "@brief Returns a marker for all vertices not being on the given grid\n" "This method will return an edge pair object for every vertex whose x coordinate is not a multiple of gx or whose " From 4924d0269c65782a164b95407c59b3700dcfff2b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 6 Nov 2019 23:28:16 +0100 Subject: [PATCH 4/8] Fixed #400, added tests. --- src/db/unit_tests/dbDeepRegionTests.cc | 102 +++++++++++++++++++++++++ testdata/algo/deep_region_au400a.gds | Bin 0 -> 35920 bytes testdata/algo/deep_region_au400b.gds | Bin 0 -> 35920 bytes testdata/algo/deep_region_au400c.gds | Bin 0 -> 15040 bytes 4 files changed, 102 insertions(+) create mode 100644 testdata/algo/deep_region_au400a.gds create mode 100644 testdata/algo/deep_region_au400b.gds create mode 100644 testdata/algo/deep_region_au400c.gds diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index a9f2c84dd..83b6be3fd 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1641,3 +1641,105 @@ TEST(issue_277) EXPECT_EQ (r.sized (1).merged (false, 1).to_string (), ""); } +TEST(issue_400) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/gds/t10.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; + // keeps a reference to the DSS + db::Region rr (db::RecursiveShapeIterator (ly, top_cell, (*ly.begin_layers ()).first), dss); + + for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) { + + unsigned int li = (*l).first; + db::Region r (db::RecursiveShapeIterator (ly, top_cell, li), dss); + + r.set_merged_semantics (false); + r.snap (19, 19); + + ly.clear_layer (li); + r.insert_into (&ly, top_cell_index, li); + + } + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au400a.gds"); +} + +TEST(issue_400_dont_keep_regions) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/gds/t10.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; + + for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) { + + unsigned int li = (*l).first; + db::Region r (db::RecursiveShapeIterator (ly, top_cell, li), dss); + + r.set_merged_semantics (false); + r.snap (19, 19); + + ly.clear_layer (li); + r.insert_into (&ly, top_cell_index, li); + + } + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au400b.gds"); +} + +TEST(issue_400_with_region) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/gds/t10.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::DBox rbox (2.61, -1.6, 12.76, 4.7); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) { + + unsigned int li = (*l).first; + db::Region r (db::RecursiveShapeIterator (ly, top_cell, li, rbox.transformed (db::CplxTrans (ly.dbu ()).inverted ())), dss); + + r.set_merged_semantics (false); + r.snap (19, 19); + + ly.clear_layer (li); + r.insert_into (&ly, top_cell_index, li); + + } + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au400c.gds"); +} diff --git a/testdata/algo/deep_region_au400a.gds b/testdata/algo/deep_region_au400a.gds new file mode 100644 index 0000000000000000000000000000000000000000..5aa551f074125f38a6f989a5d90f554a065a2eac GIT binary patch literal 35920 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 literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_au400b.gds b/testdata/algo/deep_region_au400b.gds new file mode 100644 index 0000000000000000000000000000000000000000..5aa551f074125f38a6f989a5d90f554a065a2eac GIT binary patch literal 35920 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 literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_region_au400c.gds b/testdata/algo/deep_region_au400c.gds new file mode 100644 index 0000000000000000000000000000000000000000..9351934903f88f362161b12832e7fd14507aecfd GIT binary patch literal 15040 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 F^j{xddHw(Z literal 0 HcmV?d00001 From 318efbf7b02fe282ceb13c7763aae36fa0d10fca Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Nov 2019 22:54:16 +0100 Subject: [PATCH 5/8] Fixed 'scale_and_snap' feature --- src/db/db/dbCellVariants.cc | 129 +++++++++++++++++++++++-- src/db/db/dbCellVariants.h | 119 +++-------------------- src/db/db/dbLayoutUtils.cc | 21 +++- src/db/db/dbLayoutUtils.h | 2 +- src/db/db/dbRegionUtils.cc | 6 +- src/db/db/dbRegionUtils.h | 6 +- src/db/unit_tests/dbLayoutUtils.cc | 38 ++++++++ testdata/algo/layout_utils_au_sns1.gds | Bin 0 -> 111992 bytes testdata/algo/layout_utils_au_sns2.gds | Bin 0 -> 111992 bytes testdata/algo/layout_utils_au_sns3.gds | Bin 0 -> 111992 bytes testdata/algo/scale_and_snap.gds | Bin 0 -> 37590 bytes 11 files changed, 201 insertions(+), 120 deletions(-) create mode 100644 testdata/algo/layout_utils_au_sns1.gds create mode 100644 testdata/algo/layout_utils_au_sns2.gds create mode 100644 testdata/algo/layout_utils_au_sns3.gds create mode 100644 testdata/algo/scale_and_snap.gds diff --git a/src/db/db/dbCellVariants.cc b/src/db/db/dbCellVariants.cc index adb5b6e97..38456de6b 100644 --- a/src/db/db/dbCellVariants.cc +++ b/src/db/db/dbCellVariants.cc @@ -22,11 +22,124 @@ #include "dbCellVariants.h" +#include "dbRegionUtils.h" #include "tlUtils.h" namespace db { +// ------------------------------------------------------------------------------------------ + +db::ICplxTrans OrientationReducer::reduce (const db::ICplxTrans &trans) const +{ + db::ICplxTrans res (trans); + res.disp (db::Vector ()); + res.mag (1.0); + return res; +} + +db::Trans OrientationReducer::reduce (const db::Trans &trans) const +{ + return db::Trans (trans.fp_trans ()); +} + +// ------------------------------------------------------------------------------------------ + +db::ICplxTrans MagnificationReducer::reduce (const db::ICplxTrans &trans) const +{ + return db::ICplxTrans (trans.mag ()); +} + +db::Trans MagnificationReducer::reduce (const db::Trans &) const +{ + return db::Trans (); +} + +// ------------------------------------------------------------------------------------------ + +db::ICplxTrans MagnificationAndOrientationReducer::reduce (const db::ICplxTrans &trans) const +{ + db::ICplxTrans res (trans); + res.disp (db::Vector ()); + return res; +} + +db::Trans MagnificationAndOrientationReducer::reduce (const db::Trans &trans) const +{ + return db::Trans (trans.fp_trans ()); +} + +// ------------------------------------------------------------------------------------------ + +GridReducer::GridReducer (db::Coord grid) + : m_grid (grid) +{ + // .. nothing yet .. +} + +db::ICplxTrans GridReducer::reduce (const db::ICplxTrans &trans) const +{ + // NOTE: we need to keep magnification, angle and mirror so when combining the + // reduced transformations, the result will be equivalent to reducing the combined + // transformation. + db::ICplxTrans res (trans); + res.disp (db::Vector (trans.disp ().x () - snap_to_grid (trans.disp ().x (), m_grid), trans.disp ().y () - snap_to_grid (trans.disp ().y (), m_grid))); + return res; +} + +db::Trans GridReducer::reduce (const db::Trans &trans) const +{ + db::Trans res (trans); + res.disp (db::Vector (trans.disp ().x () - snap_to_grid (trans.disp ().x (), m_grid), trans.disp ().y () - snap_to_grid (trans.disp ().y (), m_grid))); + return res; +} + +// ------------------------------------------------------------------------------------------ + +ScaleAndGridReducer::ScaleAndGridReducer (db::Coord grid, db::Coord mult, db::Coord div) + : m_mult (mult), m_grid (int64_t (grid) * int64_t (div)) +{ + // .. nothing yet .. +} + +db::ICplxTrans ScaleAndGridReducer::reduce_trans (const db::ICplxTrans &trans) const +{ + db::ICplxTrans res (trans); + int64_t dx = int64_t (trans.disp ().x ()) * m_mult; + int64_t dy = int64_t (trans.disp ().y ()) * m_mult; + res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid)))); + return res; +} + +db::Trans ScaleAndGridReducer::reduce_trans (const db::Trans &trans) const +{ + db::Trans res (trans); + int64_t dx = int64_t (trans.disp ().x ()) * m_mult; + int64_t dy = int64_t (trans.disp ().y ()) * m_mult; + res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid)))); + return res; +} + +db::ICplxTrans ScaleAndGridReducer::reduce (const db::ICplxTrans &trans) const +{ + db::ICplxTrans res (trans); + int64_t dx = int64_t (trans.disp ().x ()); + int64_t dy = int64_t (trans.disp ().y ()); + res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid)))); + return res; +} + +db::Trans ScaleAndGridReducer::reduce (const db::Trans &trans) const +{ + db::Trans res (trans); + int64_t dx = int64_t (trans.disp ().x ()); + int64_t dy = int64_t (trans.disp ().y ()); + res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid)))); + return res; +} + +// ------------------------------------------------------------------------------------------ + VariantsCollectorBase::VariantsCollectorBase () : mp_red () { @@ -219,7 +332,7 @@ VariantsCollectorBase::commit_shapes (db::Layout &layout, db::Cell &top_cell, un for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { db::ICplxTrans t = i->complex_trans (*ia); - db::ICplxTrans rt = mp_red->reduce (vc->first * t); + db::ICplxTrans rt = mp_red->reduce (vc->first * mp_red->reduce_trans (t)); std::map::const_iterator v = vt.find (rt); if (v != vt.end ()) { @@ -263,7 +376,7 @@ VariantsCollectorBase::commit_shapes (db::Layout &layout, db::Cell &top_cell, un for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { db::ICplxTrans t = i->complex_trans (*ia); - db::ICplxTrans rt = mp_red->reduce (vvc.begin ()->first * t); + db::ICplxTrans rt = mp_red->reduce (vvc.begin ()->first * mp_red->reduce_trans (t)); std::map::const_iterator v = vt.find (rt); if (v != vt.end ()) { @@ -325,11 +438,11 @@ VariantsCollectorBase::add_variant_non_tl_invariant (std::mapreduce (inst.complex_trans (*i))] += 1; + variants [mp_red->reduce_trans (inst.complex_trans (*i))] += 1; } } else { for (db::CellInstArray::iterator i = inst.begin (); ! i.at_end (); ++i) { - variants [db::ICplxTrans (mp_red->reduce (*i))] += 1; + variants [db::ICplxTrans (mp_red->reduce_trans (*i))] += 1; } } } @@ -338,9 +451,9 @@ void VariantsCollectorBase::add_variant_tl_invariant (std::map &variants, const db::CellInstArray &inst) const { if (inst.is_complex ()) { - variants [mp_red->reduce (inst.complex_trans ())] += inst.size (); + variants [mp_red->reduce_trans (inst.complex_trans ())] += inst.size (); } else { - variants [db::ICplxTrans (mp_red->reduce (inst.front ()))] += inst.size (); + variants [db::ICplxTrans (mp_red->reduce_trans (inst.front ()))] += inst.size (); } } @@ -390,7 +503,7 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell, for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { - db::ICplxTrans rt = mp_red->reduce (for_var * i->complex_trans (*ia)); + db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia))); std::map::const_iterator v = vt.find (rt); tl_assert (v != vt.end ()); @@ -419,7 +532,7 @@ VariantsCollectorBase::create_var_instances_tl_invariant (db::Cell &in_cell, std std::map::const_iterator v; - db::ICplxTrans rt = mp_red->reduce (for_var * i->complex_trans ()); + db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans ())); v = vt.find (rt); tl_assert (v != vt.end ()); diff --git a/src/db/db/dbCellVariants.h b/src/db/db/dbCellVariants.h index 34775bc4a..965bdae5f 100644 --- a/src/db/db/dbCellVariants.h +++ b/src/db/db/dbCellVariants.h @@ -50,6 +50,8 @@ public: TransformationReducer () { } virtual ~TransformationReducer () { } + virtual db::Trans reduce_trans (const db::Trans &trans) const { return reduce (trans); } + virtual db::ICplxTrans reduce_trans (const db::ICplxTrans &trans) const { return reduce (trans); } virtual db::Trans reduce (const db::Trans &trans) const = 0; virtual db::ICplxTrans reduce (const db::ICplxTrans &trans) const = 0; virtual bool is_translation_invariant () const { return true; } @@ -63,18 +65,8 @@ public: struct DB_PUBLIC OrientationReducer : public TransformationReducer { - db::ICplxTrans reduce (const db::ICplxTrans &trans) const - { - db::ICplxTrans res (trans); - res.disp (db::Vector ()); - res.mag (1.0); - return res; - } - - db::Trans reduce (const db::Trans &trans) const - { - return db::Trans (trans.fp_trans ()); - } + db::ICplxTrans reduce (const db::ICplxTrans &trans) const; + db::Trans reduce (const db::Trans &trans) const; }; /** @@ -85,15 +77,8 @@ struct DB_PUBLIC OrientationReducer struct DB_PUBLIC MagnificationReducer : public TransformationReducer { - db::ICplxTrans reduce (const db::ICplxTrans &trans) const - { - return db::ICplxTrans (trans.mag ()); - } - - db::Trans reduce (const db::Trans &) const - { - return db::Trans (); - } + db::ICplxTrans reduce (const db::ICplxTrans &trans) const; + db::Trans reduce (const db::Trans &) const; }; /** @@ -104,17 +89,8 @@ struct DB_PUBLIC MagnificationReducer struct DB_PUBLIC MagnificationAndOrientationReducer : public TransformationReducer { - db::ICplxTrans reduce (const db::ICplxTrans &trans) const - { - db::ICplxTrans res (trans); - res.disp (db::Vector ()); - return res; - } - - db::Trans reduce (const db::Trans &trans) const - { - return db::Trans (trans.fp_trans ()); - } + db::ICplxTrans reduce (const db::ICplxTrans &trans) const; + db::Trans reduce (const db::Trans &trans) const; }; /** @@ -125,47 +101,15 @@ struct DB_PUBLIC MagnificationAndOrientationReducer struct DB_PUBLIC GridReducer : public TransformationReducer { - GridReducer (db::Coord grid) - : m_grid (grid) - { - // .. nothing yet .. - } + GridReducer (db::Coord grid); - db::ICplxTrans reduce (const db::ICplxTrans &trans) const - { - // NOTE: we need to keep magnification, angle and mirror so when combining the - // reduced transformations, the result will be equivalent to reducing the combined - // transformation. - db::ICplxTrans res (trans); - res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ()))); - return res; - } - - db::Trans reduce (const db::Trans &trans) const - { - db::Trans res (trans); - res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ()))); - return res; - } + db::ICplxTrans reduce (const db::ICplxTrans &trans) const; + db::Trans reduce (const db::Trans &trans) const; bool is_translation_invariant () const { return false; } private: db::Coord m_grid; - - inline db::Coord mod (db::Coord c) const - { - if (c < 0) { - c = m_grid - (-c) % m_grid; - if (c == m_grid) { - return 0; - } else { - return c; - } - } else { - return c % m_grid; - } - } }; /** @@ -178,49 +122,18 @@ private: struct DB_PUBLIC ScaleAndGridReducer : public TransformationReducer { - ScaleAndGridReducer (db::Coord grid, db::Coord mult, db::Coord div) - : m_mult (mult), m_grid (int64_t (grid) * int64_t (div)) - { - // .. nothing yet .. - } + ScaleAndGridReducer (db::Coord grid, db::Coord mult, db::Coord div); - db::ICplxTrans reduce (const db::ICplxTrans &trans) const - { - // NOTE: we need to keep magnification, angle and mirror so when combining the - // reduced transformations, the result will be equivalent to reducing the combined - // transformation. - db::ICplxTrans res (trans); - res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ()))); - return res; - } - - db::Trans reduce (const db::Trans &trans) const - { - db::Trans res (trans); - res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ()))); - return res; - } + virtual db::ICplxTrans reduce_trans (const db::ICplxTrans &trans) const; + virtual db::Trans reduce_trans (const db::Trans &trans) const; + virtual db::ICplxTrans reduce (const db::ICplxTrans &trans) const; + virtual db::Trans reduce (const db::Trans &trans) const; bool is_translation_invariant () const { return false; } private: int64_t m_mult; int64_t m_grid; - - inline db::Coord mod (db::Coord c) const - { - int64_t cc = int64_t (c) * m_mult; - if (cc < 0) { - cc = m_grid - (-cc) % m_grid; - if (cc == m_grid) { - return 0; - } else { - return db::Coord (cc); - } - } else { - return db::Coord (cc % m_grid); - } - } }; /** diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 0b8bc636c..580c4066d 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -493,7 +493,20 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db db::Polygon poly; si->polygon (poly); poly.transform (tr); - out.insert (scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap).transformed (trinv)); + poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap); + poly.transform (trinv); + out.insert (poly); + + } + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { + + db::Text text; + si->text (text); + text.transform (tr); + text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()))); + text.transform (trinv); + out.insert (text); } @@ -515,7 +528,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) { db::Trans ti (*i); - ti.disp (scaled_and_snapped_vector (ti.disp (), g, m, d, g, m, d)); + db::Vector ti_disp = ti.disp (); + ti_disp.transform (tr); + ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + ti_disp.transform (trinv); + ti.disp (ti_disp); if (ia.is_complex ()) { new_insts.push_back (db::CellInstArray (ia.object (), ia.complex_trans (ti))); diff --git a/src/db/db/dbLayoutUtils.h b/src/db/db/dbLayoutUtils.h index 44e176ad6..2c6cbd1ae 100644 --- a/src/db/db/dbLayoutUtils.h +++ b/src/db/db/dbLayoutUtils.h @@ -229,7 +229,7 @@ private: * This method will scale and snap all layers from the given cell and below to the * specified grid. Scaling happens by the rational factor m / d. */ -void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d); +DB_PUBLIC void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d); } // namespace db diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 98475d9a0..e2b975f2f 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -427,13 +427,13 @@ scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx, } db::Vector -scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) +scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy) { int64_t dgx = int64_t (gx) * int64_t (dx); int64_t dgy = int64_t (gy) * int64_t (dy); - int64_t x = snap_to_grid (int64_t (v.x ()) * mx, dgx) / int64_t (dx); - int64_t y = snap_to_grid (int64_t (v.y ()) * my, dgy) / int64_t (dy); + int64_t x = snap_to_grid (int64_t (v.x ()) * mx + int64_t (ox), dgx) / int64_t (dx); + int64_t y = snap_to_grid (int64_t (v.y ()) * my + int64_t (oy), dgy) / int64_t (dy); return db::Vector (db::Coord (x), db::Coord (y)); } diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 95fd8e5ea..dd59d41f6 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -545,15 +545,15 @@ DB_PUBLIC db::Polygon snapped_polygon (const db::Polygon &poly, db::Coord gx, db /** * @brief Scales and snaps a polygon to the given grid * Heap is a vector of points reused for the point list - * The coordinate transformation is q = ((p * m + o) % (g * d)) / d. + * The coordinate transformation is q = ((p * m + o) snap (g * d)) / d. */ DB_PUBLIC db::Polygon scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy, std::vector &heap); /** * @brief Scales and snaps a vector to the given grid - * The coordinate transformation is q = ((p * m) % (g * d)) / d. + * The coordinate transformation is q = ((p * m + o) snap (g * d)) / d. */ -DB_PUBLIC db::Vector scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy); +DB_PUBLIC db::Vector scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy); } // namespace db diff --git a/src/db/unit_tests/dbLayoutUtils.cc b/src/db/unit_tests/dbLayoutUtils.cc index 57b73bb94..1c7ce3825 100644 --- a/src/db/unit_tests/dbLayoutUtils.cc +++ b/src/db/unit_tests/dbLayoutUtils.cc @@ -615,3 +615,41 @@ TEST(16) } +TEST(17_scale_and_snap) +{ + db::Layout l1; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (l1); + } + + db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 1, 20, 19); + + CHECKPOINT(); + db::compare_layouts (_this, l1, tl::testsrc () + "/testdata/algo/layout_utils_au_sns1.gds"); + + db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 1, 19, 20); + + CHECKPOINT(); + db::compare_layouts (_this, l1, tl::testsrc () + "/testdata/algo/layout_utils_au_sns2.gds"); +} + +TEST(18_scale_and_snap) +{ + db::Layout l1; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (l1); + } + + db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 19, 1, 1); + + CHECKPOINT(); + db::compare_layouts (_this, l1, tl::testsrc () + "/testdata/algo/layout_utils_au_sns3.gds"); +} diff --git a/testdata/algo/layout_utils_au_sns1.gds b/testdata/algo/layout_utils_au_sns1.gds new file mode 100644 index 0000000000000000000000000000000000000000..372770c6179876eb4874868741fed3acf416c375 GIT binary patch literal 111992 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 X(uL!$^6@ra06pbi@QS>W{BrmI&i0vh literal 0 HcmV?d00001 diff --git a/testdata/algo/layout_utils_au_sns2.gds b/testdata/algo/layout_utils_au_sns2.gds new file mode 100644 index 0000000000000000000000000000000000000000..1a69e3ee5e9e63791e335196cadc12c092d2bb7b GIT binary patch literal 111992 zcmeHQJB((@Rlf7;9k17Bz4(FgS}ejyfL5aG_8VDN?|OxJtiUo0m=PfXApxO-4jh0) zNPtA*jD&z-0tbW^B6L7N-~b5%%aLUvWFd>@`|f|Mr%qL!x#vG!n&~6WFZKSjJ@cJ9 z?|Pq_4yOC}zcIai@BVB5IemP3ZTjpqPpSO#^!Wb4hrj*)G=2KPqp!U8*Jr=`FaPkP zix0l@>)-zSCm&63Khkk;92~s&r9XP_>+|W^^ziXC9em>cbZF7pTCDczww1f@4bU>e%>J6d;h)s9DM%Z z!+BcJuT3^iPcFi68b+swhe33j&QGFndUhU#)0CocdUzU!(L7$k=oPFT4pnHARgCAU9 z|Mcf}vlRZr*S^R9@;m>2`L@hAUOzZkw1g2yA!Wi?=@vS|INPry=4u1_CFlra@{bB+5G7jKNTlh&l-qQAZfZ#mG`eVPgL%Om8}e z*`J%kx%uUl#n6cDRlo?+-in7|1j-ssgq@yt7(=e;& zDa`75n#1&_bC}*V%<6ecVMfwn*7;KklTX8}o~JOY=jkxas4vVqe+skCpAN%}`ogU9 zr!edMSmqD1E_HDphSSq9oQAnAcySa)rxEToF11X~!$j11n25s0S&)2s9>z~`i7$vw zu^AbK(=d1M&*JzgE_}z><2wzLPfx>)P_Vrp#rk3V^dyY+kHhE`TYN$M6kB{zI1SV9 zV>2>}PQ#3(apf$CPI2Wd3a4RWA6L$z=rm01W79l}PQzp=Y(+=WX_$P9P4gf+#in@_ zPQ#4(v1xwCb$Wo>Y~Zn|6~+31sMmDms};pMh=yuUYbBMYb{%HO2J{2eWx?kK)vo(0 zEBxU^NueX2g52cu`ud08dR8N^L?bD5(PeeOY5L4J`)HhKH=sZE-98$3VK&j%*Z=oM z7d_(+r2+lpkGklD4rUWgxu03L)Ee#_7|iCCVH9_xlxe9h8CXs`dhhD4{CWp2bjE z!+_SZ7|!f%qV+6>yE6uKY1`6b2mFu%LSKoMt+uP*3cNS_uIB) zF|M2&&`K7&I5wbjoVGa-3u4{2FBhS++)5Th8INtWn#H(gyxBI<&oT+@owJy!*C~6v zHVfU!EQZr)g;ytZkefPs&R9&TmTb#nTCHV?RDn&mC0fs7IOl3Wt69vDNuHC% zOlU2OVH4cIdFh#jy=R>9GoaNxq;M{ySwV9?*KgaB#kf~xKr2~{CtNnsdKSZiSr;wk zRZp^i+ww%ueg zMCi>65u0sGZwZpeaMP~zYi)K^YDpc9&8Q~U)l!*D)I2uZ*430eHlvQ+X4`5Wn=#Ng zpp`tv+W?zreKdyq83wdA8pA!5O|T%yMFg*GaY zSy0JiycN-xyJ%a@V@VssO1YIh#*^;dwo9}s_pI5wMvIX~o>MAg?-DD0<&I}Dyaln# z&)oYg{F*N=K*v|UU62_sOBgIP?LPIY>x==J0sUfkK^86H7GR;Hbh2bjuZ}D;l2t>! zm1%<~-n?G)f_91)9ii$(sUy@OxP>2C*4$Jb@jleu^rLDwZMVDP^&?avG)TE>sg5&qCVRCL6u9|rVG&=G1U6guLWb@1ub5pQM~q*QdoQ|Jct z3)IoGSB|387MjD<6r8ba@vt4)tiG{+(bnZp@wZDBdNHrZoJXmFHJ?SPF))XDk9t0f zQdw#~3zMbJqEteev8Ws*OPz*^eGD?9=rl}3g{gZxV-Yxr^|9F)h0`!uDoo|m87nhE ztbZIP^B+g4DmNd8>7&Bby`7K4jQWnlr(yO@6K=~y z(P^0332wtg(P@}`dJ<(nD&aO$5bKB8i%wy7Bhzu1d>UroG=3#k!t9)-qcAIIM`32sD0>`ago3iiQ8*3L@8d>v6rG0g(-g)}ag#rY^;4LY-Z*>F zxRV*f`q<nqWj&%3@3o%y`$ zYrC1xyS}5F`Mm4)z_ZIf%o6wtW>o1sTa$n|>c+Yz|i0@MN z+b$|C>(!1i-ZP+;D$jgnb`z~udFETnU9^;2sq)O1LpRa7+;BD%T2y&HK(%^9tI|)} zI*8N=>1NHm)VI%&z23X)vlH|LAMlk)^aMrJ@jRlzhHDVjm2H!yp8Yia+D{gIgGQyR zZrd_P|H96d8#M0C8qh!cSKYQ}+dGl3eXom7*v~h#O}QWZpndHNXO#_T%H2cbHjV*J zxjSgyH8-FscL&X#Y@n~6Td{naKK`99de+_$fS|h%a`ZGQZR4J1!@bpH)EL=%HQOp z9QA1Yv#r%H7QX3Wlq3Hh-)j5hkN=L}#PQGhJOBQ9_%-(}e3A$9pT9|G{rjc;eX6hX zte4?chJA=bV=1q?P%C1S~&iTh%&BY(ZM+tW!n9<`ZC)fK*^zVi2E z+I^Nj`!nAZs}DDAV@Tg^TaL1{6+X-SPha6f^~}w-xzg3={8sN#COj&(*|z>32iLKQ17;Vx%_kdXNeL;ZuQOA8ZA6EzvHGz zU1FuLJZ{D-cWRaICXXFfc?`#qH+8J%F;u4SqRW`l-=nm>>Zs*0Je$1Pww}jM44mtE zOnu|E%HNBlHW7({-sD`*W7?aLrOu^q7TI7%{oBp9^*n|L|ECf?D2wRF`T$7vzYbOW1*v)EM^-`X>&?# ze@o^-C5t8P&EyiTW-;>{*M5x#S{*|zk|!rn6`I0m$m zhxi&~7cHYgL*wnUF4~mE_!^x7tzvWrFHH(>F7Oy?^ z<_+!5wxzcO$zxdcE&bZ^nyxyhISnTFK`!JPH=P*?|=P(r|XIw>i*m~+DK0K>Z{uF>$l{d>GZDOKfB@d@UGu9 z&YUK!AH|6Mgdu4ZPNQV0gh68zorbA=iaB2ponkvY3a4SRRG2rdQ2hk~3nS*eO zU4$T<;zU*uPH|=~2&ZBCC=B_d==9F_QK*6P0km1{2J*El!_L&Ya^9SXu$|@5YKz#; za`3h$K26(}vmCp7qg}LeGN9c3-Q9XE(AZO3*7Obg&bx{#51v&P$yign+^EX_?Da)ZJ|^{!gb}!VoGRzp|atp_TB-EoZdpoa2JzJ@6K7iYKLpi1Ab`qp{bvY zKr6Q?Hr2M3C~31%Pj2lTvqUo=bHJ8(!|P>-|(9 zyJ*eNC0dnR$>I{t+|uFPcnX^6BF2zUm%CS{mX#VJCXH1!M9|-%z9#H+)p)m*mN@Xd zc=uxN^tq}G%fCdwT2IlrWi`RUCt^Be@5wSBZ4n{k}b z<6M?gwAsFe>$9>9GcLIy>b1?(zYhI&0>nq6HZrj zJ@t~J^0U~RXnb;R$unisEPy~cD%@}Fr-L=ke3aQH%G>lMmhnMb6)k5k+hgsggP!e` zI?;aCc5Yj(+$cF$W}CCEelg|lwXNPHZ*o!(jnkXPoYX_(Jgvb;mD#3VV^m}ndU&sG zwR(y`E3>W{Wx%?ew>hcTHcHZV(U%M-6?ZTC9BAGtGQ-wcj5V}>2q5wWUk|yXGXhrmT~>Z|26T`pw*jW z!b6G1Sf@d&mBkx0@=A@?D~mVio`0+NKpQk-yKXyaw|Qi2{lQQBa%;E3TXauuwX(S2 zoNf2y#!ZI4y&H5-?%hiSSBNmo-I1HO8@gy2-{ia#W5ziF(H(myTNNLoJ94X4&0EepI_Ei5gWQZUiN2|? zYe0Ya?s9j$$mct>Z4UV5zY*v>)>}r#9WNI>=M4O6cM) z=@b0i%mgy-F%YlzGhW_)Mo<47A0Un5q~|1wW#c=E}AN4|;A-}(2?zO$YR&(W!>e~7@=mNZuV+t{??9~R2U`}ab2(!VxwFj&dsAZn zf}a7D7{z0FVvZU^iT%qM>Da%xDLpMCkG6xZsPVOS$sS(NQ2LX9A3=#;Foq{m^715S zy3`Xq!KJ5`(rUZ?H7@33l+MeOoX?Wd>f-}=g05V8k~~r4Zc4&48Np-xiIlwlB-hy( z!DDzLB`;6XGbx?dpIS;|e4NsGd6ND_N@IMSl-!;vBA6O?QxZN7UmE03q~!G{>ErD0 z#`riXd3lnaN$I@))KVJbw-55&b$*U(Bccg@$0X+ie!Yd^?x7vH0$+_@q zyZtGNxFb(ve4LcLJ}%>q(v9JXl)OC2XrXjoe`+a>i91R+CR!-n7)s>Ht0x(Eq-2Xb zFwgf(-kElvWkx>#tJR0D6tvB6dg#-Cx=q_e``Ui{k@Pg`z-EhDiXJ7K&$g7LRVkg# z)3zv4x-pci&TF!4E;ehxjr7_+}N@HwCN^aW;f1>Ti@I*>uctXEEh$m8V z^CUbIqn1HlKuT_n3!W&Qw-=CoKK;o{N#-X?H%{YYBA9w|N3hU1^OKvBh&$-W=ml3B zJrku{^|WWtRQE09$!5DPo|p^VJPD1HlFc)>c%pP;cp@bmPg7$%8F!49F_h?;UP>~8 zNoh=eqMpV?3wiQ-rquYaKD=4a+lZDef8wof@MV~B)s#3Q{N=a3d}Or0ZJvTaTp2iT z{a4Pyzxbhb{bh?1?Sfv&$CJpcv+O$#H^14Ugzlnqm|E;B? zZut63)kp6JJMHd67}>!yV%e*A6c6|DY6c1eNEkV&rfZU zw?&Ei@KK^fMEmtY-*oFk%vk7~em>|?s}45$n%bl4j7Um8iLy5RXlm1D$y$o+*|vOD zqwDx&z8XV`R<%*;c)9Qo@?_J^7A5jzqh!&OEfZ}~B2P9-ThdWazBsBg6f=WwZk)Z* zwrDAl^j5$QwM`ryc7%)FeM^-;>2^{q5yefZJLP_`9?+7@-5rJs(W#Mtps zqCS}KS6giK9JNFly~cjkA(-uB2>e*rpCECJG=_xeK&$2tlX!BXMj$1~Xn^MyU z`C_NmIQ3+sbk(edw%O4}iJC3@fdjBW}KDtJ@sGvAam&Lr0{95#|NZx>}%DO7*%5^Q8)M* z#FLxS(_LcTWoG)UPrB^0K0Y$q-!_m&ZC+I);CkJQc0v3Y?6O6PzA}aqd4g>Q@#Li> zcSh(dKIyWxeSBoJzis-8t!<82>e&*}tDo+f9mzShw#JA9%~`BJ!nn%en2NN(?<`@S)$D@wKjYD zutnPzCF;XQsg?-7@)W=0=Vo2Wr<+6|E6tfvpZcae{AQSalUmWZ15 z*@zZqtgd$1b7oTWK~MAPCiAhP_vhm&tj^Ce%7ZSlL>n^#BFd3W=417={rM0vOuN|h zaaHkAYnC>$`HF>--&Y`wk&jxlwM6t4UzP?XVQuo{%PT#e#^e}U-X|SB5Tm^u&$skI zu0*+YBeYDOY`$Duo)TeR;mqC{?Uq7BB*ybuvyRL_DSTF~eU{oBCy|?{MmJ-;pI+zY zsqwmTJo)looh2xpk0<&v=Ed3ad&YJ~`=lV6Ubprld$wKcfN|vW-z>$NOK!;rZDH#d zds&IL@S%J9xLtPi@j-1eEBSqbI#|7VfGzwwpl_}@V^2P^4*YFX2kv~;AZ%vr#@;*I9Z(6k8Vi`XWIwygfq&6DB&#kAnCBB2PAdLX*v^ zD^3d@dR9TdSt;FeRzbg6 zqhfs2f|qp`m?#liRk<_Ug8wO_4#V1Mdv9%`vu_aLbdVM9q$)Ust4Eym?vjL9esf zWlJKC+ikwGMTx5>UM)*|ac=6RB=tm|yn2#6ai%mzPn^Shd6NA+DS0ELrDV%utrxU< za@$U1R<3w?d6Hg0+l|pUqs7aU)Dxu}=TB}*LgS3PG5$p9+?1Zc$M{)J-%#UYY)9$5 zwv*99p4`$2jngx|JhlGhjys`o+Rm+UL5b4YddsV(2bUUWrgQh4LgVZayc(BTg*=VZ zxJ^%tit>b6JrAMAZJxQMar(GdfA1!H)kp2m0qrE|w!u-H=xV-9Keoxn(y#G=6Qg`wLkGih=sb`PnPxX2H z?XJ^5>YrYI-gPg(y1_r{PCf+u$%kL+o^&Ta^pgDj)sH@T>*Ml`&#Nf+rT^@@M^e*A zPChquBl>B_F}=9iFH>O&wh^YRPXA@nt9+}^9(8(pO6XLvgcqn!h-pZt{q+UG^bq{C zzq%%v9)wQ&o@5HP)6Y8AKfNTG!UHDVuEdmyD8&+N)n|VZb#o<|dp7ec%df}uf@P}o zxqWqoD&7JeG)pl*6%jG^=FfvUwz}r+wZ2oKYM(C z|KH-?@)=twjg}F_LtkH^Z^!>#{uulH(|;7`3kp5;J4bY_&3gRp`}_ZUbK|e5>FGB% z^*#MY`u+Gl;%CMiubiBWT9O`zlCqb+(gGbxKRd1?BrSZ zXG(9|d1TCetTz8KoH4OKFY3PAEZ58Y zJrnzf!IX{tseM{er);lpeWpz8H@1FkX5y5I{f1d8K8`wNdML{B>-D8hkEV?}Wg}|! zzSJo*jyeSE_czSw_Cq|2o#c zWU|yjL=-*KySh%Pncjwe8XiaWvTx%^VxO9mZm83E>{Bzn2N6*hOzf*@S}*foFg=vR zV9Jh86x($&|2Z=@Z5UDUEOmA?eW^2M#CI4vU17E-G>Y!e*x8=dBkJsE`lkbD-K zGQVsc=6WcK?K=5XwhkW)Q>HaNh#tz(%%1oC(e$MEJ~N>&KX0vP{>`{5RBTL8Z^7qZ71I;sLwg5pi?I==2cs z=?#6Zac%2gQxSCtI=w!ch?0e~{pM3dR47YbQ+|2~)|W$kgia5FDRrNLiunG&+?fKGIK>2Q1Mk+Ne@Lw zMeN6{PsKj0zq(GT(TQTYH1oqxV>+d>RAZgSBC2Qnw4qMpeoE!jLtrY4=49+E zwo9{A$ojHqPB2w0mqt|B`aRX>2UGR4RHvcXmql|zrwv0$Wd}{%!*_r0pfSd+ z*ZuXew&^y=_y2vhZmc#CXygs~6grn3DzoVO`|p0bj+UL`RrKxnzsnzTk0qj{ipDI& zEV}C)xiLDR(8g0=c`e;kIg7QvQf47&1!X7g+~5E2Cm<)j)9)YZF7aDW9z7Z@86-{L zC`o(z{0*FA7L$F(IuFU2147O*i@jO;hU~GdqAOXff|kip0zGE259r)p{2)O zubatYm^mlVP8P!+hFNrq)6&n+9E;tKLMOSMEGE}@)a%x0H;ZA;xXL_7OD1{n)Re`j zR!6sZWfq#U*qcc^Sr!|A|4?^{-)5;z7L%Utn8l`VC{TMknZ;x`n)2#i8pv54y`V4V z+?HI)V$Vz8@a|f+Xtys$)IDXfvhG3lxmM-Yb)#4D(8_47$}HN zwsJdJ3?uGYw424Gx#iHtQ&Sdmdft{dmBkLLFD7ScR7_wG!>opKcxX8lT}4w_3^$SzXeWye?(Buipl%i$c*T61Ap(-(>$1zxCyoy)ij$qocwb9px4> zxjyBwL2eVPYDwpkDUa29L_|bF2lcuKC#H1WQy#0-Egk(?=6-LC8PEE?u~SNGUT;j! zp%Bb<3#;ti%gG=D?PMaH)~TYcw>W6*qpqTlHtTeq9XdO4?3MO(R@ zJcga_vuHPu4W7Mq-9VctNxd$cZtuk*s_^1c?)8bpRx9- z{Ce1oQSM|s;Llb2FZjsI5`=}i%_pCA9c1e*f!^;b$fzYb1*mk?UyKZq6dWe6!JE#>(Lw|)@l6=JP7I>MfH;ThDCBz#6nM@QI& z-bzPpUdwuT<%qep13M+u9;8W1e2w0)pSOe7xKmL2ce|f89Aw&J{v5|)=yZiU210vf zhAZZdfrfi!u%j<#ed;~xhDvL{?W9i=Q4j&o8MP@GbhcKMpV4rmyLMyOqJ!AGDYmi{FJ(%`5>|seLu5e zt2|@ph=TQlI%WG(tG7|qt;eb#wO*fJ&VtNG)Il(%Zj)6$x-|CVS?ZK&_Zu=rmJ+ss z`BT}kFmL^a`7|E;r^gcey)5_5>$IWu!+zS|Fg@vp)(`t>FPlW>b*i%dYWcLkVIt}< ztj|PLL+dZ_(>?e37cgb|{D+}arrkdbrhD%5$E`1$7`QB@^t!YsEo^sh_j@_Sa4byO zETwYlN;+j@e|@HVj{SJMf4xHNhsLJ;zE{oTI=y0IU-{^2nDFY{CDrVVu(_tW#E>7kr6v40rWXWFQS){l>(_r1m!XDXKo z?=|x;V9Ji7l?NyvAb_Zm@gKb4Ek_R2JFeK`?* zEKHBaPy0RlX*~1GN&dZBKORwXxy_L<-S=8_-1>4R^Eh;RBe#0YGi})Jhy7G8Zao&J z^xf>x>-4jv*BACvIi^qORP{}lj-p|G`PqHtOco>vrib9CGR=Q1Oy$h(eC#*2zWD0y z)|Vq^$HH{q5rx4ape;(wKVdb#g61j3nLmQDzrDt)%d{Gr&F1qp&F zvXo-G)cT=_lB?Yari$fyI;H&dAar^(t*KlRLRudlF#Rm`(@;doR3E{#vGrq2_uZPJ ze;Q&c6BGN_X(&s{1%=1Ll#VFnt4ks(Zhb1ERNSw(PnwFTLujMq>Mz1i*VO4NCns;= zZ5(D!vY|#LKkb&I5>IyKTyb3zO<|tQ>Yn1bv=#}r zJNLHwLDn#`jdt3b=Lk9xw-B$12Fqq3ddf|A!S?OHF zp09g*H*SIU?hMv-+xy3L-J6>gh1Uyj!*%Xy#@p9bt=*<@d*PcK9@^g1?7agf{k>}4 z7LC}IPp&n&qIMqb-tvsMl&f{$j+MzDqukCd&pmfDsVBEQIy_tVbj$O@ix4OB{u#xY zy5U*B8YB+1(mnN(z20Ja(yA3$+M|lJ1n;0HEiHkHx?c7p5;mNiDfiu;xzE1qe)4}t ze1Vqd4ytwQe9?73{0nuooSP-kAN+$Vdf?uPeEN+lx@X>~+{i60X(6}lRVJ82?iyN7 z;}B@bT|p1BzE7YbcLj}=Y(d|>Fh_UY`~I$q9=taMZbv1{ALD)6PTjKE!(pyo_2{}! z{7kiOc~FEwfB5&RXsnCZwPxyer@Fyjjd*uU}sfPAmaVaxX4ei~`Z_%(=1wF_O8&$1YG@_(} z?q!mcKtpb+ztFiX1QBRtrW#rv%OKE@yMi9%4io|nxhv>?lh^Ku%v3=S(h;iGZGFwD zTO75Hw*5auNu};9*&$G^+oBPn6?E_2OmET1Of|IJI99FO$}J&QMav^01X}8?q2&N1 zgLdS``U+9EqjRhzkZ2WS@;=G*PB(#l{VQWTm?A7;o!GYe2KJ+$-$rM`jyL4r6&_w< zKk?BGws!9s^oh@u@lg+2o$)*UUcN`(H9R~CpQ)`w4jS?JPQRCL7eDoC#$Fxb2^LD< z;GugxwfeyubxnRT@`i^&j`Vx^cIyXk{C`tKjDH6nze~S=5q`>jBTsMu|MZP=bZ*?` zM*H{w<#xtd=Dwbb26sV!|9pCB4_f9wlUG%RN8o_SMOUWpjC#v0w!JLx9XDqD=fC52PV|%fcia}eN7>7xVwBvY4#zyCv^H#B z(UE_9;T)ZwxzXs&TTXLmXNGT(n~|%`Z%3*q_1R-+ZT!!ixjg$(N85gqGtC1%+Ge6LkCo_wd)3ifsgP%rXY2M?D&$sm0`06+ z^zIw4S^nX_~fS#?}U8xwnHzBpot#9f)CimaY*6n7ZLCyeI(KareJSNUkN9$bT z#`BGr4J_KrWA4h-*GC&o8Th-O9{;Pbm~7l7@ZdE%M1EbFUVq~+|_s-Hm^p$xNbj-ojL0W)?1t`cERN#r#B`S z{5cj=d1%}x0l|wrj%-k8iGYQJV)({<;@25()* zMx--0Hh6nNEZXah$z5Dk3u*L}$DS9h^We^vsQ#4S8)HUhZXWA7tvPwDm;16PxjTG{ zUWwebMxdQc)O$L&@$8|!ot8S6xbfV3Jwc0h@>nk$_v&)1Ea>L3o*PR$d93$#d1|e> zau4#hOqF?#uJ*==3`%CPR=qLVn}+^2_N7hz?oNC9%p8B}joIC0gEzOOb>#2i<@Sd; zy|F=_%dXl-=OK)(@^)rCZ!*XmoU`aDi&bXjyp;`I_mss-G)|4r*6n67X`C6fwykP+ zaI?Z}-PSV|S~`LZ+Q~z>DWh7q^%e(>lfhNA%|p(Z5@)puw3EefCVdv|X0a~^(ot+j1T=k3lQLvadiq9lzeotYC|v-On&?~85Uv!`!9Rc9u;htH_xUDoe+J|FeK zlsS0>me_kdeLoQ0^h5T;l)6!}AydSv=yms-P=+)1)S24Py+o&ADnAjXd$xXDr^5;- zrDE1Un)~mDUdD`NMpd3Df7K_?mYz9?XDQkGG0(JN?8lj&GAE5yE=5jNpZ#V2UgnRE zL#MrTNsomolcf&9PkZS!&g)dQPpid#FPlh?gsF`A_Rcia?)S1B&M{TKx=xmoQ8>p` z`RY=pF`de;yuC9G^-y~1O>3pk^vXpE$A($$CuGT-5&4DCSrPn3a568Z2EGC&My)I!I z9-YVrYLaOqorampG9JNHv0TkhWvY*03d<|Dt5{za`3Rbbof-rXYHUJjhrluuDNvzKE$)m%qAI|KCU@8;C2s$167#+7Gc-FdoM z}wWDqNu zIAg48mRpGA#-1w9t{3Bcufiq9)XqPg3$9?D6<1qtCT*(M*)4MmKg4IeK?Q%Q)JyF7 z+xT<^OYB#f&Xhk`C~+oMiKly89SlJuZmd;Bdp=e~V+GyIH9z&pFlg@%5${$A8_oKhylyjYh+T9Wxg`_j7VB>)i#hjr z^w%T$Zss(`baOyiHx-+1-AO;jR~dP4)fbhV5yu` zt6PqwRejB(1zBfKpWI;xn~v)uOHDr2M$SGB{ll^Vo=w(#Um_a0%qi3ha07+|@(bq@la zjqYn(I3 z>}Hj@t=o|sGvihC?I?7T8~;&ZjIPaqN#|*_ON{~m zlpaHl_4?r^GmPWS5=)JI5Syyr6d!m8q$;tEkEx%NSZ~puwk;a5S*d&AZ|ao#^Sa%e z8*SZFud6_F_ZLI%THWqRa$_%N#E0FRqVqce|NjZ~R+_Pl0w%ju{^VTC!<@ zc5fCh(2`ejw12aBfv)+Odk(ZfOKj(L_ZMF8(4fEca$RokRJiRe09}*Yy;;1dyC%0> z7G1Y@fv(BDd5Pez@U@b;S^QJa#J%ttGZN4hKX-2yFVT`$ za^~2zR%KqID{}YT2}v-QPhPiso4burpey#qF19N35?ztoz16%#S9FejX++(~4i$9I zoDA){U;1oSYrT83xbbtKYnjQtS-e13Bh>L08zrc_VzGfaslAcA5+%KRv$$dY&TrM_ zc5fCh&^5W;o5c%sO>TEBxIowB-rV(hHH9z-m7BA72 z2*n=dYK)cWirhHeP(|DL26OoonW=YrEhV~QZ}Ju&)LoI=z16&|yP|XKLnY)!gj)3W zeq93nxgV3W<6qHQ+umwPpnv|44LbGp#-4G-%S{V<{*O6!dXa{x7uopqpSP@KJ>wlm zSGVF4<7Yb(NVwX3yx4I3;9F)fj&nUj)*irLym{oGzGW;h{yvQfYVu3;jcXV91`e3? zjlWO-KE_xLFZp)-|M3kD;+NZRlr#Oii%0(eIDF#{ci1_7r{Bx>3-RCxJoo~izSHmJ z+r@wW^$kaSgFDJe-{3y|yNjRlK!65?TO1hu>qn4avH|OVG0Nb@G2|nJYBzR`5q-PQxf=ss-$f?=q(z{_} z4QQ-LPWwv(Xsk#sdrW`DjgOCsGe-xp(Ocf&>~LH6+@T~c?(R0LTOZeb%i$kbAM((g-_+2T zf4!t`pksBv@x*!>bimmnm!eh@=d)!=)~b+>^R&5=AYGf1z$vPyQo5MW=5rE|PJW11 zC)X3^qktBv7NDh%NT9nc@^UEoNg*5nFx{gij0uClBAVMdRiE@7~f19Z%|SjZv>|{wnIr_+Zn%x?b>ic zNo_buyWWTsN(yr_J}$kMxQ`o+qolCL4JSw!Z3S$b4}Xf5Wb-7XYp3xx5ez+rBiLvh z`6*nI@dD8i=>>Bw6QrB;v}4PZw=Lkr*=~*#azU7r(Kt%tJadi{q-(YnVfBRU`1LI;x+GuelUmsm+j zA8|BtR}5X#M=W0QlHjLYNoDNVoQB;_oOF3f&@5hC~`^j_U)y8P~IwC2hvh&?aZe zT#Dq`T)xWDd3+*YwJ8Z!x{OheK~9E}Xc%_!uy$nz}x zv`tBfomffG2lD-7iTZBt8^AU))m{s$*MYM%W zD%zk}?Bp7Up16{j?8uc=^IvE=j)n)uT8La9$Odgnf@a&41Ww_W!}tw2#Y#esfsJD5 zJQ7e+8{J^uAm%r@=|3(7^dGl9GS0+&NB!qMh#b01ikJp#JVdI%x>jBiqN+_v(2e{w;uJ2)^ta)& zG3k=e#&{%jylz2~+ARChc9k1;k@z9(GFK9OrA zc)-i!JfK<5H}gDJ(?{I9z@uH%$9UutL9;O%!NQ2u$u2vNOmZIZw3u!Zj|sgy57WyN zT_lNSMg+O9Bp#Ee?asr*FzmwVgUP3yuP`OWeMO{+x9CPU@ReAW7Oykb2B%nFsrhf4 z90SY8q=N@aZ!g93LJ!1DR9H7g%izTMaxJE0ToKIP&)LUO<-I&hK)M(w__BqT z%zu*e`J;s;$=>!xoMex3qmpDVcO&U!#W`M*X|_;aB5Q$IE8)O_>=6LYh*i=6t$i8C)tJAh!aYRaDu@c zIJNNtaB5Q$IC1`z&rzZWFS`XvdwFQiMmaj)#UZ;VNgI_V*&QyBh|}y`N#N9`Byi$v z)Xm(T3BQ?2S~#kJ-%L?4Q&O%c_ziT!wHqEf<~ONsZnT%zEn_s3L7{`_2(-*G+(@|O zWJ`i(+m#fXp~%Ow@VeN%Q%&QsS-hMRY{yAgYP`%Cv64~-<-D<*iET*4S-w(|@oU&C z%&90TY%fz1q~kcv*$WZEdE;D3$jh9@nUZ3hk`HlO&UvJK$f3K!18wes-*AyomSkfJ zCB^3zVV7uLwmjfw_Zc2i5Tx)q(wBT0b$aLYB(`Xzm zLR8~6tAJBGjdOY`v#-??G|qYEoW|kfQH@*AMBIh*lkq2%6xNd|30}~K6ZF)^3m{!M V?g}4o;|0)@^@6AJO7hFy{{y;cX#oHL literal 0 HcmV?d00001 diff --git a/testdata/algo/scale_and_snap.gds b/testdata/algo/scale_and_snap.gds new file mode 100644 index 0000000000000000000000000000000000000000..9a1972426d0c755cf1a781557e720c41bce7e422 GIT binary patch literal 37590 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 literal 0 HcmV?d00001 From 988b1e563fde94756b9ffbcc2784bf8c65ff68fe Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Nov 2019 23:11:34 +0100 Subject: [PATCH 6/8] Added unit test for DeepRegion::snap --- src/db/unit_tests/dbDeepRegionTests.cc | 55 +++++++++++++++++++++++++ testdata/algo/deep_region_au27.gds | Bin 0 -> 126570 bytes 2 files changed, 55 insertions(+) create mode 100644 testdata/algo/deep_region_au27.gds diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 83b6be3fd..e8e012b42 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1490,6 +1490,61 @@ TEST(26_BreakoutCells) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au26.gds"); } +TEST(27_snap) +{ + { + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + r1.set_merged_semantics (false); + db::Region r2 = r1.snapped (19, 19); + + r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds"); + } + + { + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + r1.set_merged_semantics (false); + r1.snap (19, 19); + + r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds"); + } +} + TEST(100_Integration) { db::Layout ly; diff --git a/testdata/algo/deep_region_au27.gds b/testdata/algo/deep_region_au27.gds new file mode 100644 index 0000000000000000000000000000000000000000..aded77e85079244be8ef3216be16a4e4e672b1a0 GIT binary patch literal 126570 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 literal 0 HcmV?d00001 From 4a212e8db6b57ee7a217acdf55f23d22c543b56e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Nov 2019 23:33:54 +0100 Subject: [PATCH 7/8] Added tests for Region#scale_and_snap and Region#snap --- src/db/unit_tests/dbDeepRegionTests.cc | 147 +++++++++++++++++-------- src/db/unit_tests/dbRegion.cc | 104 +++++++++++++++++ testdata/algo/deep_region_au28.gds | Bin 0 -> 65750 bytes testdata/algo/region_au32.gds | Bin 0 -> 65750 bytes testdata/algo/region_au33.gds | Bin 0 -> 65750 bytes 5 files changed, 204 insertions(+), 47 deletions(-) create mode 100644 testdata/algo/deep_region_au28.gds create mode 100644 testdata/algo/region_au32.gds create mode 100644 testdata/algo/region_au33.gds diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index e8e012b42..cbe9a558c 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1490,59 +1490,112 @@ TEST(26_BreakoutCells) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au26.gds"); } -TEST(27_snap) +TEST(27a_snap) { + db::Layout ly; { - db::Layout ly; - { - std::string fn (tl::testsrc ()); - fn += "/testdata/algo/scale_and_snap.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); - r1.set_merged_semantics (false); - db::Region r2 = r1.snapped (19, 19); - - r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); - - CHECKPOINT(); - db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds"); + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + r1.set_merged_semantics (false); + db::Region r2 = r1.snapped (19, 19); + + r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds"); +} + +TEST(27b_snap) +{ + db::Layout ly; { - db::Layout ly; - { - std::string fn (tl::testsrc ()); - fn += "/testdata/algo/scale_and_snap.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); - r1.set_merged_semantics (false); - r1.snap (19, 19); - - r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); - - CHECKPOINT(); - db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds"); + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + r1.set_merged_semantics (false); + r1.snap (19, 19); + + r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds"); +} + +TEST(28a_snap) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + r1.set_merged_semantics (false); + db::Region r2 = r1.scaled_and_snapped (19, 2, 10, 19, 2, 10); + + r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds"); +} + +TEST(28b_snap) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + r1.set_merged_semantics (false); + r1.scale_and_snap (19, 2, 10, 19, 2, 10); + + r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds"); } TEST(100_Integration) diff --git a/src/db/unit_tests/dbRegion.cc b/src/db/unit_tests/dbRegion.cc index 9f1a4b40f..21ba05b60 100644 --- a/src/db/unit_tests/dbRegion.cc +++ b/src/db/unit_tests/dbRegion.cc @@ -28,6 +28,10 @@ #include "dbRegionProcessors.h" #include "dbEdgesUtils.h" #include "dbBoxScanner.h" +#include "dbReader.h" +#include "dbTestSupport.h" + +#include "tlStream.h" #include @@ -1391,6 +1395,106 @@ TEST(31) EXPECT_EQ (db::Region (db::Box (db::Point (0, 3999), db::Point (1001, 6000))).pull_overlapping (r).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)"); } +TEST(32a_snap) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1)); + r1.set_merged_semantics (false); + db::Region r2 = r1.snapped (19, 19); + + r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au32.gds"); +} + +TEST(32b_snap) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1)); + r1.set_merged_semantics (false); + r1.snap (19, 19); + + r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au32.gds"); +} + +TEST(33a_snap) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1)); + r1.set_merged_semantics (false); + db::Region r2 = r1.scaled_and_snapped (19, 2, 10, 19, 2, 10); + + r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds"); +} + +TEST(33b_snap) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/scale_and_snap.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); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1)); + r1.set_merged_semantics (false); + r1.scale_and_snap (19, 2, 10, 19, 2, 10); + + r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0))); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds"); +} + TEST(100_Processors) { db::Region r; diff --git a/testdata/algo/deep_region_au28.gds b/testdata/algo/deep_region_au28.gds new file mode 100644 index 0000000000000000000000000000000000000000..b7d0b6ef15e1ac33261a3303dc78f0097e275e09 GIT binary patch literal 65750 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 literal 0 HcmV?d00001 diff --git a/testdata/algo/region_au32.gds b/testdata/algo/region_au32.gds new file mode 100644 index 0000000000000000000000000000000000000000..f510c8dca2d52646f562c3e093c94d1cae76de13 GIT binary patch literal 65750 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 F^1srhbjkn# literal 0 HcmV?d00001 diff --git a/testdata/algo/region_au33.gds b/testdata/algo/region_au33.gds new file mode 100644 index 0000000000000000000000000000000000000000..bae4cd78ea91e63fbf59fe337f8e9ce922de9fee GIT binary patch literal 65750 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 literal 0 HcmV?d00001 From 1b84804d93bbe5a850afb2f13b76d04c10f2ee75 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Nov 2019 23:42:16 +0100 Subject: [PATCH 8/8] Updated changelog. --- Changelog | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index f45c73c56..71dab7f99 100644 --- a/Changelog +++ b/Changelog @@ -31,7 +31,21 @@ * Enhancement: %GITHUB%/issues/393 DRC syntax errors are now shown in their original code line of the DRC script. -* Enhancement: New Region#pull_* methods and DRC features +* Bugfix: %GITHUB%/issues/400 + Snap feature wasn't working for deep regions in certain use + cases. +* Enhancement: new "scale_and_snap" methods + These methods allow scaling and snapping of layouts. Scaling + is supported by a rational factor. After scaling, snapping can + be applied to an integer grid. There are two incarnations. + Region#scale_and_snap (or Region#scaled_and_snapped): this is + a flat implementation which allows anisotropic scaling/snapping + as well. + And there is Layout#scale_and_snap which is a fully + hierarchical scale-and-snap feature. The latter does not support + anisotropic scaling/snapping, but works hierarchically without + opening gaps. It operates on a top cell and on all layers. +* Enhancement: new Region#pull_* methods and DRC features "pull_*" is a class of methods that allows rehierarchisation of shapes. These methods act similar to "interacting", but the other way around: instead of delivering interacting