diff --git a/src/db/db/dbFlatEdges.cc b/src/db/db/dbFlatEdges.cc index e011bbf6f..0d08ec5bb 100644 --- a/src/db/db/dbFlatEdges.cc +++ b/src/db/db/dbFlatEdges.cc @@ -33,7 +33,7 @@ namespace db // FlatEdges implementation FlatEdges::FlatEdges () - : AsIfFlatEdges (), m_edges (false), m_merged_edges (false) + : AsIfFlatEdges (), mp_edges (new db::Shapes (false)), mp_merged_edges (new db::Shapes (false)) { init (); } @@ -44,18 +44,16 @@ FlatEdges::~FlatEdges () } FlatEdges::FlatEdges (const FlatEdges &other) - : AsIfFlatEdges (other), m_edges (false), m_merged_edges (false) + : AsIfFlatEdges (other), mp_edges (other.mp_edges), mp_merged_edges (other.mp_merged_edges) { init (); m_is_merged = other.m_is_merged; - m_edges = other.m_edges; - m_merged_edges = other.m_merged_edges; m_merged_edges_valid = other.m_merged_edges_valid; } FlatEdges::FlatEdges (const db::Shapes &edges, bool is_merged) - : AsIfFlatEdges (), m_edges (edges), m_merged_edges (false) + : AsIfFlatEdges (), mp_edges (new db::Shapes (edges)), mp_merged_edges (new db::Shapes (false)) { init (); @@ -63,7 +61,7 @@ FlatEdges::FlatEdges (const db::Shapes &edges, bool is_merged) } FlatEdges::FlatEdges (bool is_merged) - : AsIfFlatEdges (), m_edges (false), m_merged_edges (false) + : AsIfFlatEdges (), mp_edges (new db::Shapes (false)), mp_merged_edges (new db::Shapes (false)) { init (); @@ -78,7 +76,7 @@ void FlatEdges::set_is_merged (bool m) void FlatEdges::invalidate_cache () { invalidate_bbox (); - m_merged_edges.clear (); + mp_merged_edges->clear (); m_merged_edges_valid = false; } @@ -90,18 +88,18 @@ void FlatEdges::init () void FlatEdges::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - layout->cell (into_cell).shapes (into_layer).insert (m_edges); + layout->cell (into_cell).shapes (into_layer).insert (*mp_edges); } void FlatEdges::merged_semantics_changed () { - m_merged_edges.clear (); + mp_merged_edges->clear (); m_merged_edges_valid = false; } void FlatEdges::reserve (size_t n) { - m_edges.reserve (db::Edge::tag (), n); + mp_edges->reserve (db::Edge::tag (), n); } void @@ -109,13 +107,13 @@ FlatEdges::ensure_merged_edges_valid () const { if (! m_merged_edges_valid) { - m_merged_edges.clear (); + mp_merged_edges->clear (); db::Shapes tmp (false); EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr); db::box_scanner scanner (report_progress (), progress_desc ()); - scanner.reserve (m_edges.size ()); + scanner.reserve (mp_edges->size ()); for (EdgesIterator e (begin ()); ! e.at_end (); ++e) { if (! e->is_degenerate ()) { @@ -125,7 +123,7 @@ FlatEdges::ensure_merged_edges_valid () const scanner.process (cluster_collector, 1, db::box_convert ()); - m_merged_edges.swap (tmp); + mp_merged_edges->swap (tmp); m_merged_edges_valid = true; } @@ -133,7 +131,7 @@ FlatEdges::ensure_merged_edges_valid () const EdgesIteratorDelegate *FlatEdges::begin () const { - return new FlatEdgesIterator (&m_edges); + return new FlatEdgesIterator (mp_edges.get_const ()); } EdgesIteratorDelegate *FlatEdges::begin_merged () const @@ -142,13 +140,13 @@ EdgesIteratorDelegate *FlatEdges::begin_merged () const return begin (); } else { ensure_merged_edges_valid (); - return new FlatEdgesIterator (&m_merged_edges); + return new FlatEdgesIterator (mp_merged_edges.get_const ()); } } std::pair FlatEdges::begin_iter () const { - return std::make_pair (db::RecursiveShapeIterator (m_edges), db::ICplxTrans ()); + return std::make_pair (db::RecursiveShapeIterator (*mp_edges), db::ICplxTrans ()); } std::pair FlatEdges::begin_merged_iter () const @@ -157,23 +155,23 @@ std::pair FlatEdges::begin_merged_it return begin_iter (); } else { ensure_merged_edges_valid (); - return std::make_pair (db::RecursiveShapeIterator (m_merged_edges), db::ICplxTrans ()); + return std::make_pair (db::RecursiveShapeIterator (*mp_merged_edges), db::ICplxTrans ()); } } bool FlatEdges::empty () const { - return m_edges.empty (); + return mp_edges->empty (); } size_t FlatEdges::count () const { - return m_edges.size (); + return mp_edges->size (); } size_t FlatEdges::hier_count () const { - return m_edges.size (); + return mp_edges->size (); } bool FlatEdges::is_merged () const @@ -183,8 +181,8 @@ bool FlatEdges::is_merged () const Box FlatEdges::compute_bbox () const { - m_edges.update_bbox (); - return m_edges.bbox (); + mp_edges->update_bbox (); + return mp_edges->bbox (); } EdgesDelegate * @@ -192,25 +190,27 @@ FlatEdges::processed_in_place (const EdgeProcessorBase &filter) { std::vector edge_res; - edge_iterator_type pw = m_edges.get_layer ().begin (); + db::Shapes &e = *mp_edges; + + edge_iterator_type pw = e.get_layer ().begin (); for (EdgesIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { edge_res.clear (); filter.process (*p, edge_res); for (std::vector::const_iterator pr = edge_res.begin (); pr != edge_res.end (); ++pr) { - if (pw == m_edges.get_layer ().end ()) { - m_edges.get_layer ().insert (*pr); - pw = m_edges.get_layer ().end (); + if (pw == e.get_layer ().end ()) { + e.get_layer ().insert (*pr); + pw = e.get_layer ().end (); } else { - m_edges.get_layer ().replace (pw++, *pr); + e.get_layer ().replace (pw++, *pr); } } } - m_edges.get_layer ().erase (pw, m_edges.get_layer ().end ()); - m_merged_edges.clear (); + e.get_layer ().erase (pw, e.get_layer ().end ()); + mp_merged_edges->clear (); m_is_merged = filter.result_is_merged () && merged_semantics (); return this; @@ -219,20 +219,22 @@ FlatEdges::processed_in_place (const EdgeProcessorBase &filter) EdgesDelegate * FlatEdges::filter_in_place (const EdgeFilterBase &filter) { - edge_iterator_type pw = m_edges.get_layer ().begin (); + db::Shapes &e = *mp_edges; + + edge_iterator_type pw = e.get_layer ().begin (); for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) { if (filter.selected (*p)) { - if (pw == m_edges.get_layer ().end ()) { - m_edges.get_layer ().insert (*p); - pw = m_edges.get_layer ().end (); + if (pw == e.get_layer ().end ()) { + e.get_layer ().insert (*p); + pw = e.get_layer ().end (); } else { - m_edges.get_layer ().replace (pw++, *p); + e.get_layer ().replace (pw++, *p); } } } - m_edges.get_layer ().erase (pw, m_edges.get_layer ().end ()); - m_merged_edges.clear (); + e.get_layer ().erase (pw, e.get_layer ().end ()); + mp_merged_edges->clear (); m_is_merged = merged_semantics (); return this; @@ -272,22 +274,24 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other) invalidate_cache (); m_is_merged = false; + db::Shapes &e = *mp_edges; + FlatEdges *other_flat = dynamic_cast (other.delegate ()); if (other_flat) { - m_edges.insert (other_flat->raw_edges ().get_layer ().begin (), other_flat->raw_edges ().get_layer ().end ()); + e.insert (other_flat->raw_edges ().get_layer ().begin (), other_flat->raw_edges ().get_layer ().end ()); } else { - size_t n = m_edges.size (); + size_t n = e.size (); for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) { ++n; } - m_edges.reserve (db::Edge::tag (), n); + e.reserve (db::Edge::tag (), n); for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) { - m_edges.insert (*p); + e.insert (*p); } } @@ -297,7 +301,7 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other) const db::Edge *FlatEdges::nth (size_t n) const { - return n < m_edges.size () ? &m_edges.get_layer ().begin () [n] : 0; + return n < mp_edges->size () ? &mp_edges->get_layer ().begin () [n] : 0; } bool FlatEdges::has_valid_edges () const @@ -322,10 +326,11 @@ FlatEdges::insert (const db::Box &box) bool was_empty = empty (); - m_edges.insert (db::Edge (box.lower_left (), box.upper_left ())); - m_edges.insert (db::Edge (box.upper_left (), box.upper_right ())); - m_edges.insert (db::Edge (box.upper_right (), box.lower_right ())); - m_edges.insert (db::Edge (box.lower_right (), box.lower_left ())); + db::Shapes &e = *mp_edges; + e.insert (db::Edge (box.lower_left (), box.upper_left ())); + e.insert (db::Edge (box.upper_left (), box.upper_right ())); + e.insert (db::Edge (box.upper_right (), box.lower_right ())); + e.insert (db::Edge (box.lower_right (), box.lower_left ())); if (was_empty) { @@ -354,8 +359,9 @@ void FlatEdges::insert (const db::Polygon &polygon) { if (polygon.holes () > 0 || polygon.vertices () > 0) { + db::Shapes &edges = *mp_edges; for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) { - m_edges.insert (*e); + edges.insert (*e); } m_is_merged = false; invalidate_cache (); @@ -366,8 +372,9 @@ void FlatEdges::insert (const db::SimplePolygon &polygon) { if (polygon.vertices () > 0) { + db::Shapes &edges = *mp_edges; for (db::SimplePolygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) { - m_edges.insert (*e); + edges.insert (*e); } m_is_merged = false; invalidate_cache (); @@ -381,7 +388,7 @@ FlatEdges::insert (const db::Edge &edge) m_is_merged = false; } - m_edges.insert (edge); + mp_edges->insert (edge); invalidate_cache (); } diff --git a/src/db/db/dbFlatEdges.h b/src/db/db/dbFlatEdges.h index e4a7ede84..8ec467167 100644 --- a/src/db/db/dbFlatEdges.h +++ b/src/db/db/dbFlatEdges.h @@ -30,6 +30,7 @@ #include "dbShapes.h" #include "dbShapes2.h" #include "dbGenericShapeIterator.h" +#include "tlCopyOnWrite.h" namespace db { @@ -138,14 +139,16 @@ public: void transform (const Trans &trans) { if (! trans.is_unity ()) { - for (edge_iterator_type p = m_edges.template get_layer ().begin (); p != m_edges.get_layer ().end (); ++p) { - m_edges.get_layer ().replace (p, p->transformed (trans)); + db::Shapes &e = *mp_edges; + for (edge_iterator_type p = e.template get_layer ().begin (); p != e.get_layer ().end (); ++p) { + e.get_layer ().replace (p, p->transformed (trans)); } invalidate_cache (); } } - db::Shapes &raw_edges () { return m_edges; } + db::Shapes &raw_edges () { return *mp_edges; } + const db::Shapes &raw_edges () const { return *mp_edges; } protected: virtual void merged_semantics_changed (); @@ -159,8 +162,8 @@ private: FlatEdges &operator= (const FlatEdges &other); bool m_is_merged; - mutable db::Shapes m_edges; - mutable db::Shapes m_merged_edges; + mutable tl::copy_on_write_ptr mp_edges; + mutable tl::copy_on_write_ptr mp_merged_edges; mutable bool m_merged_edges_valid; void init (); diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index ea81f9481..9d641a553 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -33,7 +33,7 @@ namespace db // FlatRegion implementation FlatRegion::FlatRegion () - : AsIfFlatRegion (), m_polygons (false), m_merged_polygons (false) + : AsIfFlatRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)) { init (); } @@ -44,18 +44,16 @@ FlatRegion::~FlatRegion () } FlatRegion::FlatRegion (const FlatRegion &other) - : AsIfFlatRegion (other), m_polygons (false), m_merged_polygons (false) + : AsIfFlatRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons) { init (); m_is_merged = other.m_is_merged; - m_polygons = other.m_polygons; - m_merged_polygons = other.m_merged_polygons; m_merged_polygons_valid = other.m_merged_polygons_valid; } FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged) - : AsIfFlatRegion (), m_polygons (polygons), m_merged_polygons (false) + : AsIfFlatRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)) { init (); @@ -63,7 +61,7 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged) } FlatRegion::FlatRegion (bool is_merged) - : AsIfFlatRegion (), m_polygons (false), m_merged_polygons (false) + : AsIfFlatRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)) { init (); @@ -78,7 +76,7 @@ void FlatRegion::set_is_merged (bool m) void FlatRegion::invalidate_cache () { invalidate_bbox (); - m_merged_polygons.clear (); + mp_merged_polygons->clear (); m_merged_polygons_valid = false; } @@ -90,20 +88,20 @@ void FlatRegion::init () void FlatRegion::merged_semantics_changed () { - m_merged_polygons.clear (); + mp_merged_polygons->clear (); m_merged_polygons_valid = false; } void FlatRegion::min_coherence_changed () { m_is_merged = false; - m_merged_polygons.clear (); + mp_merged_polygons->clear (); m_merged_polygons_valid = false; } void FlatRegion::reserve (size_t n) { - m_polygons.reserve (db::Polygon::tag (), n); + mp_polygons->reserve (db::Polygon::tag (), n); } void @@ -111,7 +109,7 @@ FlatRegion::ensure_merged_polygons_valid () const { if (! m_merged_polygons_valid) { - m_merged_polygons.clear (); + mp_merged_polygons->clear (); db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); @@ -131,7 +129,7 @@ FlatRegion::ensure_merged_polygons_valid () const // and run the merge step db::MergeOp op (0); - db::ShapeGenerator pc (m_merged_polygons); + db::ShapeGenerator pc (*mp_merged_polygons); db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); ep.process (pg, op); @@ -142,7 +140,7 @@ FlatRegion::ensure_merged_polygons_valid () const RegionIteratorDelegate *FlatRegion::begin () const { - return new FlatRegionIterator (&m_polygons); + return new FlatRegionIterator (mp_polygons.get_const ()); } RegionIteratorDelegate *FlatRegion::begin_merged () const @@ -151,13 +149,13 @@ RegionIteratorDelegate *FlatRegion::begin_merged () const return begin (); } else { ensure_merged_polygons_valid (); - return new FlatRegionIterator (&m_merged_polygons); + return new FlatRegionIterator (mp_merged_polygons.get_const ()); } } std::pair FlatRegion::begin_iter () const { - return std::make_pair (db::RecursiveShapeIterator (m_polygons), db::ICplxTrans ()); + return std::make_pair (db::RecursiveShapeIterator (*mp_polygons), db::ICplxTrans ()); } std::pair FlatRegion::begin_merged_iter () const @@ -166,23 +164,23 @@ std::pair FlatRegion::begin_merged_i return begin_iter (); } else { ensure_merged_polygons_valid (); - return std::make_pair (db::RecursiveShapeIterator (m_merged_polygons), db::ICplxTrans ()); + return std::make_pair (db::RecursiveShapeIterator (*mp_merged_polygons), db::ICplxTrans ()); } } bool FlatRegion::empty () const { - return m_polygons.empty (); + return mp_polygons->empty (); } size_t FlatRegion::count () const { - return m_polygons.size (); + return mp_polygons->size (); } size_t FlatRegion::hier_count () const { - return m_polygons.size (); + return mp_polygons->size (); } bool FlatRegion::is_merged () const @@ -192,13 +190,13 @@ bool FlatRegion::is_merged () const Box FlatRegion::compute_bbox () const { - m_polygons.update_bbox (); - return m_polygons.bbox (); + mp_polygons->update_bbox (); + return mp_polygons->bbox (); } RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) { - db::layer &poly_layer = m_polygons.get_layer (); + db::layer &poly_layer = mp_polygons->get_layer (); polygon_iterator_type pw = poly_layer.begin (); for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { @@ -214,7 +212,7 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) poly_layer.erase (pw, poly_layer.end ()); - m_merged_polygons.clear (); + mp_merged_polygons->clear (); m_is_merged = filter.requires_raw_input () ? false : merged_semantics (); return this; @@ -222,7 +220,7 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter) { - db::layer &poly_layer = m_polygons.get_layer (); + db::layer &poly_layer = mp_polygons->get_layer (); db::layer out; std::vector poly_res; @@ -234,7 +232,7 @@ RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter poly_layer.swap (out); - m_merged_polygons.clear (); + mp_merged_polygons->clear (); m_is_merged = filter.result_is_merged () && merged_semantics (); if (filter.result_must_not_be_merged ()) { @@ -250,8 +248,9 @@ RegionDelegate *FlatRegion::merged_in_place () if (m_merged_polygons_valid) { - m_polygons.swap (m_merged_polygons); - m_merged_polygons.clear (); + db::Shapes &merged_polygons = *mp_merged_polygons; + mp_polygons->swap (merged_polygons); + merged_polygons.clear (); m_is_merged = true; return this; @@ -300,7 +299,7 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi // and run the merge step db::MergeOp op (min_wc); - db::ShapeGenerator pc (m_polygons, true /*clear*/); + db::ShapeGenerator pc (*mp_polygons, true /*clear*/); db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); ep.process (pg, op); @@ -316,7 +315,7 @@ RegionDelegate *FlatRegion::merged () const if (! m_is_merged) { if (m_merged_polygons_valid) { - return new FlatRegion (m_merged_polygons, true); + return new FlatRegion (*mp_merged_polygons, true); } else { return AsIfFlatRegion::merged (min_coherence (), 0); } @@ -360,22 +359,24 @@ RegionDelegate *FlatRegion::add_in_place (const Region &other) invalidate_cache (); m_is_merged = false; + db::Shapes &polygons = *mp_polygons; + FlatRegion *other_flat = dynamic_cast (other.delegate ()); if (other_flat) { - m_polygons.insert (other_flat->raw_polygons ().get_layer ().begin (), other_flat->raw_polygons ().get_layer ().end ()); + polygons.insert (other_flat->raw_polygons ().get_layer ().begin (), other_flat->raw_polygons ().get_layer ().end ()); } else { - size_t n = m_polygons.size (); + size_t n = polygons.size (); for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { ++n; } - m_polygons.reserve (db::Polygon::tag (), n); + polygons.reserve (db::Polygon::tag (), n); for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - m_polygons.insert (*p); + polygons.insert (*p); } } @@ -385,7 +386,7 @@ RegionDelegate *FlatRegion::add_in_place (const Region &other) const db::Polygon *FlatRegion::nth (size_t n) const { - return n < m_polygons.size () ? &m_polygons.get_layer ().begin () [n] : 0; + return n < mp_polygons->size () ? &mp_polygons->get_layer ().begin () [n] : 0; } bool FlatRegion::has_valid_polygons () const @@ -405,7 +406,7 @@ const db::RecursiveShapeIterator *FlatRegion::iter () const void FlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - layout->cell (into_cell).shapes (into_layer).insert (m_polygons); + layout->cell (into_cell).shapes (into_layer).insert (*mp_polygons); } void @@ -415,13 +416,13 @@ FlatRegion::insert (const db::Box &box) if (empty ()) { - m_polygons.insert (db::Polygon (box)); + mp_polygons->insert (db::Polygon (box)); m_is_merged = true; update_bbox (box); } else { - m_polygons.insert (db::Polygon (box)); + mp_polygons->insert (db::Polygon (box)); m_is_merged = false; invalidate_cache (); @@ -434,7 +435,7 @@ void FlatRegion::insert (const db::Path &path) { if (path.points () > 0) { - m_polygons.insert (path.polygon ()); + mp_polygons->insert (path.polygon ()); m_is_merged = false; invalidate_cache (); } @@ -444,7 +445,7 @@ void FlatRegion::insert (const db::Polygon &polygon) { if (polygon.holes () > 0 || polygon.vertices () > 0) { - m_polygons.insert (polygon); + mp_polygons->insert (polygon); m_is_merged = false; invalidate_cache (); } @@ -456,7 +457,7 @@ FlatRegion::insert (const db::SimplePolygon &polygon) if (polygon.vertices () > 0) { db::Polygon poly; poly.assign_hull (polygon.begin_hull (), polygon.end_hull ()); - m_polygons.insert (poly); + mp_polygons->insert (poly); m_is_merged = false; invalidate_cache (); } @@ -468,7 +469,7 @@ FlatRegion::insert (const db::Shape &shape) if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { db::Polygon poly; shape.polygon (poly); - m_polygons.insert (poly); + mp_polygons->insert (poly); m_is_merged = false; invalidate_cache (); } diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index b4c762266..c79268c98 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -29,6 +29,7 @@ #include "dbAsIfFlatRegion.h" #include "dbShapes.h" #include "dbShapes2.h" +#include "tlCopyOnWrite.h" namespace db { @@ -134,14 +135,16 @@ public: void transform (const Trans &trans) { if (! trans.is_unity ()) { - for (polygon_iterator_type p = m_polygons.get_layer ().begin (); p != m_polygons.get_layer ().end (); ++p) { - m_polygons.get_layer ().replace (p, p->transformed (trans)); + db::Shapes &polygons = *mp_polygons; + for (polygon_iterator_type p = polygons.get_layer ().begin (); p != polygons.get_layer ().end (); ++p) { + polygons.get_layer ().replace (p, p->transformed (trans)); } invalidate_cache (); } } - db::Shapes &raw_polygons () { return m_polygons; } + db::Shapes &raw_polygons () { return *mp_polygons; } + const db::Shapes &raw_polygons () const { return *mp_polygons; } protected: virtual void merged_semantics_changed (); @@ -157,8 +160,8 @@ private: FlatRegion &operator= (const FlatRegion &other); bool m_is_merged; - mutable db::Shapes m_polygons; - mutable db::Shapes m_merged_polygons; + mutable tl::copy_on_write_ptr mp_polygons; + mutable tl::copy_on_write_ptr mp_merged_polygons; mutable bool m_merged_polygons_valid; void init ();