Potential performance improvement for deep-mode DRC

The idea is to use broken regions for certain operations
such as booleans in deep mode (local operations). These polygons are
more efficient. To support this, a "broken polygon" view
is supplied similar for "merged" view. The translation is
handled automatically.

As a side effect, regions may appear to be composed in broken
polygons now when they have been merged before.
This commit is contained in:
Matthias Koefferlein 2026-03-19 12:53:49 +01:00
parent 95f2335fc4
commit 42a008efd1
13 changed files with 320 additions and 27 deletions

View File

@ -401,6 +401,13 @@ DeepRegion::begin_merged () const
}
}
RegionIteratorDelegate *
DeepRegion::begin_unmerged () const
{
ensure_unmerged_polygons_valid ();
return begin ();
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
DeepRegion::begin_iter () const
{
@ -445,6 +452,13 @@ DeepRegion::begin_merged_iter () const
}
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
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<db::DeepLayer &> (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<DeepLayer, DeepLayer>
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 <const DeepRegion *> (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<db::Layout &> (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<db::Layout &> (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 ();
}

View File

@ -66,9 +66,11 @@ public:
virtual RegionIteratorDelegate *begin () const;
virtual RegionIteratorDelegate *begin_merged () const;
virtual RegionIteratorDelegate *begin_unmerged () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> 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<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const;

View File

@ -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 ()
{

View File

@ -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.

View File

@ -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<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> 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; }

View File

@ -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<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_iter () const
{
return std::make_pair (db::RecursiveShapeIterator (*mp_polygons), db::ICplxTrans ());
@ -156,6 +181,12 @@ std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_merged_i
}
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_unmerged_iter () const
{
ensure_unmerged_polygons_valid ();
return begin_iter ();
}
bool FlatRegion::empty () const
{
return mp_polygons->empty ();

View File

@ -51,10 +51,10 @@ public:
typedef db::layer<db::PolygonWithProperties, db::unstable_layer_tag> 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<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> 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<db::Shapes> mp_polygons;
mutable tl::copy_on_write_ptr<db::Shapes> 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 <class Trans>
void transform_generic (const Trans &trans)

View File

@ -317,6 +317,12 @@ OriginalLayerRegion::begin_merged () const
}
}
RegionIteratorDelegate *
OriginalLayerRegion::begin_unmerged () const
{
return begin ();
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
OriginalLayerRegion::begin_iter () const
{
@ -334,6 +340,12 @@ OriginalLayerRegion::begin_merged_iter () const
}
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
OriginalLayerRegion::begin_unmerged_iter () const
{
return std::make_pair (m_iter, m_iter_trans);
}
bool
OriginalLayerRegion::empty () const
{

View File

@ -51,9 +51,11 @@ public:
virtual RegionIteratorDelegate *begin () const;
virtual RegionIteratorDelegate *begin_merged () const;
virtual RegionIteratorDelegate *begin_unmerged () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_unmerged_iter () const;
virtual bool empty () const;

View File

@ -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<db::RecursiveShapeIterator, db::ICplxTrans> begin_unmerged_iter () const
{
return mp_delegate->begin_unmerged_iter ();
}
/**
* @brief Inserts the given shape (working object) into the region
*/

View File

@ -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<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const = 0;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const = 0;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_unmerged_iter () const = 0;
virtual bool empty () const = 0;
virtual bool is_box () const = 0;

View File

@ -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<db::PolygonWithProperties> &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<db::DeepRegion *> (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<db::DeepRegion *> (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<db::DeepRegion *> (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<db::DeepRegion *> (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}");
}

Binary file not shown.