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 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/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..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 (); } } @@ -355,7 +468,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); @@ -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 f8333c6c3..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,39 @@ 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; - } - } +/** + * @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); + + 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; }; /** @@ -225,6 +193,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 +206,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..6a1539e95 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 @@ -917,22 +920,28 @@ 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; 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; + } } + m = mm; + } } else if (into_layout->cells () == 1) { @@ -948,7 +957,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/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/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; diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index e0452ea43..580c4066d 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,125 @@ 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); + 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); + + } + + 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); + 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))); + } 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..2c6cbd1ae 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. + */ +DB_PUBLIC 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..e2b975f2f 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 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 + 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 9e082f582..dd59d41f6 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) 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 + 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 ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy); + } // 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 " diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index a9f2c84dd..cbe9a558c 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1490,6 +1490,114 @@ TEST(26_BreakoutCells) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au26.gds"); } +TEST(27a_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"); +} + +TEST(27b_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.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) { db::Layout ly; @@ -1641,3 +1749,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/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/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_au27.gds b/testdata/algo/deep_region_au27.gds new file mode 100644 index 000000000..aded77e85 Binary files /dev/null and b/testdata/algo/deep_region_au27.gds differ diff --git a/testdata/algo/deep_region_au28.gds b/testdata/algo/deep_region_au28.gds new file mode 100644 index 000000000..b7d0b6ef1 Binary files /dev/null and b/testdata/algo/deep_region_au28.gds differ diff --git a/testdata/algo/deep_region_au400a.gds b/testdata/algo/deep_region_au400a.gds new file mode 100644 index 000000000..5aa551f07 Binary files /dev/null and b/testdata/algo/deep_region_au400a.gds differ diff --git a/testdata/algo/deep_region_au400b.gds b/testdata/algo/deep_region_au400b.gds new file mode 100644 index 000000000..5aa551f07 Binary files /dev/null and b/testdata/algo/deep_region_au400b.gds differ diff --git a/testdata/algo/deep_region_au400c.gds b/testdata/algo/deep_region_au400c.gds new file mode 100644 index 000000000..935193490 Binary files /dev/null and b/testdata/algo/deep_region_au400c.gds differ diff --git a/testdata/algo/layout_utils_au_sns1.gds b/testdata/algo/layout_utils_au_sns1.gds new file mode 100644 index 000000000..372770c61 Binary files /dev/null and b/testdata/algo/layout_utils_au_sns1.gds differ diff --git a/testdata/algo/layout_utils_au_sns2.gds b/testdata/algo/layout_utils_au_sns2.gds new file mode 100644 index 000000000..1a69e3ee5 Binary files /dev/null and b/testdata/algo/layout_utils_au_sns2.gds differ diff --git a/testdata/algo/layout_utils_au_sns3.gds b/testdata/algo/layout_utils_au_sns3.gds new file mode 100644 index 000000000..d6bc61269 Binary files /dev/null and b/testdata/algo/layout_utils_au_sns3.gds differ diff --git a/testdata/algo/region_au32.gds b/testdata/algo/region_au32.gds new file mode 100644 index 000000000..f510c8dca Binary files /dev/null and b/testdata/algo/region_au32.gds differ diff --git a/testdata/algo/region_au33.gds b/testdata/algo/region_au33.gds new file mode 100644 index 000000000..bae4cd78e Binary files /dev/null and b/testdata/algo/region_au33.gds differ diff --git a/testdata/algo/scale_and_snap.gds b/testdata/algo/scale_and_snap.gds new file mode 100644 index 000000000..9a1972426 Binary files /dev/null and b/testdata/algo/scale_and_snap.gds differ