diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 4cc33efa5..81988f1fe 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -401,6 +401,13 @@ DeepRegion::begin_merged () const } } +RegionIteratorDelegate * +DeepRegion::begin_unmerged () const +{ + ensure_unmerged_polygons_valid (); + return begin (); +} + std::pair DeepRegion::begin_iter () const { @@ -445,6 +452,13 @@ DeepRegion::begin_merged_iter () const } } +std::pair +DeepRegion::begin_unmerged_iter () const +{ + ensure_unmerged_polygons_valid (); + return begin_iter (); +} + bool DeepRegion::empty () const { @@ -787,6 +801,46 @@ DeepRegion::ensure_merged_polygons_valid () const } } +void +DeepRegion::ensure_unmerged_polygons_valid () const +{ + if (! m_is_merged || + (deep_layer ().store ()->max_area_ratio () == 0.0 && deep_layer ().store ()->max_vertex_count () == 0)) { + return; + } + + m_merged_polygons = deep_layer ().derived (); + db::DeepLayer &polygons = const_cast (deep_layer ()); + + m_merged_polygons_valid = true; + m_is_merged = false; + m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash (); + + db::Layout &layout = polygons.layout (); + polygons.swap (m_merged_polygons); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); + db::Shapes &st = c->shapes (deep_layer ().layer ()); + + db::PolygonRefToShapesGenerator pr (&layout, &st); + db::PolygonSplitter splitter (pr, polygons.store ()->max_area_ratio (), polygons.store ()->max_vertex_count ()); + + splitter.start (); + for (auto p = s.begin (db::ShapeIterator::All); ! p.at_end (); ++p) { + if (p->is_polygon ()) { + pr.set_prop_id (p->prop_id ()); + db::Polygon poly; + p->polygon (poly); + splitter.put (poly); + } + } + splitter.flush (); + + } +} + void DeepRegion::set_is_merged (bool f) { @@ -922,6 +976,10 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr DeepLayer DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const { + // booleans run better on simple polygons + ensure_unmerged_polygons_valid (); + other->ensure_unmerged_polygons_valid (); + DeepLayer dl_out (deep_layer ().derived ()); if (pc_skip (property_constraint)) { @@ -956,6 +1014,10 @@ DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint prope DeepLayer DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const { + // booleans run better on simple polygons + ensure_unmerged_polygons_valid (); + other->ensure_unmerged_polygons_valid (); + DeepLayer dl_out (deep_layer ().derived ()); DeepLayer dl_prep; @@ -1059,6 +1121,10 @@ DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint prope std::pair DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const { + // booleans run better on simple polygons + ensure_unmerged_polygons_valid (); + other->ensure_unmerged_polygons_valid (); + DeepLayer dl_out1 (deep_layer ().derived ()); DeepLayer dl_out2 (deep_layer ().derived ()); @@ -1179,6 +1245,10 @@ DeepRegion::add_in_place (const Region &other) const DeepRegion *other_deep = dynamic_cast (other.delegate ()); if (other_deep) { + // NOTE: as we don't benefit from merged shapes here, we prefer unmerged ones + // for potentially better performance. + other_deep->ensure_unmerged_polygons_valid (); + deep_layer ().add_from (other_deep->deep_layer ()); } else { @@ -1885,6 +1955,10 @@ DeepRegion::sized (coord_type d, unsigned int mode) const return clone (); } + // in case of negative sizing the output polygons will still be merged (on positive sizing they might + // overlap after size and are not necessarily merged) + bool will_be_merged = (d < 0 && (merged_semantics () || is_merged ())); + const db::DeepLayer &polygons = merged_deep_layer (); db::Layout &layout = const_cast (polygons.layout ()); @@ -1904,7 +1978,8 @@ DeepRegion::sized (coord_type d, unsigned int mode) const db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::PolygonRefToShapesGenerator pr (&layout, &st); - db::PolygonGenerator pg2 (pr, false /*don't resolve holes*/, true /*min. coherence*/); + db::PolygonSplitter splitter (pr, will_be_merged ? 0.0 : polygons.store ()->max_area_ratio (), will_be_merged ? 0 : polygons.store ()->max_vertex_count ()); + db::PolygonGenerator pg2 (splitter, false /*don't resolve holes*/, true /*min. coherence*/); db::SizingPolygonFilter siz (pg2, d_with_mag, d_with_mag, mode); for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { @@ -1916,11 +1991,7 @@ DeepRegion::sized (coord_type d, unsigned int mode) const } - // in case of negative sizing the output polygons will still be merged (on positive sizing they might - // overlap after size and are not necessarily merged) - if (d < 0 && (merged_semantics () || is_merged ())) { - res->set_is_merged (true); - } + res->set_is_merged (will_be_merged); return res.release (); } @@ -1938,6 +2009,10 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const return sized (dx, mode); } + // in case of negative sizing the output polygons will still be merged (on positive sizing they might + // overlap after size and are not necessarily merged) + bool will_be_merged = (dx < 0 && dy < 0 && (merged_semantics () || is_merged ())); + const db::DeepLayer &polygons = merged_deep_layer (); db::Layout &layout = const_cast (polygons.layout ()); @@ -1964,7 +2039,8 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::PolygonRefToShapesGenerator pr (&layout, &st); - db::PolygonGenerator pg2 (pr, false /*don't resolve holes*/, true /*min. coherence*/); + db::PolygonSplitter splitter (pr, will_be_merged ? 0.0 : polygons.store ()->max_area_ratio (), will_be_merged ? 0 : polygons.store ()->max_vertex_count ()); + db::PolygonGenerator pg2 (splitter, false /*don't resolve holes*/, true /*min. coherence*/); db::SizingPolygonFilter siz (pg2, dx_with_mag, dy_with_mag, mode); for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { @@ -1976,11 +2052,7 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const } - // in case of negative sizing the output polygons will still be merged (on positive sizing they might - // overlap after size and are not necessarily merged) - if (dx < 0 && dy < 0 && (merged_semantics () || is_merged ())) { - res->set_is_merged (true); - } + res->set_is_merged (will_be_merged); return res.release (); } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 3d9d5c3fb..ad26af8dc 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -66,9 +66,11 @@ public: virtual RegionIteratorDelegate *begin () const; virtual RegionIteratorDelegate *begin_merged () const; + virtual RegionIteratorDelegate *begin_unmerged () const; virtual std::pair begin_iter () const; virtual std::pair begin_merged_iter () const; + virtual std::pair begin_unmerged_iter () const; virtual bool empty () const; virtual bool is_merged () const; @@ -176,10 +178,11 @@ private: mutable DeepLayer m_merged_polygons; mutable bool m_merged_polygons_valid; mutable size_t m_merged_polygons_boc_hash; - bool m_is_merged; + mutable bool m_is_merged; void init (); void ensure_merged_polygons_valid () const; + void ensure_unmerged_polygons_valid () const; DeepLayer not_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const; DeepLayer and_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const; std::pair and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 9286bd5cf..3973d1b6d 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -232,6 +232,14 @@ bool DeepLayer::operator== (const DeepLayer &other) const return true; } +void +DeepLayer::swap (DeepLayer &other) +{ + tl_assert (mp_store.get () == other.mp_store.get ()); + std::swap (m_layer, other.m_layer); + std::swap (m_layout, other.m_layout); +} + db::Layout & DeepLayer::layout () { diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index b79b8cd59..f60a124f7 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -120,6 +120,11 @@ public: */ bool operator== (const DeepLayer &other) const; + /** + * @brief Swap two layers + */ + void swap (DeepLayer &other); + /** * @brief Gets the layout object * The return value is guaranteed to be non-null. diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index a97e908e7..fb551c9b5 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -46,9 +46,11 @@ public: virtual RegionIteratorDelegate *begin () const { return 0; } virtual RegionIteratorDelegate *begin_merged () const { return 0; } + virtual RegionIteratorDelegate *begin_unmerged () const { return 0; } virtual std::pair begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } virtual std::pair begin_merged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } + virtual std::pair begin_unmerged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } virtual bool empty () const { return true; } virtual size_t count () const { return 0; } diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index 92c4e6609..720f376de 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -33,29 +33,33 @@ namespace db // ------------------------------------------------------------------------------------------------------------- // FlatRegion implementation -FlatRegion::FlatRegion () - : MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)) +FlatRegion::FlatRegion (double area_ratio, size_t max_vertex_count) + : MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), + m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count) { init (); } FlatRegion::FlatRegion (const FlatRegion &other) - : MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons) + : MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons), + m_area_ratio (other.m_area_ratio), m_max_vertex_count (other.m_max_vertex_count) { init (); m_is_merged = other.m_is_merged; m_merged_polygons_valid = other.m_merged_polygons_valid; } -FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged) - : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)) +FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged, double area_ratio, size_t max_vertex_count) + : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), + m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count) { init (); m_is_merged = is_merged; } -FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) - : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)) +FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged, double area_ratio, size_t max_vertex_count) + : MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), + m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count) { init (); m_is_merged = is_merged; @@ -63,8 +67,9 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, set_merged_semantics (merged_semantics); } -FlatRegion::FlatRegion (bool is_merged) - : MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)) +FlatRegion::FlatRegion (bool is_merged, double area_ratio, size_t max_vertex_count) + : MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), + m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count) { init (); m_is_merged = is_merged; @@ -126,6 +131,20 @@ FlatRegion::ensure_merged_polygons_valid () const } } +void +FlatRegion::ensure_unmerged_polygons_valid () const +{ + if (! m_is_merged || (m_area_ratio == 0.0 && m_max_vertex_count == 0)) { + return; + } + + mp_merged_polygons.reset (new db::Shapes (*mp_polygons)); + m_merged_polygons_valid = true; + m_is_merged = false; + + break_polygons (*mp_polygons, m_max_vertex_count, m_area_ratio); +} + RegionIteratorDelegate *FlatRegion::begin () const { return new FlatRegionIterator (mp_polygons.get_const ()); @@ -141,6 +160,12 @@ RegionIteratorDelegate *FlatRegion::begin_merged () const } } +RegionIteratorDelegate *FlatRegion::begin_unmerged () const +{ + ensure_unmerged_polygons_valid (); + return begin (); +} + std::pair FlatRegion::begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (*mp_polygons), db::ICplxTrans ()); @@ -156,6 +181,12 @@ std::pair FlatRegion::begin_merged_i } } +std::pair FlatRegion::begin_unmerged_iter () const +{ + ensure_unmerged_polygons_valid (); + return begin_iter (); +} + bool FlatRegion::empty () const { return mp_polygons->empty (); diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index 3ade8fee6..5610eb061 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -51,10 +51,10 @@ public: typedef db::layer polygon_layer_wp_type; typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type; - FlatRegion (); - FlatRegion (const db::Shapes &polygons, bool is_merged = false); - FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false); - FlatRegion (bool is_merged); + FlatRegion (double area_ratio = 0.0, size_t max_vertex_count = 0); + FlatRegion (const db::Shapes &polygons, bool is_merged = false, double area_ratio = 0.0, size_t max_vertex_count = 0); + FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false, double area_ratio = 0.0, size_t max_vertex_count = 0); + FlatRegion (bool is_merged, double area_ratio = 0.0, size_t max_vertex_count = 0); FlatRegion (const FlatRegion &other); @@ -69,9 +69,11 @@ public: virtual RegionIteratorDelegate *begin () const; virtual RegionIteratorDelegate *begin_merged () const; + virtual RegionIteratorDelegate *begin_unmerged () const; virtual std::pair begin_iter () const; virtual std::pair begin_merged_iter () const; + virtual std::pair begin_unmerged_iter () const; virtual bool empty () const; virtual size_t count () const; @@ -143,13 +145,16 @@ private: FlatRegion &operator= (const FlatRegion &other); - bool m_is_merged; + mutable bool m_is_merged; mutable tl::copy_on_write_ptr mp_polygons; mutable tl::copy_on_write_ptr mp_merged_polygons; mutable bool m_merged_polygons_valid; + double m_area_ratio; + size_t m_max_vertex_count; void init (); void ensure_merged_polygons_valid () const; + void ensure_unmerged_polygons_valid () const; template void transform_generic (const Trans &trans) diff --git a/src/db/db/dbOriginalLayerRegion.cc b/src/db/db/dbOriginalLayerRegion.cc index ccc4c18cf..674ff7ec3 100644 --- a/src/db/db/dbOriginalLayerRegion.cc +++ b/src/db/db/dbOriginalLayerRegion.cc @@ -317,6 +317,12 @@ OriginalLayerRegion::begin_merged () const } } +RegionIteratorDelegate * +OriginalLayerRegion::begin_unmerged () const +{ + return begin (); +} + std::pair OriginalLayerRegion::begin_iter () const { @@ -334,6 +340,12 @@ OriginalLayerRegion::begin_merged_iter () const } } +std::pair +OriginalLayerRegion::begin_unmerged_iter () const +{ + return std::make_pair (m_iter, m_iter_trans); +} + bool OriginalLayerRegion::empty () const { diff --git a/src/db/db/dbOriginalLayerRegion.h b/src/db/db/dbOriginalLayerRegion.h index dd5fe82e5..a72db588b 100644 --- a/src/db/db/dbOriginalLayerRegion.h +++ b/src/db/db/dbOriginalLayerRegion.h @@ -51,9 +51,11 @@ public: virtual RegionIteratorDelegate *begin () const; virtual RegionIteratorDelegate *begin_merged () const; + virtual RegionIteratorDelegate *begin_unmerged () const; virtual std::pair begin_iter () const; virtual std::pair begin_merged_iter () const; + virtual std::pair begin_unmerged_iter () const; virtual bool empty () const; diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 1cd9d1bbd..ce3aeb470 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -349,6 +349,17 @@ public: return RegionIterator (mp_delegate->begin_merged ()); } + /** + * @brief Returns the unmerged polygons + * + * "unmerged" polygons are polygons which are optimized for local operations, + * specifically broken according to the area ratio and max vertex count. + */ + const_iterator begin_unmerged () const + { + return RegionIterator (mp_delegate->begin_unmerged ()); + } + /** * @brief Delivers a RecursiveShapeIterator pointing to the polygons plus the necessary transformation */ @@ -365,6 +376,14 @@ public: return mp_delegate->begin_merged_iter (); } + /** + * @brief Delivers a RecursiveShapeIterator pointing to the unmerged polygons plus the necessary transformation + */ + std::pair begin_unmerged_iter () const + { + return mp_delegate->begin_unmerged_iter (); + } + /** * @brief Inserts the given shape (working object) into the region */ diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index e6714bf56..ff1c90fe4 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -185,9 +185,11 @@ public: virtual RegionIteratorDelegate *begin () const = 0; virtual RegionIteratorDelegate *begin_merged () const = 0; + virtual RegionIteratorDelegate *begin_unmerged () const = 0; virtual std::pair begin_iter () const = 0; virtual std::pair begin_merged_iter () const = 0; + virtual std::pair begin_unmerged_iter () const = 0; virtual bool empty () const = 0; virtual bool is_box () const = 0; diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 947abd71a..55fc38675 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -3158,3 +3158,135 @@ TEST(deep_region_merged_with_pseudo_labels) rr2.merge (); EXPECT_EQ (rr2.to_string (), "(0,0;0,2000;2000,2000;2000,0){A=>17,B=>42};(998,2998;998,3002;1002,3002;1002,2998)"); } + +namespace { + +class AttachPropertiesProcessor + : public db::PolygonProcessorBase +{ +public: + AttachPropertiesProcessor (db::properties_id_type pid) + : m_pid (pid) + { } + + virtual void process (const db::PolygonWithProperties &s, std::vector &res) const + { + res.push_back (db::PolygonWithProperties (s, m_pid)); + } + + virtual bool result_is_merged () const + { + return true; + } + +private: + db::properties_id_type m_pid; +}; + +} + +TEST(deep_unmerged_regions) +{ + db::Layout ly; + + db::Cell &top = ly.cell (ly.add_cell ("TOP")); + + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.insert_layer (db::LayerProperties (2, 0)); + + top.shapes (l1).insert (db::Box (0, 0, 2000, 2000)); + top.shapes (l2).insert (db::Box (200, 200, 1800, 1800)); + + db::DeepShapeStore dss; + dss.set_max_area_ratio (2.0); + + db::Region r1 (db::RecursiveShapeIterator (ly, top, l1), dss); + db::Region r2 (db::RecursiveShapeIterator (ly, top, l2), dss); + + db::DeepRegion *r1_deep = dynamic_cast (r1.delegate ()); + EXPECT_EQ (r1_deep->is_merged (), false); + EXPECT_EQ (r1_deep->merged_polygons_available (), false); + + db::Region r12 = (r1 - r2).merged (); + EXPECT_EQ (r12.to_string (), "(0,0;0,2000;2000,2000;2000,0/200,200;1800,200;1800,1800;200,1800)"); + db::DeepRegion *r12_deep = dynamic_cast (r12.delegate ()); + + EXPECT_EQ (r12_deep->is_merged (), true); + EXPECT_EQ (r12_deep->merged_polygons_available (), true); + + // this will force r12 back into unmerged state, but merged polygons are still available + db::Region rx = r1 | r12; + + EXPECT_EQ (r12_deep->is_merged (), false); + EXPECT_EQ (r12_deep->merged_polygons_available (), true); + EXPECT_EQ (r12.to_string (), "(200,0;200,200;2000,200;2000,0);(1800,200;1800,1000;2000,1000;2000,200);(0,0;0,1000;200,1000;200,0);(1800,1000;1800,2000;2000,2000;2000,1000);(0,1000;0,1800;200,1800;200,1000);(0,1800;0,2000;1800,2000;1800,1800)"); + EXPECT_EQ (rx.to_string (), "(0,0;0,2000;2000,2000;2000,0)"); + + // repeat with properties + + db::PropertiesSet ps; + ps.insert (tl::Variant ("n"), tl::Variant (42)); + auto pid = db::properties_id (ps); + AttachPropertiesProcessor ap (pid); + r12 = (r1 - r2).merged ().processed (ap); + + EXPECT_EQ (r12.to_string (), "(0,0;0,2000;2000,2000;2000,0/200,200;1800,200;1800,1800;200,1800){n=>42}"); + r12_deep = dynamic_cast (r12.delegate ()); + + EXPECT_EQ (r12_deep->is_merged (), true); + EXPECT_EQ (r12_deep->merged_polygons_available (), true); + + rx = r1 | r12; + + EXPECT_EQ (r12_deep->is_merged (), false); + EXPECT_EQ (r12_deep->merged_polygons_available (), true); + EXPECT_EQ (r12.to_string (), "(200,0;200,200;2000,200;2000,0){n=>42};(1800,200;1800,1000;2000,1000;2000,200){n=>42};(0,0;0,1000;200,1000;200,0){n=>42};(1800,1000;1800,2000;2000,2000;2000,1000){n=>42};(0,1000;0,1800;200,1800;200,1000){n=>42};(0,1800;0,2000;1800,2000;1800,1800){n=>42}"); + EXPECT_EQ (rx.to_string (), "(0,0;0,2000;2000,2000;2000,0);(0,0;0,2000;2000,2000;2000,0/200,200;1800,200;1800,1800;200,1800){n=>42}"); + + // now with "+" instead of "|" + + db::Region r12p = (r1 - r2).merged (); + db::DeepRegion *r12p_deep = dynamic_cast (r12p.delegate ()); + + EXPECT_EQ (r12p_deep->is_merged (), true); + EXPECT_EQ (r12p_deep->merged_polygons_available (), true); + + // this will also force r12 back into unmerged state, but merged polygons are still available + db::Region ry = (r1 + r12p).merged (); + + EXPECT_EQ (r12p_deep->is_merged (), false); + EXPECT_EQ (r12p_deep->merged_polygons_available (), true); + EXPECT_EQ (r12p.to_string (), "(200,0;200,200;2000,200;2000,0);(1800,200;1800,1000;2000,1000;2000,200);(0,0;0,1000;200,1000;200,0);(1800,1000;1800,2000;2000,2000;2000,1000);(0,1000;0,1800;200,1800;200,1000);(0,1800;0,2000;1800,2000;1800,1800)"); + EXPECT_EQ (ry.to_string (), "(0,0;0,2000;2000,2000;2000,0)"); +} + +TEST(processed_delivers_polygon_refs) +{ + db::Layout ly; + + db::Cell &top = ly.cell (ly.add_cell ("TOP")); + + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.insert_layer (db::LayerProperties (2, 0)); + + top.shapes (l1).insert (db::Box (0, 0, 2000, 2000)); + top.shapes (l2).insert (db::Box (200, 200, 1800, 1800)); + + db::DeepShapeStore dss; + + db::Region r1 (db::RecursiveShapeIterator (ly, top, l1), dss); + db::Region r2 (db::RecursiveShapeIterator (ly, top, l2), dss); + + db::PropertiesSet ps; + ps.insert (tl::Variant ("n"), tl::Variant (42)); + auto pid = db::properties_id (ps); + AttachPropertiesProcessor ap (pid); + + db::Region r12 = (r1 - r2).merged ().processed (ap); + + r12.set_join_properties_on_merge (true); + + db::Region rx = r1 | r12; + + EXPECT_EQ (rx.to_string (), "(0,0;0,2000;2000,2000;2000,0);(0,0;0,2000;2000,2000;2000,0/200,200;1800,200;1800,1800;200,1800){n=>42}"); +} diff --git a/testdata/algo/deep_region_au9a.gds b/testdata/algo/deep_region_au9a.gds index 16dd35174..615373aae 100644 Binary files a/testdata/algo/deep_region_au9a.gds and b/testdata/algo/deep_region_au9a.gds differ