diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 50bb03d83..46af6c33b 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1447,6 +1447,15 @@ AsIfFlatRegion::add (const Region &other) const } } +void +AsIfFlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer); + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + shapes.insert (*p); + } +} + bool AsIfFlatRegion::equals (const Region &other) const { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index e9cedaaa8..b932903e4 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -201,6 +201,8 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + protected: void update_bbox (const db::Box &box); void invalidate_bbox (); diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index 66cb0a01c..c50001a0c 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -179,6 +179,17 @@ public: return m_b2a_mapping; } + /** + * @brief Creates mappings for all cells not mapped yet + * + * When constructing a cell mapping by explicit mapping (map (a, b)), some cells may be + * left unmapped. This method allows creating mappings for these missing cells by adding + * new cells and the corresponding instances into the target layout_a. + * + * The returned vector lists the new cells. + */ + 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); + private: void extract_unique (std::map >::const_iterator cand, std::map &unique_mapping, @@ -187,8 +198,6 @@ private: void dump_mapping (const std::map > &candidates, const db::Layout &layout_a, const db::Layout &layout_b); - 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); - std::map m_b2a_mapping; }; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 78fa48d95..d5c1cbbfa 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -31,17 +31,73 @@ namespace db { +namespace +{ + /** + * @brief An iterator delegate for the deep region + * TODO: this is kind of redundant with OriginalLayerIterator .. + */ + class DB_PUBLIC DeepRegionIterator + : public RegionIteratorDelegate + { + public: + typedef db::Polygon value_type; + + DeepRegionIterator (const db::RecursiveShapeIterator &iter) + : m_iter (iter) + { + set (); + } + + virtual bool at_end () const + { + return m_iter.at_end (); + } + + virtual void increment () + { + ++m_iter; + set (); + } + + virtual const value_type *get () const + { + return &m_polygon; + } + + virtual RegionIteratorDelegate *clone () const + { + return new DeepRegionIterator (*this); + } + + private: + friend class Region; + + db::RecursiveShapeIterator m_iter; + mutable value_type m_polygon; + + void set () const + { + if (! m_iter.at_end ()) { + m_iter.shape ().polygon (m_polygon); + m_polygon.transform (m_iter.trans (), false); + } + } + }; + +} + // ------------------------------------------------------------------------------------------------------------- // DeepRegion implementation DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) - : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)) + : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons (false) { init (); } DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count) - : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)) + : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons (false) { init (); @@ -223,5 +279,11 @@ DeepRegion::ensure_merged_polygons_valid () const } } +void +DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + m_deep_layer.insert_into (layout, into_cell, into_layer); +} + } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 415973bf8..147162aa0 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -32,57 +32,7 @@ namespace db { /** - * @brief An iterator delegate for the deep region - */ -class DB_PUBLIC DeepRegionIterator - : public RegionIteratorDelegate -{ -public: - typedef db::Polygon value_type; - - DeepRegionIterator (const db::RecursiveShapeIterator &iter) - : m_iter (iter) - { - set (); - } - - virtual bool at_end () const - { - return m_iter.at_end (); - } - - virtual void increment () - { - ++m_iter; - set (); - } - - virtual const value_type *get () const - { - return &m_tmp; - } - - virtual RegionIteratorDelegate *clone () const - { - return new DeepRegionIterator (*this); - } - -private: - friend class Region; - - db::RecursiveShapeIterator m_iter; - mutable value_type m_tmp; - - void set () const - { - if (! m_iter.at_end ()) { - m_iter->polygon (m_tmp); - } - } -}; - -/** - * @brief A flat, polygon-set delegate + * @brief A deep, polygon-set delegate */ class DB_PUBLIC DeepRegion : public AsIfFlatRegion @@ -120,6 +70,8 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + protected: virtual void merged_semantics_changed (); diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index e9a317ae9..b17a15b39 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -22,6 +22,9 @@ #include "dbDeepShapeStore.h" +#include "dbCellMapping.h" +#include "dbLayoutUtils.h" + #include "tlTimer.h" namespace db @@ -47,16 +50,57 @@ DeepLayer::DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int l // .. nothing yet .. } -// ---------------------------------------------------------------------------------- - -DeepShapeStore::DeepShapeStore () +DeepLayer::~DeepLayer () { // .. nothing yet .. } +void +DeepLayer::insert_into (db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + check_dss (); + const_cast (mp_store.get ())->insert (*this, into_layout, into_cell, into_layer); +} + +db::Layout * +DeepLayer::layout () +{ + check_dss (); + return mp_store->layout (m_layout); +} + +const db::Layout * +DeepLayer::layout () const +{ + check_dss (); + return const_cast (mp_store.get ())->layout (m_layout); +} + +void +DeepLayer::check_dss () const +{ + if (mp_store.get () == 0) { + throw tl::Exception (tl::to_string (tr ("Heap lost: the DeepShapeStore container no longer exists"))); + } +} + +// ---------------------------------------------------------------------------------- + +static size_t s_instance_count = 0; + +DeepShapeStore::DeepShapeStore () +{ + ++s_instance_count; +} + DeepShapeStore::~DeepShapeStore () { - // .. nothing yet .. + --s_instance_count; +} + +size_t DeepShapeStore::instance_count () +{ + return s_instance_count; } DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) @@ -108,5 +152,86 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator return DeepLayer (this, layout_index, layer_index); } +void +DeepShapeStore::insert (const DeepLayer &deep_layer, db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) +{ + const db::Layout *source_layout = deep_layer.layout (); + if (source_layout->begin_top_down () == source_layout->end_top_cells ()) { + // empty source - nothing to do. + return; + } + + db::cell_index_type source_top = *source_layout->begin_top_down(); + + db::HierarchyBuilder &original_builder = m_builders [deep_layer.layout_index ()]; + + // derive a cell mapping for source to target. We employ a + + DeliveryMappingCacheKey key (deep_layer.layout_index (), into_layout, into_cell); + + std::map::iterator cm = m_delivery_mapping_cache.find (key); + if (cm == m_delivery_mapping_cache.end ()) { + + cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first; + + 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 + // provided inside the original hierarchy builders. They list the source cells and the target cells + // create from them. We need to consider however, that the hierarchy builder is allowed to create + // variants which we cannot map. + + bool any_skipped = false; + + for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ++m) { + + HierarchyBuilder::cell_map_type::const_iterator mm = m; + ++mm; + bool skip = false; + while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) { + // we have cell variants and cannot simply map + ++mm; + ++m; + skip = true; + } + + if (! skip) { + cm->second.map (m->first.first, m->second); + } else { + any_skipped = true; + } + + } + + if (any_skipped) { + // Add new cells for the variants + cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top); + } + + } else if (into_layout->cells () == 1) { + + // Another simple case is mapping into an empty (or single-top-cell-only) layout, where we can use "create_from_single_full". + cm->second.create_single_mapping_full (*into_layout, into_cell, *source_layout, source_top); + + } else { + + cm->second.create_from_geometry_full (*into_layout, into_cell, *source_layout, source_top); + + } + + } + + // Actually copy the shapes + + db::ICplxTrans trans (source_layout->dbu () / into_layout->dbu ()); + + std::map lm; + lm.insert (std::make_pair (deep_layer.layer (), into_layer)); + + std::vector source_cells; + source_cells.push_back (source_top); + db::copy_shapes (*into_layout, *source_layout, trans, source_cells, cm->second.table (), lm); +} + } diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index c08bfb44d..227213d36 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -31,6 +31,7 @@ #include "dbLayout.h" #include "dbRecursiveShapeIterator.h" #include "dbHierarchyBuilder.h" +#include "gsiObject.h" #include #include @@ -87,6 +88,19 @@ public: return m_layer; } + /** + * @brief Gets the layout index + */ + unsigned int layout_index () const + { + return m_layout; + } + + /** + * @brief Inserts the layer into the given layout, starting from the given cell and into the given layer + */ + void insert_into (Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) const; + private: friend class DeepShapeStore; @@ -95,6 +109,8 @@ private: */ DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer); + void check_dss () const; + tl::weak_ptr mp_store; unsigned int m_layout; unsigned int m_layer; @@ -121,7 +137,7 @@ struct DB_PUBLIC RecursiveShapeIteratorCompareForTargetHierarchy * algorithms for doing the preparation and transfer. */ class DB_PUBLIC DeepShapeStore - : public tl::Object + : public tl::Object, public gsi::ObjectBase { public: /** @@ -146,7 +162,24 @@ public: */ DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16); + /** + * @brief Inserts the deep layer's into some target layout + */ + void insert (const DeepLayer &layer, db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer); + + /** + * @brief For testing + */ + static size_t instance_count (); + private: + friend class DeepLayer; + + db::Layout *layout (unsigned int n) + { + return &m_layouts [n]; + } + typedef std::map layout_map_type; // no copying @@ -156,9 +189,47 @@ private: tl::stable_vector m_layouts; tl::stable_vector m_builders; layout_map_type m_layout_map; + + struct DeliveryMappingCacheKey + { + // NOTE: we shouldn't keep pointers here as the layouts may get deleted and recreated with the same address. + // But as we don't access these objects that's fairly safe. + DeliveryMappingCacheKey (unsigned int _from_index, db::Layout *_into_layout, db::cell_index_type _into_cell) + : from_index (_from_index), into_layout (_into_layout), into_cell (_into_cell) + { + // .. nothing yet .. + } + + bool operator< (const DeliveryMappingCacheKey &other) const + { + if (from_index != other.from_index) { + return from_index < other.from_index; + } + if (into_layout != other.into_layout) { + return into_layout < other.into_layout; + } + return into_cell m_delivery_mapping_cache; }; } +namespace tl +{ + + // disable copying of the deep shape store object + template <> struct type_traits : public type_traits { + typedef tl::false_tag has_copy_constructor; + }; + +} + #endif diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 696853af1..da0327ba0 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -120,6 +120,8 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; + virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { } + private: EmptyRegion &operator= (const EmptyRegion &other); }; diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index 411dff8e5..ae1868c23 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -362,6 +362,11 @@ const db::RecursiveShapeIterator *FlatRegion::iter () const return 0; } +void FlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + layout->cell (into_cell).shapes (into_layer).insert (m_polygons); +} + void FlatRegion::insert (const db::Box &box) { diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index 72e712a6d..cbae0ba71 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -109,6 +109,8 @@ public: virtual size_t size () const; virtual bool is_merged () const; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + virtual RegionDelegate *merged_in_place (); virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); virtual RegionDelegate *merged () const; diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 383f2b685..c07523fb4 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -62,16 +62,19 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter if (iter1.has_complex_region () && iter1.complex_region () != iter2.complex_region ()) { return iter1.complex_region () < iter2.complex_region () ? -1 : 1; } + if (iter1.region () != iter2.region ()) { + return iter1.region () < iter2.region () ? -1 : 1; + } if (iter1.multiple_layers () != iter2.multiple_layers ()) { return iter1.multiple_layers () < iter2.multiple_layers () ? -1 : 1; } if (iter1.multiple_layers ()) { if (iter1.layers () != iter2.layers ()) { - return iter1.layers () < iter2.layers (); + return iter1.layers () < iter2.layers () ? -1 : 1; } } else { if (iter1.layer () != iter2.layer ()) { - return iter1.layer () < iter2.layer (); + return iter1.layer () < iter2.layer () ? -1 : 1; } } } @@ -161,9 +164,9 @@ void HierarchyBuilder::begin (const RecursiveShapeIterator *iter) { if (m_initial_pass) { - m_ref_iter = *iter; + m_source = *iter; } else { - tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_ref_iter, *iter) == 0); + tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_source, *iter) == 0); } m_cell_stack.clear (); diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index c982ec384..37176b340 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -41,7 +41,7 @@ namespace db * This function will return -1, 0 or 1 depending on whether the two iterators * can be used with the same builder (0) or whether they are less (-1) or greater (1). */ -int compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2); +int DB_PUBLIC compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2); /** * @brief A class to receive shapes from the hierarchy builder @@ -199,18 +199,50 @@ public: void reset (); /** - * @brief Gets the initial cell the builder produced + * @brief Gets the initial cell the builder produced in the target layout */ db::Cell *initial_cell () { return mp_initial_cell; } + /** + * @brief Gets the target layout + */ + db::Layout *target () + { + return mp_target.get (); + } + + /** + * @brief Gets the recursive shape iterator the data was taken from + */ + const db::RecursiveShapeIterator &source () const + { + return m_source; + } + + /** + * @brief Gets the iterator for the cell map + */ + cell_map_type::const_iterator begin_cell_map () const + { + return m_cell_map.begin (); + } + + /** + * @brief Gets the iterator for the cell map (end) + */ + cell_map_type::const_iterator end_cell_map () const + { + return m_cell_map.end (); + } + private: tl::weak_ptr mp_target; HierarchyBuilderShapeReceiver *mp_pipe; bool m_initial_pass; - db::RecursiveShapeIterator m_ref_iter; + db::RecursiveShapeIterator m_source; cell_map_type m_cell_map; std::set m_cells_seen; cell_map_type::const_iterator m_cm_entry; diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 0380deb12..91fd9f995 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -31,6 +31,7 @@ #include "dbLibraryProxy.h" #include "dbLibraryManager.h" #include "dbLibrary.h" +#include "dbRegion.h" #include "tlTimer.h" #include "tlLog.h" #include "tlInternational.h" @@ -638,6 +639,12 @@ Layout::delete_cell (cell_index_type id) } } +void +Layout::insert (db::cell_index_type cell, int layer, const db::Region ®ion) +{ + region.insert_into (this, cell, layer); +} + void Layout::flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::ICplxTrans &t, int levels) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 8ebaf1fbc..eb48b7727 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -61,6 +61,7 @@ class Library; class LibraryProxy; class CellMapping; class LayerMapping; +class Region; template class generic_repository; typedef generic_repository GenericRepository; @@ -1090,6 +1091,15 @@ public: */ void flatten (db::Cell &cell, int levels, bool prune = false); + /** + * @brief Inserts a region (potentially hierarchical) into the given cell and layer + * + * If the region is flat (conceptionally), it will be put into the cell. + * If the region is hierarchical, a cell hierarchy will be built below the + * given cell. + */ + void insert (db::cell_index_type cell, int layer, const db::Region ®ion); + /** * @brief Delete a cell plus all subcells * diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 4a4cc4e9e..c2969f45e 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1685,6 +1685,14 @@ public: return mp_delegate->less (other); } + /** + * @brief Less operator + */ + void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const + { + return mp_delegate->insert_into (layout, into_cell, into_layer); + } + private: friend class Edges; friend class EdgePairs; diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index ecf10d292..626317f50 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -179,6 +179,8 @@ public: virtual bool equals (const Region &other) const = 0; virtual bool less (const Region &other) const = 0; + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const = 0; + protected: const std::string &progress_desc () const { diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 9784a56af..220fd40f8 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1356,7 +1356,6 @@ static std::vector copy_tree (db::Cell *cell, const db::Cel throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); } - db::PropertyMapper pm (*target_layout, *source_layout); db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ()); db::CellMapping cm; @@ -1387,7 +1386,6 @@ static void copy_tree_shapes2 (db::Cell *cell, const db::Cell &source_cell, cons throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); } - db::PropertyMapper pm (*target_layout, *source_layout); db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ()); db::LayerMapping lm; @@ -1413,7 +1411,6 @@ static void copy_tree_shapes3 (db::Cell *cell, const db::Cell &source_cell, cons throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout"))); } - db::PropertyMapper pm (*target_layout, *source_layout); db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ()); std::vector source_cells; diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 48c60db98..537cd5ada 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -32,6 +32,7 @@ #include "dbLibraryManager.h" #include "dbPCellDeclaration.h" #include "dbHash.h" +#include "dbRegion.h" #include "tlStream.h" namespace gsi @@ -1179,6 +1180,18 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.20.\n" ) + + gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, unsigned int, const db::Region &)) &db::Layout::insert, + gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), + "@brief Inserts a region into the given cell and layer\n" + "If the region is (conceptionally) a flat region, it will be inserted into the cell's shapes " + "list as a flat sequence of polygons.\n" + "If the region is a deep (hierarchical) region, it will create a subhierarchy below the given " + "cell and it's shapes will be put into the respective cells. Suitable subcells will be picked " + "for inserting the shapes. If a hierarchy already exists below the given cell, the algorithm will " + "try to reuse this hierarchy.\n" + "\n" + "This method has been introduced in version 0.26.\n" + ) + gsi::method_ext ("flatten", &flatten, "@brief Flattens the given cell\n" "@args cell_index, levels, prune\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 7cb106fa8..12df8eeee 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -26,6 +26,8 @@ #include "dbPolygonTools.h" #include "dbLayoutUtils.h" #include "dbShapes.h" +#include "dbDeepShapeStore.h" +#include "dbRegion.h" #include "tlGlobPattern.h" #include @@ -213,6 +215,11 @@ static db::Region *new_si (const db::RecursiveShapeIterator &si) return new db::Region (si); } +static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) +{ + return new db::Region (si, dss, area_ratio, max_vertex_count); +} + static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) { return new db::Region (si, trans); @@ -712,6 +719,25 @@ static Container *decompose_trapezoids (const db::Region *r, int mode) int td_simple (); int po_any (); +Class decl_DeepShapeStore ("db", "DeepShapeStore", + method ("instance_count", db::DeepShapeStore::instance_count, "@hide"), + "@brief An opaque layout heap for the deep region processor\n" + "\n" + "This class is used for keeping intermediate, hierarchical data for the " + "deep region processor. It is used in conjunction with the region " + "constructor to create a deep (hierarchical) region." + "\n" + "@code\n" + "layout = ... # a layout\n" + "layer = ... # a layer\n" + "cell = ... # a cell (initial cell for the deep region)\n" + "dss = RBA::DeepShapeStore::new\n" + "region = RBA::Region::new(cell.begin(layer), dss)\n" + "@/code\n" + "\n" + "This class has been introduced in version 0.26.\n" +); + Class decl_Region ("db", "Region", constructor ("new", &new_v, "@brief Default constructor\n" @@ -789,6 +815,22 @@ Class decl_Region ("db", "Region", "r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n" "@/code\n" ) + + constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("area_ratio", 3.0), gsi::arg ("max_vertex_count", size_t (16)), + "@brief Constructor for a deep region from a hierarchical shape set\n" + "\n" + "This constructor creates a hierarchical region. Use a \\DeepShapeStore object to " + "supply the hierarchical heap. See \\DeepShapeStore for more details.\n" + "\n" + "'area_ratio' and 'max_vertex' supply two optimization parameters which control how " + "big polygons are split to reduce the region's polygon complexity.\n" + "\n" + "@param shape_iterator The recursive shape iterator which delivers the hierarchy to take\n" + "@param deep_shape_store The hierarchical heap (see there)\n" + "@param area_ratio The maximum ratio of bounding box to polygon area before polygons are split\n" + "@param" + "\n" + "This method has been introduced in version 0.26.\n" + ) + constructor ("new", &new_texts, gsi::arg("shape_iterator"), gsi::arg ("expr"), gsi::arg ("as_pattern", true), "@brief Constructor from a text set\n" "\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc new file mode 100644 index 000000000..a5e582579 --- /dev/null +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -0,0 +1,113 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbHierarchyBuilder.h" +#include "dbReader.h" +#include "dbTestSupport.h" +#include "dbRegion.h" +#include "dbDeepShapeStore.h" +#include "tlUnitTest.h" +#include "tlStream.h" + +TEST(1) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + + db::DeepShapeStore dss; + db::Layout target; + + // deliberately using vector to force reallocation ... + std::vector regions; + std::vector target_layers; + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + unsigned int li1 = (*li).first; + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1); + target_layers.push_back (target.insert_layer (*(*li).second)); + + regions.push_back (db::Region (iter, dss)); + + } + + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + for (std::vector::const_iterator r = regions.begin (); r != regions.end (); ++r) { + target.insert (target_top_cell_index, target_layers [r - regions.begin ()], *r); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au1.gds"); +} + +TEST(2) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_region_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + + db::DeepShapeStore dss; + db::Layout target; + + // deliberately using vector to force reallocation ... + std::vector > regions; + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + unsigned int li1 = (*li).first; + unsigned int tl = target.insert_layer (*(*li).second); + + db::RecursiveShapeIterator iter1 (ly, ly.cell (top_cell_index), li1, db::Box (2000, -1000, 6000, 4000)); + regions.push_back (std::make_pair (db::Region (iter1, dss), tl)); + + db::RecursiveShapeIterator iter2 (ly, ly.cell (top_cell_index), li1, db::Box (14000, 0, 20000, 3000)); + regions.push_back (std::make_pair (db::Region (iter2, dss), tl)); + + } + + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + for (std::vector >::const_iterator r = regions.begin (); r != regions.end (); ++r) { + target.insert (target_top_cell_index, r->second, r->first); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au1.gds"); +} + diff --git a/src/db/unit_tests/dbHierarchyBuilderTests.cc b/src/db/unit_tests/dbHierarchyBuilderTests.cc index 1dffa2d9d..84a7394f5 100644 --- a/src/db/unit_tests/dbHierarchyBuilderTests.cc +++ b/src/db/unit_tests/dbHierarchyBuilderTests.cc @@ -335,3 +335,135 @@ TEST(4_ComplexRegionAndLayoutWithClip) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au4a.gds"); } +TEST(5_CompareRecursiveShapeIterators) +{ + db::Layout ly; + db::cell_index_type ci = ly.add_cell ("TOP"); + db::cell_index_type ci1 = ly.add_cell ("TOPA"); + + db::Layout ly2; + db::cell_index_type ci2 = ly2.add_cell ("TOP"); + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + db::RecursiveShapeIterator iter2 (ly2, ly2.cell (ci2), 0); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci1), 0); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 1); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + std::vector ll1; + ll1.push_back (100); + ll1.push_back (101); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), ll1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 1); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0); + iter1.max_depth (1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0); + iter2.max_depth (1); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + + iter2.max_depth (2); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 1, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + std::vector ll1; + ll1.push_back (100); + ll1.push_back (101); + + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), ll1, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3001)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + r1.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, db::Box (0, 1000, 2000, 3000)); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + r1.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::Region r2; + r2.insert (db::Box (0, 1000, 2000, 3000)); + r2.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, r2); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2), 0); + } + + { + db::Region r1; + r1.insert (db::Box (0, 1000, 2000, 3000)); + r1.insert (db::Box (0, 4000, 2000, 6000)); + db::RecursiveShapeIterator iter1 (ly, ly.cell (ci), 0, r1); + db::Region r2; + r2.insert (db::Box (0, 1000, 2000, 3000)); + r2.insert (db::Box (0, 4000, 2000, 6001)); + db::RecursiveShapeIterator iter2 (ly, ly.cell (ci), 0, r2); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != 0, true); + EXPECT_EQ (db::compare_iterators_with_respect_to_target_hierarchy (iter1, iter2) != db::compare_iterators_with_respect_to_target_hierarchy (iter2, iter1), true); + } +} + diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index e6b19cd84..5c0d7a9a4 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -55,7 +55,8 @@ SOURCES = \ dbSaveLayoutOptionsTests.cc \ dbHierarchyBuilderTests.cc \ dbRecursiveShapeIteratorTests.cc \ - dbHierProcessorTests.cc + dbHierProcessorTests.cc \ + dbDeepRegionTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/testdata/algo/deep_region_au1.gds b/testdata/algo/deep_region_au1.gds new file mode 100644 index 000000000..bfa6b5bde Binary files /dev/null and b/testdata/algo/deep_region_au1.gds differ diff --git a/testdata/algo/deep_region_l1.gds b/testdata/algo/deep_region_l1.gds new file mode 100644 index 000000000..fa837f4e2 Binary files /dev/null and b/testdata/algo/deep_region_l1.gds differ diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 01d4ea556..3bce9e803 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -769,6 +769,35 @@ class DBRegion_TestClass < TestBase end + # deep region tests + def test_deep1 + + # construction/destruction magic ... + GC.start + assert_equal(RBA::DeepShapeStore::instance_count, 0) + dss = RBA::DeepShapeStore::new + dss._create + assert_equal(RBA::DeepShapeStore::instance_count, 1) + dss = nil + GC.start + assert_equal(RBA::DeepShapeStore::instance_count, 0) + + dss = RBA::DeepShapeStore::new + ly = RBA::Layout::new + ly.read(File.join($ut_testsrc, "testdata", "algo", "deep_region_l1.gds")) + l1 = ly.layer(1, 0) + r = RBA::Region::new(ly.top_cell.begin_shapes_rec(l1), dss) + rf = RBA::Region::new(ly.top_cell.begin_shapes_rec(l1)) + + assert_equal(r.area, 53120000) + assert_equal(rf.area, 53120000) + + # force destroy, so the unit tests pass on the next iteration + dss._destroy + assert_equal(RBA::DeepShapeStore::instance_count, 0) + + end + end load("test_epilogue.rb")