diff --git a/src/db/db/db.pro b/src/db/db/db.pro index ff156a235..f32306b99 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -136,7 +136,8 @@ SOURCES = \ dbFlatEdgePairs.cc \ dbOriginalLayerEdgePairs.cc \ dbEdgePairsDelegate.cc \ - dbDeepShapeStore.cc + dbDeepShapeStore.cc \ + dbHierarchyBuilder.cc HEADERS = \ dbArray.h \ @@ -242,7 +243,8 @@ HEADERS = \ dbFlatEdgePairs.h \ dbOriginalLayerEdgePairs.h \ dbEdgePairsDelegate.h \ - dbDeepShapeStore.h + dbDeepShapeStore.h \ + dbHierarchyBuilder.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index e51bd5a3a..abb1469e8 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -21,4 +21,39 @@ */ -// ... +#include "dbDeepShapeStore.h" + +namespace db +{ + +DeepLayer::DeepLayer (const DeepLayer &x) + : mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer) +{ + // .. nothing yet .. +} + +DeepLayer::DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer) + : mp_store (store), m_layout (layout), m_layer (layer) +{ + // .. nothing yet .. +} + + + +DeepShapeStore::DeepShapeStore () +{ + // @@@ +} + +DeepShapeStore::~DeepShapeStore () +{ + // @@@ +} + +DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) +{ + return DeepLayer (0, 0, 0); // @@@ +} + +} + diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 2a32c2439..f76805fd1 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -30,6 +30,9 @@ #include "dbLayout.h" #include "dbRecursiveShapeIterator.h" +#include +#include + namespace db { class DeepShapeStore; @@ -81,9 +84,6 @@ private: */ DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer); - unsigned int layout () const { return m_layout; } - unsigned int layer () const { return m_layer; } - tl::weak_ptr mp_store; unsigned int m_layout; unsigned int m_layer; @@ -92,7 +92,7 @@ private: /** * @brief The "deep shape store" is a working model for the hierarchical ("deep") processor * - * The deep shape store keep temporary data for the deep shape processor. + * The deep shape store keeps temporary data for the deep shape processor. * It mainly consists of layout objects holding the hierarchy trees and layers * for the actual shapes. * @@ -110,10 +110,28 @@ public: */ DeepShapeStore (); + /** + * @brief The destructor + */ + ~DeepShapeStore (); + + /** + * @brief Inserts a polygon layer into the deep shape store + * + * This method will create a new layer inside the deep shape store as a + * working copy of the original layer. Preparation involves re-shaping + * the polygons so their bounding box is a better approximation and the + * polygon complexity is reduced. For this, the polygons are split + * into parts satisfying the area ratio (bounding box vs. polygon area) + * and maximum vertex count constraints. + */ + DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16); + private: // no copying DeepShapeStore (const DeepShapeStore &); DeepShapeStore &operator= (const DeepShapeStore &); + }; } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 388da34e3..be5945412 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -24,10 +24,13 @@ #include "dbHierarchyBuilder.h" #include "dbClip.h" #include "dbRegion.h" +#include "dbPolygonTools.h" namespace db { +static HierarchyBuilderShapeInserter def_inserter; + // ------------------------------------------------------------------------------------------- int @@ -78,104 +81,82 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter // ------------------------------------------------------------------------------------------- -static bool is_outside (const db::Box &obj, const std::set ®ion) -{ - if (region.empty ()) { - return false; - } - - for (std::set::const_iterator b = region.begin (); b != region.end (); ++b) { - if (obj.touches (*b)) { - return false; - } - } - - return true; -} - -static bool is_inside (const db::Box &obj, const std::set ®ion) -{ - if (region.empty ()) { - return true; - } - - for (std::set::const_iterator b = region.begin (); b != region.end (); ++b) { - if (obj.inside (*b)) { - return true; - } - } - - if (is_outside (obj, region)) { - return false; - } else { - - // TODO: basically a detailed analysis is required here - return false; - - } -} - /** * @brief Computes the clip variant (a box set) from a cell bbox, a region and a complex region (optional) */ -static std::set compute_clip_variant (const db::Box &cell_bbox, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region) +static std::pair > compute_clip_variant (const db::Box &cell_bbox, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region) { + if (region == db::Box::world ()) { + return std::make_pair (true, std::set ()); + } + + db::ICplxTrans trans_inv (trans.inverted ()); + db::Box region_in_cell = region.transformed (trans_inv); + std::set clip_variant; - if (region != db::Box::world () && ! cell_bbox.inside (region)) { + if (! cell_bbox.overlaps (region_in_cell)) { + // an empty clip variant should not happen, but who knows + return std::make_pair (false, std::set ()); + } - db::Box rect_box = region & cell_bbox; + db::Box rect_box = region_in_cell & cell_bbox; - if (complex_region) { + if (complex_region) { - for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (rect_box, db::box_convert ()); ! cr.at_end (); ++cr) { - if (rect_box.overlaps (*cr)) { - clip_variant.insert (rect_box * *cr); - } + for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (region, db::box_convert ()); ! cr.at_end (); ++cr) { + db::Box cr_in_cell = (*cr).transformed (trans_inv); + if (rect_box.overlaps (cr_in_cell)) { + clip_variant.insert (rect_box * cr_in_cell); } - - if (clip_variant.empty ()) { - // an empty clip variant should not happen, but who knows - clip_variant.insert (db::Box ()); - } - - } else { - clip_variant.insert (rect_box); } + if (clip_variant.empty ()) { + // an empty clip variant should not happen, but who knows + return std::make_pair (false, std::set ()); + } + + } else { + clip_variant.insert (rect_box); } - return clip_variant; + return std::make_pair (true, clip_variant); } -static void insert_clipped (const db::Box &box, const std::set &clip, db::Shapes &shapes) +HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, HierarchyBuilderShapeReceiver *pipe) + : mp_target (target), m_initial_pass (true), m_target_layer (target_layer) { - for (std::set::const_iterator b = clip.begin (); b != clip.end (); ++b) { - db::Box bb = *b & box; - if (! bb.empty ()) { - shapes.insert (bb); - } - } + mp_pipe = pipe ? pipe : &def_inserter; } -static void insert_clipped (const db::Polygon &poly, const std::set &clip, db::Shapes &shapes) +HierarchyBuilder::HierarchyBuilder (db::Layout *target, HierarchyBuilderShapeReceiver *pipe) + : mp_target (target), m_initial_pass (true), m_target_layer (0) { - // TODO: is this good way to clip a polygon at a complex boundary? - for (std::set::const_iterator b = clip.begin (); b != clip.end (); ++b) { - std::vector clipped_poly; - db::clip_poly (poly, *b, clipped_poly); - for (std::vector::const_iterator p = clipped_poly.begin (); p != clipped_poly.end (); ++p) { - shapes.insert (*p); - } - } + mp_pipe = pipe ? pipe : &def_inserter; } - -HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, bool clip_shapes) - : mp_target (target), m_clip_shapes (clip_shapes), m_initial_pass (true), m_target_layer (target_layer) +HierarchyBuilder::~HierarchyBuilder () { // .. nothing yet .. } +void +HierarchyBuilder::set_shape_receiver (HierarchyBuilderShapeReceiver *pipe) +{ + mp_pipe = pipe; +} + +void +HierarchyBuilder::reset () +{ + m_initial_pass = true; + mp_initial_cell = 0; + + m_cell_map.clear (); + m_cells_seen.clear (); + m_cell_stack.clear (); + m_cm_entry = cell_map_type::const_iterator (); +} + void HierarchyBuilder::begin (const RecursiveShapeIterator *iter) { @@ -185,20 +166,32 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter) tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_ref_iter, *iter) == 0); } - m_cells_seen.clear (); - m_cm_entry = cell_map_type::const_iterator (); - m_cell_stack.clear (); + m_cells_seen.clear (); + + std::pair > key (iter->top_cell ()->cell_index (), std::set ()); + m_cm_entry = m_cell_map.find (key); + if (m_cm_entry == m_cell_map.end ()) { + + db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first)); + m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first; + + } + + db::Cell &new_top = mp_target->cell (m_cm_entry->second); + m_cells_seen.insert (key); - db::Cell &new_top = mp_target->cell (mp_target->add_cell (iter->layout ()->cell_name (iter->top_cell ()->cell_index ()))); m_cell_stack.push_back (&new_top); } void HierarchyBuilder::end (const RecursiveShapeIterator * /*iter*/) { + tl_assert (m_cell_stack.size () == 1); + m_initial_pass = false; m_cells_seen.clear (); + mp_initial_cell = m_cell_stack.back (); m_cell_stack.pop_back (); } @@ -217,7 +210,7 @@ HierarchyBuilder::leave_cell (const RecursiveShapeIterator * /*iter*/, const db: m_cell_stack.pop_back (); } -bool +HierarchyBuilder::new_inst_mode HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) { if (all) { @@ -238,67 +231,296 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn } - return (m_cells_seen.find (key) == m_cells_seen.end ()); + // To see the cell once, use NI_single. If we did see the cell already, skip the whole instance array. + return (m_cells_seen.find (key) == m_cells_seen.end ()) ? NI_single : NI_skip; } else { - // iterate by instance array members - return true; + + // Iterate by instance array members + return NI_all; + } } bool -HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region) +HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all) { - db::Box cell_bbox = iter->layout ()->cell (inst.object ().cell_index ()).bbox (); - std::set clip_variant = compute_clip_variant (cell_bbox, region, complex_region); + if (all) { - std::pair > key (inst.object ().cell_index (), clip_variant); - m_cm_entry = m_cell_map.find (key); + return true; - if (m_initial_pass) { + } else { - if (m_cm_entry == m_cell_map.end ()) { - std::string suffix; - if (! key.second.empty ()) { - suffix = "$CLIP_VAR"; - } - db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ()); - m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first; + db::Box cell_bbox = iter->layout ()->cell (inst.object ().cell_index ()).bbox (); + std::pair > clip_variant = compute_clip_variant (cell_bbox, trans, region, complex_region); + if (! clip_variant.first) { + return false; } - db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans); - m_cell_stack.back ()->insert (new_inst); + std::pair > key (inst.object ().cell_index (), clip_variant.second); + m_cm_entry = m_cell_map.find (key); + + if (m_initial_pass) { + + if (m_cm_entry == m_cell_map.end ()) { + std::string suffix; + if (! key.second.empty ()) { + suffix = "$CLIP_VAR"; + } + db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ()); + m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first; + } + + db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans); + m_cell_stack.back ()->insert (new_inst); + + } + + return (m_cells_seen.find (key) == m_cells_seen.end ()); } - - return (m_cells_seen.find (key) == m_cells_seen.end ()); } void -HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/) +HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box ®ion, const box_tree_type *complex_region) { - tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != cell_map_type::const_iterator ()); - - // TODO: property mapping? - db::Shapes &shapes = m_cell_stack.back ()->shapes (m_target_layer); + mp_pipe->push (shape, region, complex_region, &shapes); +} - if (m_cm_entry->first.second.empty () || is_inside (shape.bbox (), m_cm_entry->first.second)) { +// --------------------------------------------------------------------------------------------- - shapes.insert (shape); +ClippingHierarchyBuilderShapeReceiver::ClippingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe) + : mp_pipe (pipe ? pipe : &def_inserter) +{ + // .. nothing yet .. +} - } else if (! is_outside (shape.bbox (), m_cm_entry->first.second)) { +void +ClippingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + static db::Box world = db::Box::world (); + + if (region == world || is_inside (shape.bbox (), region, complex_region)) { + + mp_pipe->push (shape, world, 0, target); + + } else if (! is_outside (shape.bbox (), region, complex_region)) { // clip the shape if required - if (! m_clip_shapes || shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) { - shapes.insert (shape); + if (shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) { + mp_pipe->push (shape, world, 0, target); } else if (shape.is_box ()) { - insert_clipped (shape.box (), m_cm_entry->first.second, shapes); + insert_clipped (shape.box (), region, complex_region, target); } else if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) { - insert_clipped (shape.polygon (), m_cm_entry->first.second, shapes); + db::Polygon poly; + shape.polygon (poly); + insert_clipped (poly, region, complex_region, target); } } } +void +ClippingHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + static db::Box world = db::Box::world (); + + if (! complex_region) { + db::Box r = shape & region; + if (! r.empty()) { + mp_pipe->push (r, world, 0, target); + } + } else { + insert_clipped (shape, region, complex_region, target); + } +} + +void +ClippingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + static db::Box world = db::Box::world (); + + if (region == world || (shape.box ().inside (region) && ! complex_region)) { + mp_pipe->push (shape, world, 0, target); + } else { + insert_clipped (shape, region, complex_region, target); + } +} + +bool +ClippingHierarchyBuilderShapeReceiver::is_inside (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region) +{ + if (region == db::Box::world ()) { + return true; + } + + if (box.inside (region)) { + + db::Box rect_box = region & box; + + if (complex_region) { + + // TODO: this is not a real test for being inside a complex region + for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (rect_box, db::box_convert ()); ! cr.at_end (); ++cr) { + if (rect_box.inside (*cr)) { + return true; + } + } + + } + + } + + return false; +} + +bool +ClippingHierarchyBuilderShapeReceiver::is_outside (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region) +{ + if (region == db::Box::world ()) { + return false; + } + + if (box.overlaps (region)) { + + db::Box rect_box = region & box; + + if (complex_region) { + for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (rect_box, db::box_convert ()); ! cr.at_end (); ++cr) { + if (rect_box.overlaps (*cr)) { + return false; + } + } + } else { + return false; + } + + } + + return true; +} + +void +ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + db::Box bb = box & region; + static db::Box world = db::Box::world (); + + if (complex_region) { + for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (bb, db::box_convert ()); ! cr.at_end (); ++cr) { + mp_pipe->push (*cr & bb, world, 0, target); + } + } else { + mp_pipe->push (bb, world, 0, target); + } +} + +void +ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Polygon &poly, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + std::vector clipped_poly; + static db::Box world = db::Box::world (); + + if (complex_region) { + // TODO: is this good way to clip a polygon at a complex boundary? + for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (region, db::box_convert ()); ! cr.at_end (); ++cr) { + db::clip_poly (poly, *cr & region, clipped_poly); + } + } else { + db::clip_poly (poly, region, clipped_poly); + } + + for (std::vector::const_iterator p = clipped_poly.begin (); p != clipped_poly.end (); ++p) { + mp_pipe->push (*p, world, 0, target); + } +} + +// --------------------------------------------------------------------------------------------- + +ReducingHierarchyBuilderShapeReceiver::ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe, double area_ratio, size_t max_vertex_count) + : mp_pipe (pipe ? pipe : &def_inserter), m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count) +{ + // .. nothing yet .. +} + +void +ReducingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + if (shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) { + mp_pipe->push (shape, region, complex_region, target); + } else if (shape.is_box ()) { + mp_pipe->push (shape.box (), region, complex_region, target); + } else if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) { + db::Polygon poly; + shape.polygon (poly); + reduce (poly, region, complex_region, target); + } +} + +void +ReducingHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + mp_pipe->push (shape, region, complex_region, target); +} + +void +ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + reduce (shape, region, complex_region, target); +} + +static double area_ratio (const db::Polygon &poly) +{ + return double (poly.box ().area ()) / double (poly.area ()); +} + +void +ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + size_t npoints = 0; + for (unsigned int c = 0; c < poly.holes () + 1; ++c) { + npoints += poly.contour (c).size (); + } + + if (npoints > m_max_vertex_count || area_ratio (poly) > m_area_ratio) { + + std::vector split_polygons; + db::split_polygon (poly, split_polygons); + for (std::vector ::const_iterator sp = split_polygons.begin (); sp != split_polygons.end (); ++sp) { + reduce (*sp, region, complex_region, target); + } + + } else { + mp_pipe->push (poly, region, complex_region, target); + } +} + +// --------------------------------------------------------------------------------------------- + +PolygonReferenceHierarchyBuilderShapeReceiver::PolygonReferenceHierarchyBuilderShapeReceiver (db::Layout *layout) + : mp_layout (layout) +{ + // nothing yet .. +} + +void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +{ + if (shape.is_box () || shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) { + db::Polygon poly; + shape.polygon (poly); + target->insert (db::PolygonRef (poly, mp_layout->shape_repository ())); + } +} + +void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +{ + target->insert (db::PolygonRef (db::Polygon (shape), mp_layout->shape_repository ())); +} + +void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +{ + target->insert (db::PolygonRef (shape, mp_layout->shape_repository ())); +} + } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index c452beb25..c982ec384 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -43,6 +43,108 @@ namespace db */ int 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 + * + * This class can be reimplemented to implement clipping and/or + * simplification. + */ +class DB_PUBLIC HierarchyBuilderShapeReceiver +{ +public: + HierarchyBuilderShapeReceiver () { } + virtual ~HierarchyBuilderShapeReceiver () { } + + virtual void push (const db::Shape &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; + virtual void push (const db::Box &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; + virtual void push (const db::Polygon &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; +}; + +/** + * @brief A shape receiver that simply pushes into the target + */ +class DB_PUBLIC HierarchyBuilderShapeInserter + : public HierarchyBuilderShapeReceiver +{ +public: + HierarchyBuilderShapeInserter () { } + + virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) + { + target->insert (shape); + } + + virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) + { + target->insert (shape); + } + + virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) + { + target->insert (shape); + } +}; + +/** + * @brief A clipping shape receiver that forwards to another one + */ +class DB_PUBLIC ClippingHierarchyBuilderShapeReceiver + : public HierarchyBuilderShapeReceiver +{ +public: + ClippingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0); + + virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + +private: + void insert_clipped (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); + void insert_clipped (const db::Polygon &poly, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); + static bool is_inside (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region); + static bool is_outside (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region); + + HierarchyBuilderShapeReceiver *mp_pipe; +}; + +/** + * @brief A polygon reducing shape receiver that forwards to another one + */ +class DB_PUBLIC ReducingHierarchyBuilderShapeReceiver + : public HierarchyBuilderShapeReceiver +{ +public: + ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0, double area_ratio = 3.0, size_t max_vertex_count = 16); + + virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + +private: + void reduce (const db::Polygon &poly, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); + + HierarchyBuilderShapeReceiver *mp_pipe; + double m_area_ratio; + size_t m_max_vertex_count; +}; + +/** + * @brief A polygon reference generating shape receiver that feeds a shapes array after turning the shapes into PolygonRefs + */ +class DB_PUBLIC PolygonReferenceHierarchyBuilderShapeReceiver + : public HierarchyBuilderShapeReceiver +{ +public: + PolygonReferenceHierarchyBuilderShapeReceiver (db::Layout *layout); + + virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + +private: + db::Layout *mp_layout; +}; + /** * @brief A class building a hierarchy from a recursive shape iterator in push mode * @@ -58,26 +160,55 @@ int compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShape * rely on precisely the same hierarchy arrangement. This is not given with * region selections. */ -class HierarchyBuilder +class DB_PUBLIC HierarchyBuilder : public db::RecursiveShapeReceiver { public: typedef std::map >, db::cell_index_type> cell_map_type; - HierarchyBuilder (db::Layout *target, unsigned int target_layer, bool clip_shapes); + HierarchyBuilder (db::Layout *target, unsigned int target_layer, HierarchyBuilderShapeReceiver *pipe = 0); + HierarchyBuilder (db::Layout *target, HierarchyBuilderShapeReceiver *pipe = 0); + virtual ~HierarchyBuilder (); + + /** + * @brief Installs a custom shape receiver + * The hierarchy builder will *NOT* take ownership of this object. + */ + void set_shape_receiver (HierarchyBuilderShapeReceiver *pipe); virtual void begin (const RecursiveShapeIterator *iter); - virtual void end (const RecursiveShapeIterator * /*iter*/); - virtual void enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/); - virtual void leave_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/); - virtual bool new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all); - virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region); - virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans); + virtual void end (const RecursiveShapeIterator *iter); + virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region); + virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell); + virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all); + virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all); + virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region); + + /** + * @brief Sets the target layer - shapes will be put there + */ + void set_target_layer (unsigned int target_layer) + { + m_target_layer = target_layer; + } + + /** + * @brief Reset the builder - performs a new initial pass + */ + void reset (); + + /** + * @brief Gets the initial cell the builder produced + */ + db::Cell *initial_cell () + { + return mp_initial_cell; + } private: tl::weak_ptr mp_target; - bool m_clip_shapes; + HierarchyBuilderShapeReceiver *mp_pipe; bool m_initial_pass; db::RecursiveShapeIterator m_ref_iter; cell_map_type m_cell_map; @@ -85,6 +216,7 @@ private: cell_map_type::const_iterator m_cm_entry; unsigned int m_target_layer; std::vector m_cell_stack; + db::Cell *mp_initial_cell; }; } diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 90e2a9200..0380deb12 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1511,6 +1511,24 @@ Layout::insert_layer (unsigned int index, const LayerProperties &props) layer_properties_changed (); } +unsigned int +Layout::get_layer (const db::LayerProperties &lp) +{ + if (lp.is_null ()) { + // for a null layer info always create a layer + return insert_layer (); + } else { + // if we have a layer with the requested properties already, return this. + for (db::Layout::layer_iterator li = begin_layers (); li != end_layers (); ++li) { + if ((*li).second->log_equal (lp)) { + return (*li).first; + } + } + // otherwise create a new layer + return insert_layer (lp); + } +} + unsigned int Layout::waste_layer () const { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index e1724657d..8ebaf1fbc 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1447,6 +1447,14 @@ public: */ void insert_layer (unsigned int index, const LayerProperties &props = LayerProperties ()); + /** + * @brief Gets or creates a layer with the given properties + * + * If there already is a layer matching the given properties, it's index will be + * returned. Otherwise a new layer with these properties is created. + */ + unsigned int get_layer (const db::LayerProperties &props); + /** * @brief Insert a new special layer with the given properties * diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index 2c9216776..d55bce34c 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -716,8 +716,10 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const m_inst_quad_id_stack.push_back (m_inst_quad_id); bool ia = is_inactive (); + bool aoi = is_all_of_instance (); mp_cell = &mp_layout->cell (m_inst->cell_index ()); set_inactive (ia); + set_all_of_instance (aoi); m_trans = m_trans * m_inst->complex_trans (*m_inst_array); @@ -876,22 +878,34 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const } } + bool all_of_instance = false; + bool with_region = false; + if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) { - if (receiver && ! receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), false)) { - m_inst_array = inst_array_iterator (); - } else { - m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert); - } + with_region = true; } else { // TODO: optimization potential: only report all_of_instance == false, if not entirely within the complex region - bool all_of_instance = m_local_complex_region_stack.empty (); - if (receiver && ! receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance)) { - m_inst_array = inst_array_iterator (); - } else { - m_inst_array = m_inst->cell_inst ().begin (); - } + all_of_instance = m_local_complex_region_stack.empty (); } + RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all; + if (receiver) { + ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance); + } + + if (ni == RecursiveShapeReceiver::NI_skip) { + m_inst_array = inst_array_iterator (); + } else if (ni == RecursiveShapeReceiver::NI_single) { + // a singular iterator + m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false); + } else if (with_region) { + m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert); + } else { + m_inst_array = m_inst->cell_inst ().begin (); + } + + set_all_of_instance (all_of_instance); + new_inst_member (receiver); if (! m_inst_array.at_end ()) { @@ -921,7 +935,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const } while (! m_inst_array.at_end () && receiver) { - if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ())) { + if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) { break; } else { ++m_inst_array; @@ -950,7 +964,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver) validate (receiver); while (! at_end ()) { - receiver->shape (this, *m_shape, m_trans); + receiver->shape (this, *m_shape, m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ()); next (receiver); } diff --git a/src/db/db/dbRecursiveShapeIterator.h b/src/db/db/dbRecursiveShapeIterator.h index ce54b7c2f..59cc5679f 100644 --- a/src/db/db/dbRecursiveShapeIterator.h +++ b/src/db/db/dbRecursiveShapeIterator.h @@ -548,7 +548,7 @@ public: } /** - * @brief Get the current depth + * @brief Gets the current depth * * Returns the number of hierarchy levels we are below top level currently. */ @@ -559,7 +559,7 @@ public: } /** - * @brief Get the current shape + * @brief Gets the current shape * * Returns the shape currently referred to by the recursive iterator. * This shape is not transformed yet and is located in the current cell. @@ -600,27 +600,25 @@ public: bool at_end () const; /** - * @brief Get the current cell's index + * @brief Gets the current cell's index */ db::cell_index_type cell_index () const { - validate (0); - size_t c = reinterpret_cast (mp_cell); - return reinterpret_cast (c - (c & size_t (1)))->cell_index (); + return cell ()->cell_index (); } /** - * @brief Get the current cell's reference + * @brief Gets the current cell's reference */ const cell_type *cell () const { validate (0); size_t c = reinterpret_cast (mp_cell); - return reinterpret_cast (c - (c & size_t (1))); + return reinterpret_cast (c - (c & size_t (3))); } /** - * @brief Increment the iterator (operator version) + * @brief Increments the iterator (operator version) */ RecursiveShapeIterator &operator++() { @@ -749,7 +747,19 @@ private: { size_t c = reinterpret_cast (mp_cell); c -= (c & size_t (1)); - mp_cell = reinterpret_cast (c + a); + mp_cell = reinterpret_cast (c + (a ? 1 : 0)); + } + + bool is_all_of_instance () const + { + return (reinterpret_cast (mp_cell) & size_t (2)) != 0; + } + + void set_all_of_instance (bool a) const + { + size_t c = reinterpret_cast (mp_cell); + c -= (c & size_t (2)); + mp_cell = reinterpret_cast (c + (a ? 2 : 0)); } }; @@ -769,7 +779,19 @@ class DB_PUBLIC RecursiveShapeReceiver public: typedef RecursiveShapeIterator::box_tree_type box_tree_type; + /** + * @brief See new_inst for details. + */ + enum new_inst_mode { NI_all = 0, NI_single = 1, NI_skip = 2 }; + + /** + * @brief Constructor + */ RecursiveShapeReceiver () { } + + /** + * @brief Destructor + */ virtual ~RecursiveShapeReceiver () { } /** @@ -824,9 +846,12 @@ public: * * The "all" parameter is true, if all instances of the array will be addressed. * - * If this method returns false, the instance (the whole array) is skipped and the cell is not entered. + * This method can return the following values: + * - NI_all: iterate all members through "new_inst_member" + * - NI_single: iterate a single member (the first one) + * - NI_skip: skips the whole array (not a single instance is iterated) */ - virtual bool new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; } + virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; } /** * @brief Enters a new array member of the instance @@ -835,16 +860,18 @@ public: * which holds the complex transformation for this particular instance of * the array. * + * "all" is true, if an instance array is iterated in "all" mode (see new_inst). + * * If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered. */ - virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { return true; } + virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; } /** * @brief Delivers a shape * * @param trans The transformation which maps the shape to the top cell. */ - virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/) { } + virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { } }; } // namespace db diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 298655b8f..48c60db98 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -367,41 +367,24 @@ static std::vector multi_clip_into (db::Layout *l, db::cell return db::clip_layout(*l, *t, c, boxes, true); } -static unsigned int get_layer (db::Layout *l, const db::LayerProperties &lp) -{ - if (lp.is_null ()) { - // for a null layer info always create a layer - return l->insert_layer (); - } else { - // if we have a layer with the requested properties already, return this. - for (db::Layout::layer_iterator li = l->begin_layers (); li != l->end_layers (); ++li) { - if ((*li).second->log_equal (lp)) { - return (*li).first; - } - } - // otherwise create a new layer - return l->insert_layer (lp); - } -} - static unsigned int get_layer0 (db::Layout *l) { - return get_layer (l, db::LayerProperties ()); + return l->get_layer (db::LayerProperties ()); } static unsigned int get_layer1 (db::Layout *l, const std::string &name) { - return get_layer (l, db::LayerProperties (name)); + return l->get_layer (db::LayerProperties (name)); } static unsigned int get_layer2 (db::Layout *l, int ln, int dn) { - return get_layer (l, db::LayerProperties (ln, dn)); + return l->get_layer (db::LayerProperties (ln, dn)); } static unsigned int get_layer3 (db::Layout *l, int ln, int dn, const std::string &name) { - return get_layer (l, db::LayerProperties (ln, dn, name)); + return l->get_layer (db::LayerProperties (ln, dn, name)); } static tl::Variant find_layer (db::Layout *l, const db::LayerProperties &lp) @@ -1297,7 +1280,7 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.25.\n" ) + - gsi::method_ext ("layer", &get_layer, + gsi::method ("layer", &db::Layout::get_layer, "@brief Finds or creates a layer with the given properties\n" "@args info\n" "\n" diff --git a/src/db/unit_tests/dbHierarchyBuilderTests.cc b/src/db/unit_tests/dbHierarchyBuilderTests.cc new file mode 100644 index 000000000..1dffa2d9d --- /dev/null +++ b/src/db/unit_tests/dbHierarchyBuilderTests.cc @@ -0,0 +1,337 @@ + +/* + + 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 "tlUnitTest.h" +#include "tlStream.h" + +TEST(1) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::HierarchyBuilder builder (&target, false); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1); + + iter.push (&builder); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au1.gds"); +} + +TEST(2_WithoutClip) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::HierarchyBuilder builder (&target, false); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000)); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2a.gds"); +} + +TEST(2_WithClip) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::ClippingHierarchyBuilderShapeReceiver clip; + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000)); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2b.gds"); +} + +TEST(2_WithClipAndSimplification) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::ReducingHierarchyBuilderShapeReceiver red(0, 1.2, 4); + db::ClippingHierarchyBuilderShapeReceiver clip(&red); + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000)); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2c.gds"); +} + +TEST(2_WithClipAndRefGeneration) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::PolygonReferenceHierarchyBuilderShapeReceiver ref(&target); + db::ClippingHierarchyBuilderShapeReceiver clip(&ref); + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000)); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2d.gds"); +} + +TEST(2_WithEmptyResult) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::PolygonReferenceHierarchyBuilderShapeReceiver ref(&target); + db::ClippingHierarchyBuilderShapeReceiver clip(&ref); + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, 10000, 18500, 15000)); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2e.gds"); +} + +TEST(3_ComplexRegionWithClip) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l2.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::ClippingHierarchyBuilderShapeReceiver clip; + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Region reg; + reg.insert (db::Box (5000, 13000, 18500, 20000)); + reg.insert (db::Box (11000, 20000, 18500, 36000)); + reg.merge (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, reg); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au3a.gds"); +} + +TEST(4_ComplexRegionAndLayoutWithClip) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l3.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::ClippingHierarchyBuilderShapeReceiver clip; + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Region reg; + reg.insert (db::Box (5000, 13000, 18500, 20000)); + reg.insert (db::Box (11000, 20000, 18500, 36000)); + reg.merge (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, reg); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au4a.gds"); +} + diff --git a/src/db/unit_tests/dbRecursiveShapeIterator.cc b/src/db/unit_tests/dbRecursiveShapeIterator.cc index 03dc7f918..dfd115c27 100644 --- a/src/db/unit_tests/dbRecursiveShapeIterator.cc +++ b/src/db/unit_tests/dbRecursiveShapeIterator.cc @@ -918,19 +918,23 @@ public: m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; } - virtual bool new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) { m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ()); if (all) { m_text += ",all"; } m_text += ")\n"; - return true; + return NI_all; } - virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) + virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all) { - m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans) + ")\n"; + m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans); + if (all) { + m_text += ",all"; + } + m_text += ")\n"; return true; } @@ -949,10 +953,26 @@ class ReceiverRejectingACellInstanceArray public: ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { } - virtual bool new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) { LoggingReceiver::new_inst (iter, inst, region, complex_region, all); - return inst.object ().cell_index () != m_rejected; + return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip; + } + +private: + db::cell_index_type m_rejected; +}; + +class ReceiverRejectingACellInstanceArrayExceptOne + : public LoggingReceiver +{ +public: + ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { } + + virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, const box_tree_type *complex_region, bool all) + { + LoggingReceiver::new_inst (iter, inst, region, complex_region, all); + return inst.object ().cell_index () != m_rejected ? NI_all : NI_single; } private: @@ -965,9 +985,9 @@ class ReceiverRejectingACellInstance public: ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { } - virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region) + virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region, bool all) { - LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region); + LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all); return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected; } @@ -1001,82 +1021,82 @@ TEST(10) EXPECT_EQ (lr1.text (), "begin\n" "new_inst($2,all)\n" - "new_inst_member($2,r0 *1 0,0)\n" + "new_inst_member($2,r0 *1 0,0,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" "leave_cell($3)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 0,6000)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 0,6000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 0,8000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n" "leave_cell($3)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 6000,0)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n" "leave_cell($3)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n" "leave_cell($3)\n" @@ -1091,25 +1111,67 @@ TEST(10) EXPECT_EQ (rr1.text (), "begin\n" "new_inst($2,all)\n" - "new_inst_member($2,r0 *1 0,0)\n" + "new_inst_member($2,r0 *1 0,0,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 0,6000)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" "leave_cell($2)\n" "end\n" ); + ReceiverRejectingACellInstanceArrayExceptOne rs1 (c2.cell_index ()); + db::RecursiveShapeIterator is1 (g, c0, 0); + is1.push (&rs1); + + EXPECT_EQ (rs1.text (), + "begin\n" + "new_inst($2,all)\n" + "new_inst_member($2,r0 *1 0,0,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,0)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 0,6000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,0)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" + "enter_cell($2)\n" + "new_inst($3,all)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "enter_cell($3)\n" + "shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n" + "leave_cell($3)\n" + "leave_cell($2)\n" + "end\n" + ); + ReceiverRejectingACellInstance rri1 (c2.cell_index (), db::ICplxTrans ()); db::RecursiveShapeIterator iri1 (g, c0, 0); iri1.push (&rri1); @@ -1117,70 +1179,70 @@ TEST(10) EXPECT_EQ (rri1.text (), "begin\n" "new_inst($2,all)\n" - "new_inst_member($2,r0 *1 0,0)\n" + "new_inst_member($2,r0 *1 0,0,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" // -> skipped - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" // -> skipped + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 0,2000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n" "leave_cell($3)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 0,6000)\n" + "new_inst_member($2,r0 *1 0,6000,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 0,8000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n" "leave_cell($3)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,0)\n" + "new_inst_member($2,r0 *1 6000,0,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n" "leave_cell($3)\n" "leave_cell($2)\n" - "new_inst_member($2,r0 *1 6000,6000)\n" + "new_inst_member($2,r0 *1 6000,6000,all)\n" "enter_cell($2)\n" "new_inst($3,all)\n" - "new_inst_member($3,r0 *1 0,0)\n" - "new_inst_member($3,r0 *1 0,2000)\n" + "new_inst_member($3,r0 *1 0,0,all)\n" + "new_inst_member($3,r0 *1 0,2000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,1000)\n" + "new_inst_member($3,r0 *1 3000,1000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n" "leave_cell($3)\n" - "new_inst_member($3,r0 *1 3000,3000)\n" + "new_inst_member($3,r0 *1 3000,3000,all)\n" "enter_cell($3)\n" "shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n" "leave_cell($3)\n" diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index c1a034f6a..2e3f8a0e1 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -53,7 +53,8 @@ SOURCES = \ dbWriterTools.cc \ dbVariableWidthPath.cc \ dbLoadLayoutOptionsTests.cc \ - dbSaveLayoutOptionsTests.cc + dbSaveLayoutOptionsTests.cc \ + dbHierarchyBuilderTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/src/tl/tl/tlObject.cc b/src/tl/tl/tlObject.cc index 0d1b4cfca..305e0b3bb 100644 --- a/src/tl/tl/tlObject.cc +++ b/src/tl/tl/tlObject.cc @@ -130,12 +130,12 @@ bool Object::has_strong_references () const return false; } -void Object::keep () +void Object::keep_object () { mp_ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) | size_t (1)); } -void Object::release () +void Object::release_object () { mp_ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1)); diff --git a/src/tl/tl/tlObject.h b/src/tl/tl/tlObject.h index df78b0435..a66426675 100644 --- a/src/tl/tl/tlObject.h +++ b/src/tl/tl/tlObject.h @@ -106,14 +106,14 @@ public: * no strong pointer is having a reference to this object and longer, the * object is not deleted. */ - void keep (); + void keep_object (); /** * @brief Releases this object from being kept * This method may delete the object if no strong pointer holds a * reference to it. */ - void release (); + void release_object (); protected: /** diff --git a/testdata/algo/hierarchy_builder_au1.gds b/testdata/algo/hierarchy_builder_au1.gds new file mode 100644 index 000000000..fa837f4e2 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au1.gds differ diff --git a/testdata/algo/hierarchy_builder_au2a.gds b/testdata/algo/hierarchy_builder_au2a.gds new file mode 100644 index 000000000..9d556aed6 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au2a.gds differ diff --git a/testdata/algo/hierarchy_builder_au2b.gds b/testdata/algo/hierarchy_builder_au2b.gds new file mode 100644 index 000000000..66a8a6d76 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au2b.gds differ diff --git a/testdata/algo/hierarchy_builder_au2c.gds b/testdata/algo/hierarchy_builder_au2c.gds new file mode 100644 index 000000000..85f5d6082 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au2c.gds differ diff --git a/testdata/algo/hierarchy_builder_au2d.gds b/testdata/algo/hierarchy_builder_au2d.gds new file mode 100644 index 000000000..9589536ac Binary files /dev/null and b/testdata/algo/hierarchy_builder_au2d.gds differ diff --git a/testdata/algo/hierarchy_builder_au2e.gds b/testdata/algo/hierarchy_builder_au2e.gds new file mode 100644 index 000000000..db00d1fc1 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au2e.gds differ diff --git a/testdata/algo/hierarchy_builder_au3a.gds b/testdata/algo/hierarchy_builder_au3a.gds new file mode 100644 index 000000000..671fad2a1 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au3a.gds differ diff --git a/testdata/algo/hierarchy_builder_au4a.gds b/testdata/algo/hierarchy_builder_au4a.gds new file mode 100644 index 000000000..504df9920 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au4a.gds differ diff --git a/testdata/algo/hierarchy_builder_l1.gds b/testdata/algo/hierarchy_builder_l1.gds new file mode 100644 index 000000000..fa837f4e2 Binary files /dev/null and b/testdata/algo/hierarchy_builder_l1.gds differ diff --git a/testdata/algo/hierarchy_builder_l2.gds b/testdata/algo/hierarchy_builder_l2.gds new file mode 100644 index 000000000..7447367b2 Binary files /dev/null and b/testdata/algo/hierarchy_builder_l2.gds differ diff --git a/testdata/algo/hierarchy_builder_l3.gds b/testdata/algo/hierarchy_builder_l3.gds new file mode 100644 index 000000000..2deb1d3e4 Binary files /dev/null and b/testdata/algo/hierarchy_builder_l3.gds differ