From 478b8385897680ab5a3df55db2f41365626d4a2e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 9 Jan 2023 00:05:31 +0100 Subject: [PATCH] WIP: properties for regions, starting with deep regions --- src/db/db/dbDeepShapeStore.cc | 11 ++- src/db/db/dbHierarchyBuilder.cc | 148 +++++++++++++++++++---------- src/db/db/dbHierarchyBuilder.h | 84 +++++++++------- src/db/db/dbRegion.cc | 6 +- src/db/db/dbShapes.cc | 66 ++++++------- src/db/unit_tests/dbRegionTests.cc | 55 +++++++++++ 6 files changed, 246 insertions(+), 124 deletions(-) diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 39211ad6e..f7a4874a3 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -481,13 +481,14 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Region ®ion, bool for_n // try to maintain the texts on top level - go through shape iterator std::pair ii = region.begin_iter (); + bool regard_props = ((ii.first.shape_flags () & db::ShapeIterator::RegardProperties) != 0); db::ICplxTrans ttop = trans * ii.second; while (! ii.first.at_end ()) { if (for_netlist && ii.first->is_text () && ii.first.layout () && ii.first.cell () != ii.first.top_cell ()) { // Skip texts on levels below top cell. For the reasoning see the description of this method. } else { - red.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes); + red.push (*ii.first, regard_props ? ii.first->prop_id () : 0, ttop * ii.first.trans (), world, 0, shapes); } ++ii.first; @@ -518,9 +519,10 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC db::EdgeBuildingHierarchyBuilderShapeReceiver eb (false); std::pair ii = edges.begin_iter (); + bool regard_props = ((ii.first.shape_flags () & db::ShapeIterator::RegardProperties) != 0); db::ICplxTrans ttop = trans * ii.second; while (! ii.first.at_end ()) { - eb.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes); + eb.push (*ii.first, regard_props ? ii.first->prop_id () : 0, ttop * ii.first.trans (), world, 0, shapes); ++ii.first; } @@ -548,9 +550,10 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::IC db::TextBuildingHierarchyBuilderShapeReceiver tb (&layout ()); std::pair ii = texts.begin_iter (); + bool regard_props = ((ii.first.shape_flags () & db::ShapeIterator::RegardProperties) != 0); db::ICplxTrans ttop = trans * ii.second; while (! ii.first.at_end ()) { - tb.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes); + tb.push (*ii.first, regard_props ? ii.first->prop_id () : 0, ttop * ii.first.trans (), world, 0, shapes); ++ii.first; } @@ -905,7 +908,7 @@ DeepLayer DeepShapeStore::create_copy (const DeepLayer &source, HierarchyBuilder db::Shapes &into = c->shapes (layer_index); const db::Shapes &from = c->shapes (from_layer_index); for (db::Shapes::shape_iterator s = from.begin (db::ShapeIterator::All); ! s.at_end (); ++s) { - pipe->push (*s, trans, region, 0, &into); + pipe->push (*s, s->prop_id (), trans, region, 0, &into); } } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 959b34276..c3ca09941 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -152,13 +152,13 @@ static std::pair > compute_clip_variant (const db::Box & } HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, const db::ICplxTrans &trans, HierarchyBuilderShapeReceiver *pipe) - : mp_target (target), m_initial_pass (true), m_cm_new_entry (false), m_target_layer (target_layer), m_trans (trans) + : mp_target (target), m_initial_pass (true), m_ignore_properties (true), m_cm_new_entry (false), m_target_layer (target_layer), m_trans (trans) { set_shape_receiver (pipe); } HierarchyBuilder::HierarchyBuilder (db::Layout *target, const db::ICplxTrans &trans, HierarchyBuilderShapeReceiver *pipe) - : mp_target (target), m_initial_pass (true), m_cm_new_entry (false), m_target_layer (0), m_trans (trans) + : mp_target (target), m_initial_pass (true), m_ignore_properties (true), m_cm_new_entry (false), m_target_layer (0), m_trans (trans) { set_shape_receiver (pipe); } @@ -179,6 +179,7 @@ HierarchyBuilder::reset () { m_initial_pass = true; mp_initial_cell = 0; + m_ignore_properties = true; m_cells_to_be_filled.clear (); m_cell_map.clear (); @@ -244,6 +245,8 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter) tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_source, *iter) == 0); } + m_ignore_properties = ((iter->shape_flags () & db::ShapeIterator::RegardProperties) == 0); + m_cell_stack.clear (); m_cells_seen.clear (); @@ -275,6 +278,7 @@ HierarchyBuilder::end (const RecursiveShapeIterator *iter) { tl_assert (! iter->layout () || ! iter->top_cell () || m_cell_stack.size () == 1); + m_ignore_properties = true; m_initial_pass = false; m_cells_seen.clear (); mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second.front (); @@ -411,7 +415,7 @@ HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shap { for (std::vector::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) { db::Shapes &shapes = (*c)->shapes (m_target_layer); - mp_pipe->push (shape, m_trans * apply_always, region, complex_region, &shapes); + mp_pipe->push (shape, m_ignore_properties ? 0 : shape.prop_id (), m_trans * apply_always, region, complex_region, &shapes); } } @@ -424,54 +428,54 @@ ClippingHierarchyBuilderShapeReceiver::ClippingHierarchyBuilderShapeReceiver (Hi } void -ClippingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ClippingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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, trans, world, 0, target); + mp_pipe->push (shape, prop_id, trans, world, 0, target); } else if (! is_outside (shape.bbox (), region, complex_region)) { // clip the shape if required if (shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) { - mp_pipe->push (shape, trans, world, 0, target); + mp_pipe->push (shape, prop_id, trans, world, 0, target); } else if (shape.is_box ()) { - insert_clipped (shape.box (), trans, region, complex_region, target); + insert_clipped (shape.box (), prop_id, trans, region, complex_region, target); } else if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) { db::Polygon poly; shape.polygon (poly); - insert_clipped (poly, trans, region, complex_region, target); + insert_clipped (poly, prop_id, trans, region, complex_region, target); } } } void -ClippingHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ClippingHierarchyBuilderShapeReceiver::push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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, trans, world, 0, target); + mp_pipe->push (r, prop_id, trans, world, 0, target); } } else { - insert_clipped (shape, trans, region, complex_region, target); + insert_clipped (shape, prop_id, trans, region, complex_region, target); } } void -ClippingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ClippingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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, trans, world, 0, target); + mp_pipe->push (shape, prop_id, trans, world, 0, target); } else { - insert_clipped (shape, trans, region, complex_region, target); + insert_clipped (shape, prop_id, trans, region, complex_region, target); } } @@ -529,7 +533,7 @@ ClippingHierarchyBuilderShapeReceiver::is_outside (const db::Box &box, const db: } void -ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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 (); @@ -538,16 +542,16 @@ ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (bb, db::box_convert ()); ! cr.at_end (); ++cr) { db::Box bc = *cr & bb; if (! bc.empty ()) { - mp_pipe->push (bc, trans, world, 0, target); + mp_pipe->push (bc, prop_id, trans, world, 0, target); } } } else if (! bb.empty ()) { - mp_pipe->push (bb, trans, world, 0, target); + mp_pipe->push (bb, prop_id, trans, world, 0, target); } } void -ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Polygon &poly, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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 (); @@ -562,7 +566,7 @@ ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Polygon &poly, } for (std::vector::const_iterator p = clipped_poly.begin (); p != clipped_poly.end (); ++p) { - mp_pipe->push (*p, trans, world, 0, target); + mp_pipe->push (*p, prop_id, trans, world, 0, target); } } @@ -575,33 +579,33 @@ ReducingHierarchyBuilderShapeReceiver::ReducingHierarchyBuilderShapeReceiver (Hi } void -ReducingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ReducingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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, trans, region, complex_region, target); + mp_pipe->push (shape, prop_id, trans, region, complex_region, target); } else if (shape.is_box ()) { - mp_pipe->push (shape.box (), trans, region, complex_region, target); + mp_pipe->push (shape.box (), prop_id, trans, region, complex_region, target); } else if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) { db::Polygon poly; shape.polygon (poly); - reduce (poly, trans, region, complex_region, target); + reduce (poly, prop_id, trans, region, complex_region, target); } } void -ReducingHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ReducingHierarchyBuilderShapeReceiver::push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) { - mp_pipe->push (shape, trans, region, complex_region, target); + mp_pipe->push (shape, prop_id, trans, region, complex_region, target); } void -ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) { - reduce (shape, trans, region, complex_region, target); + reduce (shape, prop_id, trans, region, complex_region, target); } void -ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target, bool check) +ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target, bool check) { if (check && m_reject_odd_polygons && is_non_orientable_polygon (poly)) { // non-orientable polygons generate an error @@ -620,11 +624,11 @@ ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db db::split_polygon (poly, split_polygons); for (std::vector ::const_iterator sp = split_polygons.begin (); sp != split_polygons.end (); ++sp) { - reduce (*sp, trans, region, complex_region, target, false); + reduce (*sp, prop_id, trans, region, complex_region, target, false); } } else { - mp_pipe->push (poly, trans, region, complex_region, target); + mp_pipe->push (poly, prop_id, trans, region, complex_region, target); } } @@ -639,7 +643,7 @@ PolygonReferenceHierarchyBuilderShapeReceiver::PolygonReferenceHierarchyBuilderS } } -void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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 ()) { @@ -652,7 +656,11 @@ void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape // NOTE: as this is a specialized receiver for the purpose of building region // representations we don't need empty polygons here if (poly.area2 () > 0) { - target->insert (db::PolygonRef (poly, mp_layout->shape_repository ())); + if (prop_id != 0) { + target->insert (db::PolygonRefWithProperties (db::PolygonRef (poly, mp_layout->shape_repository ()), prop_id)); + } else { + target->insert (db::PolygonRef (poly, mp_layout->shape_repository ())); + } } } else if (shape.is_text () && m_text_enlargement >= 0) { @@ -672,23 +680,36 @@ void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape target->insert (db::PolygonRefWithProperties (pref, pid)); } else { - target->insert (pref); + + if (prop_id != 0) { + target->insert (db::PolygonRefWithProperties (pref, prop_id)); + } else { + target->insert (pref); + } } } } -void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { if (shape.area () > 0) { - target->insert (db::PolygonRef (db::Polygon (shape.transformed (trans)), mp_layout->shape_repository ())); + if (prop_id != 0) { + target->insert (db::PolygonRefWithProperties (db::PolygonRef (db::Polygon (shape.transformed (trans)), mp_layout->shape_repository ()), prop_id)); + } else { + target->insert (db::PolygonRef (db::Polygon (shape.transformed (trans)), mp_layout->shape_repository ())); + } } } -void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { if (shape.area2 () > 0) { - target->insert (db::PolygonRef (shape.transformed (trans), mp_layout->shape_repository ())); + if (prop_id != 0) { + target->insert (db::PolygonRefWithProperties (db::PolygonRef (shape.transformed (trans), mp_layout->shape_repository ()), prop_id)); + } else { + target->insert (db::PolygonRef (shape.transformed (trans), mp_layout->shape_repository ())); + } } } @@ -700,34 +721,49 @@ EdgeBuildingHierarchyBuilderShapeReceiver::EdgeBuildingHierarchyBuilderShapeRece // .. nothing yet .. } -void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) { if (m_as_edges && (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ())) { db::Polygon poly; shape.polygon (poly); - push (poly, trans, region, complex_region, target); + push (poly, prop_id, trans, region, complex_region, target); } else if (m_as_edges && shape.is_box ()) { - push (shape.box (), trans, region, complex_region, target); + push (shape.box (), prop_id, trans, region, complex_region, target); } else if (shape.is_edge ()) { - target->insert (shape.edge ()); + if (prop_id != 0) { + target->insert (db::EdgeWithProperties (shape.edge (), shape.prop_id ())); + } else { + target->insert (shape.edge ()); + } } } -void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Box &box, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Box &box, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { if (m_as_edges && ! box.empty ()) { - target->insert (db::Edge (box.p1 (), box.upper_left ()).transformed (trans)); - target->insert (db::Edge (box.upper_left (), box.p2 ()).transformed (trans)); - target->insert (db::Edge (box.p2 (), box.lower_right ()).transformed (trans)); - target->insert (db::Edge (box.lower_right (), box.p1 ()).transformed (trans)); + if (prop_id != 0) { + target->insert (db::EdgeWithProperties (db::Edge (box.p1 (), box.upper_left ()).transformed (trans), prop_id)); + target->insert (db::EdgeWithProperties (db::Edge (box.upper_left (), box.p2 ()).transformed (trans), prop_id)); + target->insert (db::EdgeWithProperties (db::Edge (box.p2 (), box.lower_right ()).transformed (trans), prop_id)); + target->insert (db::EdgeWithProperties (db::Edge (box.lower_right (), box.p1 ()).transformed (trans), prop_id)); + } else { + target->insert (db::Edge (box.p1 (), box.upper_left ()).transformed (trans)); + target->insert (db::Edge (box.upper_left (), box.p2 ()).transformed (trans)); + target->insert (db::Edge (box.p2 (), box.lower_right ()).transformed (trans)); + target->insert (db::Edge (box.lower_right (), box.p1 ()).transformed (trans)); + } } } -void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Polygon &poly, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { if (m_as_edges) { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { - target->insert ((*e).transformed (trans)); + if (prop_id != 0) { + target->insert (db::EdgeWithProperties ((*e).transformed (trans), prop_id)); + } else { + target->insert ((*e).transformed (trans)); + } } } } @@ -739,10 +775,14 @@ EdgePairBuildingHierarchyBuilderShapeReceiver::EdgePairBuildingHierarchyBuilderS // .. nothing yet .. } -void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) +void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) { if (shape.is_edge_pair ()) { - target->insert (shape.edge_pair ().transformed (trans)); + if (prop_id != 0) { + target->insert (db::EdgePairWithProperties (shape.edge_pair ().transformed (trans), prop_id)); + } else { + target->insert (shape.edge_pair ().transformed (trans)); + } } } @@ -754,13 +794,17 @@ TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeRece // .. nothing yet .. } -void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) +void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) { if (shape.is_text ()) { // NOTE: we intentionally skip all the text attributes (font etc.) here because in the context // of a text collections we're only interested in the locations. db::Text t (shape.text_string (), shape.text_trans ()); - target->insert (db::TextRef (t.transformed (trans), mp_layout->shape_repository ())); + if (prop_id != 0) { + target->insert (db::TextRefWithProperties (db::TextRef (t.transformed (trans), mp_layout->shape_repository ()), prop_id)); + } else { + target->insert (db::TextRef (t.transformed (trans), mp_layout->shape_repository ())); + } } } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index a248e4cd4..e653baf8e 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -55,9 +55,9 @@ public: HierarchyBuilderShapeReceiver () { } virtual ~HierarchyBuilderShapeReceiver () { } - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, 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::ICplxTrans &trans, 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::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; + virtual void push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; + virtual void push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; + virtual void push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0; }; /** @@ -69,28 +69,45 @@ class DB_PUBLIC HierarchyBuilderShapeInserter public: HierarchyBuilderShapeInserter () { } - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) + virtual void push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { - tl::ident_map pm; + tl::const_map pm (prop_id); target->insert (shape, trans, pm); } - virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) + virtual void push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { if (trans.is_ortho ()) { - target->insert (shape.transformed (trans)); + if (prop_id != 0) { + target->insert (db::BoxWithProperties (shape.transformed (trans), prop_id)); + } else { + target->insert (shape.transformed (trans)); + } } else { - db::Polygon poly (shape); - target->insert (poly.transformed (trans)); + if (prop_id != 0) { + db::PolygonWithProperties poly (db::Polygon (shape), prop_id); + target->insert (poly.transformed (trans)); + } else { + db::Polygon poly (shape); + target->insert (poly.transformed (trans)); + } } } - virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) + virtual void push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { if (trans.is_unity ()) { - target->insert (shape); + if (prop_id != 0) { + target->insert (db::PolygonWithProperties (shape, prop_id)); + } else { + target->insert (shape); + } } else { - target->insert (shape.transformed (trans)); + if (prop_id != 0) { + target->insert (db::PolygonWithProperties (shape.transformed (trans), prop_id)); + } else { + target->insert (shape.transformed (trans)); + } } } }; @@ -104,13 +121,13 @@ class DB_PUBLIC ClippingHierarchyBuilderShapeReceiver public: ClippingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0); - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); private: - void insert_clipped (const db::Box &box, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); - void insert_clipped (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); + void insert_clipped (const db::Box &box, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target); + void insert_clipped (const db::Polygon &poly, db::properties_id_type prop_id, const db::ICplxTrans &trans, 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); @@ -126,12 +143,12 @@ class DB_PUBLIC ReducingHierarchyBuilderShapeReceiver public: ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0, double area_ratio = 3.0, size_t max_vertex_count = 16, bool reject_odd_polygons = false); - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Shape &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); private: - void reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target, bool check = true); + void reduce (const db::Polygon &poly, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target, bool check = true); HierarchyBuilderShapeReceiver *mp_pipe; double m_area_ratio; @@ -148,9 +165,9 @@ class DB_PUBLIC PolygonReferenceHierarchyBuilderShapeReceiver public: PolygonReferenceHierarchyBuilderShapeReceiver (db::Layout *layout, int text_enlargement = -1, const tl::Variant &text_prop_name = tl::Variant ()); - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Shape &shape, properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); private: db::Layout *mp_layout; @@ -168,9 +185,9 @@ class DB_PUBLIC EdgeBuildingHierarchyBuilderShapeReceiver public: EdgeBuildingHierarchyBuilderShapeReceiver (bool as_edges); - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Shape &shape, properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, db::properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); private: bool m_as_edges; @@ -185,9 +202,9 @@ class DB_PUBLIC EdgePairBuildingHierarchyBuilderShapeReceiver public: EdgePairBuildingHierarchyBuilderShapeReceiver (); - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } - virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } + virtual void push (const db::Shape &shape, properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &, db::properties_id_type, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } + virtual void push (const db::Polygon &, db::properties_id_type, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } }; /** @@ -199,9 +216,9 @@ class DB_PUBLIC TextBuildingHierarchyBuilderShapeReceiver public: TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout); - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); - virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } - virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } + virtual void push (const db::Shape &shape, properties_id_type prop_id, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &, db::properties_id_type, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } + virtual void push (const db::Polygon &, db::properties_id_type, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } private: db::Layout *mp_layout; @@ -380,6 +397,7 @@ private: tl::weak_ptr mp_target; HierarchyBuilderShapeReceiver *mp_pipe; bool m_initial_pass; + bool m_ignore_properties; db::RecursiveShapeIterator m_source; cell_map_type m_cell_map; original_target_to_variants_map_type m_original_targets_to_variants_map; diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index c40bcfdcb..06df9c844 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -455,7 +455,7 @@ public: } } - virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) + virtual void push (const db::Shape &shape, db::properties_id_type, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) { bool is_text = false; std::string text_string; @@ -498,8 +498,8 @@ public: } } - virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } - virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } + virtual void push (const db::Box &, db::properties_id_type, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } + virtual void push (const db::Polygon &, db::properties_id_type, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } private: Delivery m_delivery; diff --git a/src/db/db/dbShapes.cc b/src/db/db/dbShapes.cc index c738c5aaf..d8b439404 100644 --- a/src/db/db/dbShapes.cc +++ b/src/db/db/dbShapes.cc @@ -469,6 +469,8 @@ template Shapes::shape_type Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_delegate_base &pm) { + db::properties_id_type new_pid = shape.has_prop_id () ? pm (shape.prop_id ()) : 0; + switch (shape.m_type) { case shape_type::Null: default: @@ -478,10 +480,10 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del shape_type::polygon_type p (shape.polygon ()); // Hint: we don't compress so we don't loose information p.transform (t, false); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::PolygonRef: @@ -492,10 +494,10 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del // Hint: we don't compress so we don't loose information p.transform (t, false); // TODO: could create a reference again, but this is what a transform would to as well. - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::SimplePolygon: @@ -503,10 +505,10 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del shape_type::simple_polygon_type p (shape.simple_polygon ()); // Hint: we don't compress so we don't loose information p.transform (t, false); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::SimplePolygonRef: @@ -517,50 +519,50 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del // Hint: we don't compress so we don't loose information p.transform (t, false); // TODO: could create a reference again, but this is what a transform would to as well. - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::Edge: { shape_type::edge_type p (shape.edge ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::Point: { shape_type::point_type p (shape.point ()); p = t.trans (p); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::EdgePair: { shape_type::edge_pair_type p (shape.edge_pair ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::Path: { shape_type::path_type p (shape.path ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::PathRef: @@ -570,10 +572,10 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del shape.path (p); p.transform (t); // TODO: could create a reference again, but this is what a transform would to as well. - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::Box: @@ -584,19 +586,19 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del if (t.is_ortho ()) { shape_type::box_type p (shape.box ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } else { // A box cannot stay a box in this case ... shape_type::simple_polygon_type p (shape.box ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } } @@ -604,10 +606,10 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del { shape_type::text_type p (shape.text ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::TextRef: @@ -617,20 +619,20 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del shape.text (p); p.transform (t); // TODO: could create a reference again, but this is what a transform would to as well. - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::UserObject: { shape_type::user_object_type p (shape.user_object ()); p.transform (t); - if (! shape.has_prop_id ()) { + if (new_pid == 0) { return insert (p); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return insert (db::object_with_properties (p, new_pid)); } } case shape_type::PolygonPtrArray: @@ -709,7 +711,7 @@ Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type p throw tl::Exception (tl::to_string (tr ("Function 'replace_prop_id' is permitted only in editable mode"))); } - if (ref.with_props ()) { + if (ref.has_prop_id ()) { // this assumes we can simply patch the properties ID .. switch (ref.m_type) { @@ -1241,7 +1243,7 @@ Shapes::reinsert_member_with_props (typename db::object_tag, const shape_ty } // the shape types are not equal - resolve into erase and insert (of new) - if (! ref.with_props ()) { + if (! ref.has_prop_id ()) { erase_shape (ref); return insert (sh); } else { @@ -1260,7 +1262,7 @@ Shapes::replace_member_with_props (typename db::object_tag, const shape_typ } // the shape types are not equal - resolve into erase and insert (of new) - if (! ref.with_props ()) { + if (! ref.has_prop_id ()) { erase_shape (ref); return insert (sh); } else { @@ -1310,7 +1312,7 @@ Shapes::replace_member_with_props (typename db::object_tag tag, const shape_ throw tl::Exception (tl::to_string (tr ("Function 'replace' is permitted only in editable mode"))); } - if (! ref.with_props ()) { + if (! ref.has_prop_id ()) { if (manager () && manager ()->transacting ()) { check_is_editable_for_undo_redo (); diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 9ff50a5e1..7f7c2fc8c 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -2199,6 +2199,61 @@ TEST(51_PropertiesFlatFromLayout) EXPECT_EQ (s.at_end (), true); } +TEST(52_PropertiesDeep) +{ + db::DeepShapeStore dss ("TOP", 0.001); + db::Region r (dss); + + // Fill flat region with parts with properties + + r.insert (db::Box (0, 0, 100, 200)); + r.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1)); + r.insert (db::Box (10, 20, 110, 220)); + r.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), 42)); + + EXPECT_EQ (r.count (), size_t (4)); + + db::Region::const_iterator s = r.begin (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (1)); + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (42)); + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + EXPECT_EQ (s.at_end (), true); + + s = r.begin_merged (); + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (0)); + // property #0 elements are merged + EXPECT_EQ (s->to_string (), "(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)"); + ++s; + + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (1)); + // a single property #1 element + EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)"); + ++s; + + EXPECT_EQ (s.at_end (), false); + EXPECT_EQ (s.prop_id (), db::properties_id_type (42)); + // a single property #42 element + EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)"); + ++s; + + EXPECT_EQ (s.at_end (), true); +} + TEST(100_Processors) { db::Region r;