From eafa97a862a38318e34a150e131db8db894aa1a0 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Mon, 13 Jan 2025 17:06:58 +0100 Subject: [PATCH] major cleanup of Polyline_constraint_hierarchy_2 - remove all mentions of `Edge` and `Constraint` - `Subconstraint_iterator` is renamed `Subconstraint_and_contexts_iterator` (because of its value type) - a new `Subconstraint_iterator`, with value type `Subconstraint` - a few unused/untested and uncompilable functions are removed from the code - a lot of internal renamings == Breaking changes == For `Constrained_triangulation_plus_2`, there are a few breaking changes... - The value type of `subconstraints_begin()`, `subconstraints_end()`, of the range `subconstraints()` has changed to `Subconstraint` (a simple `std::pair` of vertex handles). That is actually a kind of bug-fix, because it was documented as such in the user manual. - The new member functions `subconstraints_and_contexts_begin()`, `subconstraints_and_contexts_end()`, `subconstraints_and_contexts()` are created get the old value type (`std::pair*>`). - A few range types have changed from `CGAL::Iterator_range` to `unspecified_type`, for efficiency reasons. - Doc fixes. == Determinism == Even if it was not documented, the range `subconstraints()` is deterministic (used by Mesh_2), and `subconstraints_and_contexts()` is not. --- Mesh_2/include/CGAL/Mesh_2/Clusters.h | 7 +- Mesh_2/include/CGAL/Mesh_2/Refine_edges.h | 2 +- Mesh_2/test/Mesh_2/conform_plus.cpp | 19 +- .../CGAL/Constrained_triangulation_plus_2.h | 46 ++- .../constrained_hierarchy_plus.cpp | 10 +- .../polylines_triangulation.cpp | 7 +- .../CGAL/Constrained_triangulation_plus_2.h | 83 ++++- .../internal/CTP2_subconstraint_graph.h | 107 +++---- .../Polyline_constraint_hierarchy_2.h | 294 +++++++++--------- 9 files changed, 302 insertions(+), 273 deletions(-) diff --git a/Mesh_2/include/CGAL/Mesh_2/Clusters.h b/Mesh_2/include/CGAL/Mesh_2/Clusters.h index f52dcb16d206..13533041f469 100644 --- a/Mesh_2/include/CGAL/Mesh_2/Clusters.h +++ b/Mesh_2/include/CGAL/Mesh_2/Clusters.h @@ -160,15 +160,14 @@ class Clusters void create_clusters(Tag_true) { cluster_map.clear(); Unique_hash_map created(false); - for(typename Tr::Subconstraint_iterator it = tr.subconstraints_begin(); - it != tr.subconstraints_end(); ++it) { - Vertex_handle vh = it->first.first; + for(const auto& sc : tr.subconstraints()) { + Vertex_handle vh = sc.first; if(!created[vh]){ created[vh] = true; create_clusters_of_vertex(vh); } - vh = it->first.second; + vh = sc.second; if(!created[vh]){ created[vh] = true; create_clusters_of_vertex(vh); diff --git a/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h b/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h index 055ae0d7a213..2208f28fc453 100644 --- a/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h +++ b/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h @@ -344,7 +344,7 @@ class Refine_edges_base : void scan_triangulation_impl(Tag_true) { - for(const auto& [v1, v2] : tr.hierarchy_ref().edges()) + for(const auto& [v1, v2] : tr.subconstraints()) { if(!is_locally_conform(tr, v1, v2) ){ add_constrained_edge_to_be_conformed(v1, v2); diff --git a/Mesh_2/test/Mesh_2/conform_plus.cpp b/Mesh_2/test/Mesh_2/conform_plus.cpp index 83978e3d9ef8..6e4128dd68e6 100644 --- a/Mesh_2/test/Mesh_2/conform_plus.cpp +++ b/Mesh_2/test/Mesh_2/conform_plus.cpp @@ -18,15 +18,7 @@ int main() std::pair p; - for(CDT::Subconstraint_iterator sit = cdt.subconstraints_begin(); - sit != cdt.subconstraints_end(); - ++sit){ - - p = (*sit).first; - - Vertex_handle vh1 = p.first; - Vertex_handle vh2 = p.second; - + for(const auto& [vh1, vh2] : cdt.subconstraints()) { std::cerr << "subconstraint: " << vh1->point() << " -- " << vh2->point() << std::endl; } @@ -36,15 +28,8 @@ int main() int counter = 0; - for(CDT::Subconstraint_iterator sit = cdt.subconstraints_begin(); - sit != cdt.subconstraints_end(); - ++sit){ + for(const auto& [vh1, vh2] : cdt.subconstraints()) { ++counter; - p = (*sit).first; - - Vertex_handle vh1 = p.first; - Vertex_handle vh2 = p.second; - std::cerr << "subconstraint: " << vh1->point() << " -- " << vh2->point() << std::endl; } diff --git a/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h b/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h index 29d2b48d7456..1a5d4b691f09 100644 --- a/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h +++ b/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h @@ -84,9 +84,10 @@ The value type of this iterator is `Constraint_id`. typedef unspecified_type Constraint_iterator; /*! -A range type for iterating over all constraints. +A range type for iterating over all constraints. The iterator type of +the range is `Constraint_iterator`. */ -typedef Iterator_range Constraints; +typedef unspecified_type Constraints; /*! @@ -95,19 +96,30 @@ A subconstraint is a pair of vertices that correspond to an `Edge`. typedef std::pair Subconstraint; /*! -An iterator -to visit all the subconstraints of the triangulation. +An iterator to visit all the subconstraints of the triangulation. The order of visit is undefined. -The value type of this iterator is `std::pair*>` -corresponding to the vertices of the -subconstraint. +The value type of this iterator is `Subconstraint`. */ typedef unspecified_type Subconstraint_iterator; /*! -A range type for iterating over all subconstraints. +A range type for iterating over all subconstraints. The iterator type of +the range is `Subconstraint_iterator`. */ -typedef Iterator_range Subconstraints; +typedef unspecified_type Subconstraints; + +/*! +An iterator to visit all the subconstraints of the triangulation and the +contexts of their enclosing constraints. The order of visit is undefined. +The value type of this iterator is `std::pair*>`. +*/ +typedef unspecified_type Subconstraint_and_contexts_iterator; + +/*! +A range type for iterating over all subconstraints. The iterator type of +the range is `Subconstraint_and_contexts_iterator`. +*/ +typedef unspecified_type Subconstraints_and_contexts; /*! An iterator on the @@ -381,6 +393,22 @@ returns a range of subconstraints. */ Subconstraints subconstraints() const; +/*! +returns a `Subconstraint_and_contexts_iterator` pointing at the first +subconstraint of the triangulation. +*/ +Subconstraint_and_contexts_iterator subconstraints_and_contexts_begin() const; + +/*! +returns the past-the-end iterator of the subconstraints of the triangulation. +*/ +Subconstraint_and_contexts_iterator subconstraints_and_contexts_end() const; + +/*! +returns a range of subconstraints with the contexts of their enclosing constraints. +*/ +Subconstraints_and_contexts subconstraints_and_contexts() const; + /*! returns the number of constraints enclosing the subconstraint `(va,vb)`. diff --git a/Triangulation_2/examples/Triangulation_2/constrained_hierarchy_plus.cpp b/Triangulation_2/examples/Triangulation_2/constrained_hierarchy_plus.cpp index 950cb0226320..b243e152693d 100644 --- a/Triangulation_2/examples/Triangulation_2/constrained_hierarchy_plus.cpp +++ b/Triangulation_2/examples/Triangulation_2/constrained_hierarchy_plus.cpp @@ -30,15 +30,15 @@ main( ) cdt.insert_constraint( Point(j,0), Point(j,6)); int count = 0; - for (Triangulation::Subconstraint_iterator scit = cdt.subconstraints_begin(); - scit != cdt.subconstraints_end(); - ++scit) ++count; + for (const Triangulation::Subconstraint& sc : cdt.subconstraints()) { + ++count; + } std::cout << "The number of resulting constrained edges is "; std::cout << count << std::endl; //verbose mode of is_valid ; shows the number of vertices at each level std::cout << "The number of vertices at successive levels" << std::endl; - assert(cdt.is_valid(true)); + bool valid = cdt.is_valid(true); - return 0; + return valid ? 0 : 1; } diff --git a/Triangulation_2/examples/Triangulation_2/polylines_triangulation.cpp b/Triangulation_2/examples/Triangulation_2/polylines_triangulation.cpp index bc00e7071ba9..b2b38e937655 100644 --- a/Triangulation_2/examples/Triangulation_2/polylines_triangulation.cpp +++ b/Triangulation_2/examples/Triangulation_2/polylines_triangulation.cpp @@ -28,13 +28,14 @@ print(const CDTP& cdtp, Cid cid) void contexts(const CDTP& cdtp) { - for(auto sc : cdtp.subconstraints()){ - Vertex_handle vp = sc.first.first, vq = sc.first.second; + for(const auto& sc_and_contexts : cdtp.subconstraints_and_contexts()) { + const auto& [subconstraint, contexts_list_ptr] = sc_and_contexts; + Vertex_handle vp = subconstraint.first, vq = subconstraint.second; if(cdtp.number_of_enclosing_constraints(vp, vq) == 2){ std::cout << "subconstraint " << vp->point() << " " << vq->point() << " is on constraints starting at:\n"; - for(const CDTP::Context& c : cdtp.contexts(vp,vq)){ + for(const CDTP::Context& c : *contexts_list_ptr) { std::cout << (*(c.vertices_begin()))->point() << std::endl; } } diff --git a/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h b/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h index ac3889c53416..1d4cd0dcbfb3 100644 --- a/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h +++ b/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h @@ -165,11 +165,14 @@ class Constrained_triangulation_plus_2 typedef typename Constraint_hierarchy::Context_iterator Context_iterator; typedef Iterator_range Contexts; - typedef typename Constraint_hierarchy::C_iterator Constraint_iterator; - typedef Iterator_range Constraints; + typedef typename Constraint_hierarchy::Constraint_iterator Constraint_iterator; + typedef typename Constraint_hierarchy::Constraints Constraints; - typedef typename Constraint_hierarchy::Subconstraint_iterator Subconstraint_iterator; - typedef Iterator_range Subconstraints; + typedef typename Constraint_hierarchy::Subconstraint_iterator Subconstraint_iterator; + typedef typename Constraint_hierarchy::Subconstraints Subconstraints; + + typedef typename Constraint_hierarchy::Subconstraint_and_contexts_iterator Subconstraint_and_contexts_iterator; + typedef typename Constraint_hierarchy::Subconstraints_and_contexts Subconstraints_and_contexts; typedef typename Constraint_hierarchy::Constraint_id Constraint_id; @@ -768,18 +771,15 @@ class Constrained_triangulation_plus_2 // Query of the constraint hierarchy Constraint_iterator constraints_begin() const; Constraint_iterator constraints_end() const; - Constraints constraints() const - { - return Constraints(constraints_begin(),constraints_end()); - } + Constraints constraints() const; Subconstraint_iterator subconstraints_begin() const; Subconstraint_iterator subconstraints_end() const; + Subconstraints subconstraints() const; - Subconstraints subconstraints() const - { - return Subconstraints(subconstraints_begin(),subconstraints_end()); - } + Subconstraint_and_contexts_iterator subconstraints_and_contexts_begin() const; + Subconstraint_and_contexts_iterator subconstraints_and_contexts_end() const; + Subconstraints_and_contexts subconstraints_and_contexts() const; Context context(Vertex_handle va, Vertex_handle vb); //AF: const; @@ -1266,7 +1266,7 @@ Constrained_triangulation_plus_2::Constraint_iterator Constrained_triangulation_plus_2:: constraints_begin() const { - return hierarchy.c_begin(); + return hierarchy.constraints_begin(); } template @@ -1276,7 +1276,17 @@ Constrained_triangulation_plus_2::Constraint_iterator Constrained_triangulation_plus_2:: constraints_end() const { - return hierarchy.c_end(); + return hierarchy.constraints_end(); +} + +template +inline +typename +Constrained_triangulation_plus_2::Constraints +Constrained_triangulation_plus_2:: +constraints() const +{ + return hierarchy.constraints(); } template @@ -1286,7 +1296,7 @@ Constrained_triangulation_plus_2::Subconstraint_iterator Constrained_triangulation_plus_2:: subconstraints_begin() const { - return hierarchy.subconstraint_begin(); + return hierarchy.subconstraints_begin(); } template @@ -1296,9 +1306,48 @@ Constrained_triangulation_plus_2::Subconstraint_iterator Constrained_triangulation_plus_2:: subconstraints_end() const { - return hierarchy.subconstraint_end(); + return hierarchy.subconstraints_end(); +} + +template +inline +typename +Constrained_triangulation_plus_2::Subconstraints +Constrained_triangulation_plus_2:: +subconstraints() const +{ + return hierarchy.subconstraints(); } +template +inline +typename +Constrained_triangulation_plus_2::Subconstraint_and_contexts_iterator +Constrained_triangulation_plus_2:: +subconstraints_and_contexts_begin() const +{ + return hierarchy.subconstraints_and_contexts_begin(); +} + +template +inline +typename +Constrained_triangulation_plus_2::Subconstraint_and_contexts_iterator +Constrained_triangulation_plus_2:: +subconstraints_and_contexts_end() const +{ + return hierarchy.subconstraints_and_contexts_end(); +} + +template +inline +typename +Constrained_triangulation_plus_2::Subconstraints_and_contexts +Constrained_triangulation_plus_2:: +subconstraints_and_contexts() const +{ + return hierarchy.subconstraints_and_contexts(); +} template inline @@ -1325,7 +1374,7 @@ inline bool Constrained_triangulation_plus_2:: is_subconstraint(Vertex_handle va, Vertex_handle vb) { - return hierarchy.is_subconstrained_edge(va,vb); + return hierarchy.is_subconstraint(va,vb); } diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h index 5eab13d4c1ef..e85eb22fa19b 100644 --- a/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 GeometryFactory (France). All rights reserved. +// Copyright (c) 2020,2025 GeometryFactory (France). All rights reserved. // // This file is part of CGAL (www.cgal.org) // @@ -17,8 +17,6 @@ #include #include -#include - namespace CGAL { @@ -30,90 +28,71 @@ class CTP2_subconstraint_graph { CTP2& ctp2; public: - - typedef typename CTP2::Vertex_handle vertex_descriptor; - typedef typename CTP2::Subconstraint edge_descriptor; - typedef boost::undirected_tag directed_category; - typedef boost::disallow_parallel_edge_tag edge_parallel_category; - struct CTP2_graph_traversal_category : - public virtual boost::bidirectional_graph_tag, - public virtual boost::adjacency_graph_tag, - public virtual boost::edge_list_graph_tag, - public virtual boost::vertex_list_graph_tag - { }; - typedef CTP2_graph_traversal_category traversal_category; - typedef internal::Dereference_to_handle_enforcer< - CTP2, - typename CTP2::Finite_vertices_iterator, - vertex_descriptor> vertex_iterator; - - typedef typename CTP2::Subconstraint_iterator::value_type Subconstr_it_v_t; - typedef First_of_pair_property_map Subconstr_map; - typedef Property_map_to_unary_function Subconstr_uf; - typedef boost::transform_iterator edge_iterator; - - CTP2_subconstraint_graph (CTP2& ctp2) : ctp2(ctp2) { } - - friend Iterator_range vertices (const CTP2_subconstraint_graph& g) - { - return make_range (vertex_iterator(g.ctp2.finite_vertices_begin()), - vertex_iterator(g.ctp2.finite_vertices_end())); + using vertex_descriptor = typename CTP2::Vertex_handle; + using edge_descriptor = typename CTP2::Subconstraint; + using directed_category = boost::undirected_tag; + using edge_parallel_category = boost::disallow_parallel_edge_tag; + struct CTP2_graph_traversal_category : public virtual boost::bidirectional_graph_tag, + public virtual boost::adjacency_graph_tag, + public virtual boost::edge_list_graph_tag, + public virtual boost::vertex_list_graph_tag + {}; + using traversal_category = CTP2_graph_traversal_category; + using vertex_iterator = + internal::Dereference_to_handle_enforcer; + + using edge_iterator = typename CTP2::Subconstraint_iterator; + + CTP2_subconstraint_graph(CTP2& ctp2) + : ctp2(ctp2) {} + + friend Iterator_range vertices(const CTP2_subconstraint_graph& g) { + return make_range(vertex_iterator(g.ctp2.finite_vertices_begin()), vertex_iterator(g.ctp2.finite_vertices_end())); } - friend Iterator_range edges (const CTP2_subconstraint_graph& g) - { - return make_range (boost::make_transform_iterator(g.ctp2.subconstraints_begin(), Subconstr_uf(Subconstr_map())), - boost::make_transform_iterator(g.ctp2.subconstraints_end(), Subconstr_uf(Subconstr_map()))); + friend Iterator_range edges(const CTP2_subconstraint_graph& g) { + return g.ctp2.subconstraints(); } - friend vertex_descriptor source (edge_descriptor ed, const CTP2_subconstraint_graph&) - { - return ed.first; - } + friend vertex_descriptor source(edge_descriptor ed, const CTP2_subconstraint_graph&) { return ed.first; } - friend vertex_descriptor target (edge_descriptor ed, const CTP2_subconstraint_graph&) - { - return ed.second; - } + friend vertex_descriptor target(edge_descriptor ed, const CTP2_subconstraint_graph&) { return ed.second; } }; - template class CTP2_graph_visitor { private: + using Constraint_id = typename CTP2::Constraint_id; + using Vertex_handle = typename CTP2::Vertex_handle; CTP2& ctp2; - std::vector to_remove; - typename CTP2::Constraint_id current; - typename CTP2::Vertex_handle latest_vertex; + std::vector to_remove; + Constraint_id current{}; + Vertex_handle latest_vertex{}; public: + CTP2_graph_visitor(CTP2& ctp2) + : ctp2(ctp2) {} - CTP2_graph_visitor (CTP2& ctp2) : ctp2 (ctp2) { } - - void start_new_polyline() - { - latest_vertex = typename CTP2::Vertex_handle(); - current = typename CTP2::Constraint_id(); + void start_new_polyline() { + latest_vertex = Vertex_handle(); + current = Constraint_id(); } - void add_node (typename CTP2::Vertex_handle vh) - { - if (latest_vertex != typename CTP2::Vertex_handle()) - { - to_remove.push_back (ctp2.context(latest_vertex, vh).id()); - typename CTP2::Constraint_id cid = ctp2.insert_constraint(latest_vertex, vh); - if (current == typename CTP2::Constraint_id()) + void add_node(Vertex_handle vh) { + if(latest_vertex != Vertex_handle()) { + to_remove.push_back(ctp2.context(latest_vertex, vh).id()); + Constraint_id cid = ctp2.insert_constraint(latest_vertex, vh); + if(current == Constraint_id()) current = cid; else - current = ctp2.concatenate (current, cid); + current = ctp2.concatenate(current, cid); } latest_vertex = vh; } - void end_polyline() - { - for (typename CTP2::Constraint_id id : to_remove) + void end_polyline() { + for(Constraint_id id : to_remove) ctp2.remove_constraint(id); to_remove.clear(); } diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/Polyline_constraint_hierarchy_2.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/Polyline_constraint_hierarchy_2.h index 81d45f4d89e8..8a6f32ba81f1 100644 --- a/Triangulation_2/include/CGAL/Triangulation_2/internal/Polyline_constraint_hierarchy_2.h +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/Polyline_constraint_hierarchy_2.h @@ -45,8 +45,6 @@ class Polyline_constraint_hierarchy_2 { public: typedef T Vertex_handle; - typedef std::pair Edge; - typedef std::pair Constraint; typedef std::pair Subconstraint; using size_type = std::size_t; @@ -125,9 +123,10 @@ class Polyline_constraint_hierarchy_2 Vertex_list_ptr vl_ptr() const { return vl; } - operator std::pair() const{ - Edge edge = vl == nullptr ? Edge() : Edge(vl->front().vertex(), vl->back().vertex()); - return std::make_pair(edge, vl); + operator std::pair() const { + Subconstraint subconstraint = + vl == nullptr ? Subconstraint() : Subconstraint(vl->front().vertex(), vl->back().vertex()); + return { subconstraint, vl }; } Constraint_id& operator=(std::nullptr_t) { @@ -173,11 +172,11 @@ class Polyline_constraint_hierarchy_2 public: Pair_compare(const Compare& comp) : comp(comp) {} - bool operator()(const Edge& e1, const Edge& e2) const { - if(comp(e1.first, e2.first)) { + bool operator()(const Subconstraint& sc1, const Subconstraint& sc2) const { + if(comp(sc1.first, sc2.first)) { return true; - } else if((! comp(e2.first, e1.first)) && // !less(e1,e2) && !less(e2,e1) == equal - comp(e1.second, e2.second)) { + } else if((! comp(sc2.first, sc1.first)) && // !less(sc1,sc2) && !less(sc2,sc1) == equal + comp(sc1.second, sc2.second)) { return true; } else { return false; @@ -203,57 +202,61 @@ class Polyline_constraint_hierarchy_2 typedef std::list Context_list; typedef typename Context_list::iterator Context_iterator; - typedef std::set Constraint_set; + typedef std::set Constraints_set; #if CGAL_USE_BARE_STD_MAP - typedef std::map Sc_to_c_map; #else - typedef CGAL::unordered_flat_map> Sc_to_c_map; + typedef CGAL::unordered_flat_map> Sc_to_c_map; #endif - typedef typename Constraint_set::iterator C_iterator; + typedef typename Constraints_set::iterator Constraint_iterator; + typedef const Constraints_set& Constraints; typedef typename Sc_to_c_map::const_iterator Sc_iterator; - typedef Sc_iterator Subconstraint_iterator; + typedef Sc_iterator Subconstraint_and_contexts_iterator; + typedef const Sc_to_c_map& Subconstraints_and_contexts; - class Edge_iterator : public boost::stl_interfaces::proxy_iterator_interface< + class Subconstraint_iterator : public boost::stl_interfaces::proxy_iterator_interface< #if !BOOST_STL_INTERFACES_USE_DEDUCED_THIS - Edge_iterator, + Subconstraint_iterator, #endif std::bidirectional_iterator_tag, - Edge> + Subconstraint> { using base_type = boost::stl_interfaces::proxy_iterator_interface< #if !BOOST_STL_INTERFACES_USE_DEDUCED_THIS - Edge_iterator, + Subconstraint_iterator, #endif std::bidirectional_iterator_tag, - Edge>; + Subconstraint>; - const Constraint_set* constraint_set = nullptr; - C_iterator constraint_it{}; + const Constraints_set* constraints_set = nullptr; + Constraint_iterator constraint_it{}; Vertex_it vertex_it{}; public: - // - The object is singular if and only if `constraint_set==nullptr`. + // - The object is singular if and only if `constraints_set==nullptr`. // - // - The end value is when `constraint_it` is the end iterator of `constraint_set`. + // - The end value is when `constraint_it` is the end iterator of `constraints_set`. // In that case `vertex_it` must be singular. // // - Otherwise all members must be valid pointers or dereferencable iterators. - bool equal(const Edge_iterator& other) const { - return constraint_set == other.constraint_set && - (constraint_set == nullptr || (constraint_it == other.constraint_it && vertex_it == other.vertex_it)); + bool equal(const Subconstraint_iterator& other) const { + return constraints_set == other.constraints_set && + (constraints_set == nullptr || (constraint_it == other.constraint_it && + vertex_it == other.vertex_it)); } - Vertex_it first_vertex_it(C_iterator constraint_it) const { - if(constraint_it == constraint_set->end()) { + Vertex_it begin_or_null(Constraint_iterator constraint_it) const { + if(constraint_it == constraints_set->end()) { return Vertex_it(); } return constraint_it->begin(); } public: - Edge_iterator() = default; + Subconstraint_iterator() = default; // Constructors for begin and end. The constructors are public, but only the // hierarchy can create an iterator of this class, through its friendship of @@ -262,7 +265,7 @@ class Polyline_constraint_hierarchy_2 class Construction_access { private: - friend class Edge_iterator; + friend class Subconstraint_iterator; friend class Polyline_constraint_hierarchy_2; static auto begin_tag() { return Begin_tag(); } @@ -275,45 +278,49 @@ class Polyline_constraint_hierarchy_2 }; // // constructor for the begin iterator - explicit Edge_iterator(Construction_access::Begin_tag, const Constraint_set* constraint_set) - : constraint_set(constraint_set) - , constraint_it(constraint_set->begin()) - , vertex_it(first_vertex_it(constraint_set->begin())) {} + explicit Subconstraint_iterator(typename Construction_access::Begin_tag, + const Constraints_set* constraints_set) + : constraints_set(constraints_set) + , constraint_it(constraints_set->begin()) + , vertex_it(begin_or_null(constraints_set->begin())) {} // // constructor for the end iterator - explicit Edge_iterator(Construction_access::End_tag, const Constraint_set* constraint_set) - : constraint_set(constraint_set) - , constraint_it(constraint_set->end()) + explicit Subconstraint_iterator(typename Construction_access::End_tag, + const Constraints_set* constraints_set) + : constraints_set(constraints_set) + , constraint_it(constraints_set->end()) , vertex_it() {} - Edge operator*() const { - CGAL_precondition(constraint_set != nullptr && constraint_it != constraint_set->end()); + Subconstraint operator*() const { + CGAL_precondition(constraints_set != nullptr && constraint_it != constraints_set->end()); CGAL_assertion(vertex_it != constraint_it->end()); CGAL_assertion(std::next(vertex_it) != constraint_it->end()); - return Edge(*vertex_it, *std::next(vertex_it)); + return Subconstraint(*vertex_it, *std::next(vertex_it)); } - friend bool operator==(const Edge_iterator& lhs, const Edge_iterator& rhs) { return lhs.equal(rhs); } + friend bool operator==(const Subconstraint_iterator& lhs, const Subconstraint_iterator& rhs) { + return lhs.equal(rhs); + } using base_type::operator++; - Edge_iterator& operator++() { - CGAL_precondition(constraint_set != nullptr && constraint_it != constraint_set->end()); + Subconstraint_iterator& operator++() { + CGAL_precondition(constraints_set != nullptr && constraint_it != constraints_set->end()); ++vertex_it; CGAL_assertion(vertex_it != constraint_it->end()); if(std::next(vertex_it) == constraint_it->end()) { ++constraint_it; - vertex_it = first_vertex_it(constraint_it); + vertex_it = begin_or_null(constraint_it); } return *this; } using base_type::operator--; - Edge_iterator& operator--() { - CGAL_precondition(constraint_set != nullptr); - CGAL_precondition(constraint_it != constraint_set->begin() || vertex_it != constraint_it->begin()); - if(constraint_it == constraint_set->end() || vertex_it == constraint_it->begin()) { + Subconstraint_iterator& operator--() { + CGAL_precondition(constraints_set != nullptr); + CGAL_precondition(constraint_it != constraints_set->begin() || vertex_it != constraint_it->begin()); + if(constraint_it == constraints_set->end() || vertex_it == constraint_it->begin()) { --constraint_it; vertex_it = std::prev(constraint_it->end(), 2); } else { @@ -321,12 +328,12 @@ class Polyline_constraint_hierarchy_2 } return *this; } - }; // end class Edge_iterator + }; // end class Subconstraint_iterator + typedef Iterator_range Subconstraints; private: - // data for the 1d hierarchy Compare comp; - Constraint_set constraint_set; + Constraints_set constraints_set; Sc_to_c_map sc_to_c_map; public: @@ -346,7 +353,7 @@ class Polyline_constraint_hierarchy_2 Polyline_constraint_hierarchy_2& operator=(Polyline_constraint_hierarchy_2&& ch) = default; // Query - bool is_subconstrained_edge(T va, T vb) const; + bool is_subconstraint(T va, T vb) const; Vertex_it vertices_in_constraint_begin(Constraint_id cid) const { return cid.begin(); } @@ -361,7 +368,6 @@ class Polyline_constraint_hierarchy_2 Point_it points_in_constraint_end(Constraint_id cid) const { return cid.vl_ptr()->all_end(); } - bool enclosing_constraint(Edge he, Constraint& hc) const; bool enclosing_constraint(T vaa, T vbb, T& va, T& vb) const; bool next_along_sc(T va, T vb, T& w) const; void oriented_end(T va, T vb, T& vc) const; @@ -371,7 +377,7 @@ class Polyline_constraint_hierarchy_2 Context_iterator contexts_begin(T va, T vb) const; Context_iterator contexts_end(T va, T vb) const; Iterator_range contexts_range(T va, T vb) const; - size_type number_of_constraints() const { return constraint_set.size();} + size_type number_of_constraints() const { return constraints_set.size();} size_type number_of_subconstraints()const {return sc_to_c_map.size();} @@ -399,39 +405,41 @@ class Polyline_constraint_hierarchy_2 // iterators - Subconstraint_iterator subconstraint_begin() const + Subconstraint_and_contexts_iterator subconstraints_and_contexts_begin() const { return sc_to_c_map.begin(); } - Subconstraint_iterator subconstraint_end() const + Subconstraint_and_contexts_iterator subconstraints_and_contexts_end() const { return sc_to_c_map.end(); } - Edge_iterator edges_begin() const { - BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(Edge_iterator, std::bidirectional_iterator); - BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(Edge_iterator, std::bidirectional_iterator_tag, - std::bidirectional_iterator, Edge, Edge, - typename Edge_iterator::pointer, std::ptrdiff_t); - return Edge_iterator(Edge_iterator::Construction_access::begin_tag(), &constraint_set); + Subconstraint_iterator subconstraints_begin() const { + BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(Subconstraint_iterator, std::bidirectional_iterator); + BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + Subconstraint_iterator, std::bidirectional_iterator_tag, std::bidirectional_iterator, + Subconstraint, Subconstraint, typename Subconstraint_iterator::pointer, std::ptrdiff_t); + return Subconstraint_iterator(Subconstraint_iterator::Construction_access::begin_tag(), + &constraints_set); } - Edge_iterator edges_end() const { - return Edge_iterator(Edge_iterator::Construction_access::end_tag(), &constraint_set); + Subconstraint_iterator subconstraints_end() const { + return Subconstraint_iterator(Subconstraint_iterator::Construction_access::end_tag(), + &constraints_set); } - auto edges() const { return Iterator_range(edges_begin(), edges_end()); } - Sc_iterator sc_begin() const{ return sc_to_c_map.begin(); } Sc_iterator sc_end() const{ return sc_to_c_map.end(); } - C_iterator c_begin() const{ return constraint_set.begin(); } - C_iterator c_end() const{ return constraint_set.end(); } + Constraint_iterator constraints_begin() const{ return constraints_set.begin(); } + Constraint_iterator constraints_end() const{ return constraints_set.end(); } // Ranges - auto constraints() const { return Iterator_range(c_begin(), c_end()); } - const auto & subconstraints() const { return sc_to_c_map; } - + const auto& constraints() const { return constraints_set; } + const auto& subconstraints_and_contexts() const { return sc_to_c_map; } + auto subconstraints() const { + return Iterator_range(subconstraints_begin(), subconstraints_end()); + } // Helper functions void copy(const Polyline_constraint_hierarchy_2& ch); @@ -440,11 +448,13 @@ class Polyline_constraint_hierarchy_2 private: Constraint_id new_constraint_id() const { - auto id = number_of_constraints() == 0 ? 0 : constraint_set.rbegin()->id + 1; + auto id = number_of_constraints() == 0 ? 0 : constraints_set.rbegin()->id + 1; return Constraint_id(new Vertex_list, id); } - Edge make_edge(T va, T vb) const; - Edge make_edge(Edge e) { const auto& [va, vb] = e; return make_edge(va, vb); } + Subconstraint sorted_pair(T va, T vb) const; + Subconstraint sorted_pair(Subconstraint sc) { + const auto& [va, vb] = sc; return sorted_pair(va, vb); + } Vertex_it get_pos(T va, T vb) const; bool get_contexts(T va, T vb, Context_iterator& ctxt, @@ -498,22 +508,22 @@ copy(const Polyline_constraint_hierarchy_2& other, std::map cstr_map; clear(); - // copy constraint_set + // copy constraints_set for(const auto& cid1: other.constraints()) { Constraint_id cid2 = new_constraint_id(); cstr_map[cid1] = cid2; for(const auto& node : cid1.elements()) { cid2.vl_ptr()->push_back(Node(vmap[node.vertex()], node.input())); } - constraint_set.insert(cid2); + constraints_set.insert(cid2); } // copy sc_to_c_map - for(const auto& [edge1, hcl1] : other.subconstraints()) { + for(const auto& [sc1, hcl1] : other.subconstraints_and_contexts()) { Context_list* hcl2 = new Context_list; - Vertex_handle uu2 = vmap[edge1.first]; - Vertex_handle vv2 = vmap[edge1.second]; - Edge edge2 = make_edge(uu2, vv2); - sc_to_c_map[edge2] = hcl2; + Vertex_handle uu2 = vmap[sc1.first]; + Vertex_handle vv2 = vmap[sc1.second]; + Subconstraint sc2 = sorted_pair(uu2, vv2); + sc_to_c_map[sc2] = hcl2; for(const Context& ctxt1 : *hcl1) { // vertices of the enclosing constraints Context ctxt2; @@ -540,37 +550,16 @@ swap(Polyline_constraint_hierarchy_2& ch) { using std::swap; swap(comp, ch.comp); - constraint_set.swap(ch.constraint_set); + constraints_set.swap(ch.constraints_set); sc_to_c_map.swap(ch.sc_to_c_map); } -/* template bool Polyline_constraint_hierarchy_2:: -is_constrained_edge(T va, T vb) const +is_subconstraint(T va, T vb) const { - return( c_to_sc_map.find(make_edge(va, vb)) != c_to_sc_map.end() ); -} -*/ - -template -bool Polyline_constraint_hierarchy_2:: -is_subconstrained_edge(T va, T vb) const -{ - return( sc_to_c_map.find(make_edge(va, vb)) != sc_to_c_map.end() ); -} - - -// af: obsolete -template -bool Polyline_constraint_hierarchy_2:: -enclosing_constraint(Edge he, Constraint& hc) const -{ - Context_iterator hcit, past; - if ( !get_contexts(he.first,he.second, hcit ,past)) return false; - hc = make_edge(hcit->enclosing.front(), hcit->enclosing.back()); - return true; + return( sc_to_c_map.find(sorted_pair(va, vb)) != sc_to_c_map.end() ); } @@ -659,7 +648,7 @@ swap(Constraint_id constr_a, Constraint_id constr_b) { auto substitute_enclosing_in_vertex_list = [this](Vertex_list_ptr vl, Constraint_id old_id, Constraint_id new_id) { // We have to look at all subconstraints for(Vertex_it it = vl->skip_begin(), succ = it, end = vl->skip_end(); ++succ != end; ++it) { - typename Sc_to_c_map::iterator scit = this->sc_to_c_map.find(make_edge(*it, *succ)); + typename Sc_to_c_map::iterator scit = this->sc_to_c_map.find(sorted_pair(*it, *succ)); CGAL_assertion(scit != this->sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -687,13 +676,13 @@ template void Polyline_constraint_hierarchy_2:: remove_constraint(Constraint_id cid){ - constraint_set.erase(cid); + constraints_set.erase(cid); // We have to look at all subconstraints for(Vertex_it it = cid.begin(), succ = it, end = cid.end(); ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -722,14 +711,13 @@ remove_constraint(Constraint_id cid){ // and for the case that the constrained edge u,w has no intersections template void Polyline_constraint_hierarchy_2::simplify(Vertex_it uc, - Vertex_it vc, - Vertex_it wc) - + Vertex_it vc, + Vertex_it wc) { // TODO: How do we (want to) deal with u == w ??? Vertex_handle u = *uc, v = *vc, w = *wc; - typename Sc_to_c_map::iterator uv_sc_iter = sc_to_c_map.find(make_edge(u, v)); - typename Sc_to_c_map::iterator vw_sc_iter = sc_to_c_map.find(make_edge(v, w)); + typename Sc_to_c_map::iterator uv_sc_iter = sc_to_c_map.find(sorted_pair(u, v)); + typename Sc_to_c_map::iterator vw_sc_iter = sc_to_c_map.find(sorted_pair(v, w)); Context_list* uv_hcl = uv_sc_iter->second; Context_list* vw_hcl = vw_sc_iter->second; // AF: what is input() about??? @@ -777,7 +765,7 @@ void Polyline_constraint_hierarchy_2::simplify(Vertex_it uc, sc_to_c_map.erase(vw_sc_iter); // reuse other context list - sc_to_c_map[make_edge(u,w)] = uv_hcl; + sc_to_c_map[sorted_pair(u,w)] = uv_hcl; } @@ -803,8 +791,8 @@ typename Polyline_constraint_hierarchy_2::size_type Polyline_constraint_hierarchy_2::remove_points_without_corresponding_vertex() { size_type n = 0; - for(C_iterator it = constraint_set.begin(); it!= constraint_set.end(); ++it){ - n+= remove_points_without_corresponding_vertex(*it); + for(const auto& cid : constraints_set){ + n+= remove_points_without_corresponding_vertex(cid); } return n; } @@ -817,13 +805,13 @@ Polyline_constraint_hierarchy_2::concatenate(Constraint_id cons // std::cerr << std::format("concatenate({}, {}) ", constr_a.id, constr_b.id) << std::endl; Vertex_list_ptr constr_a_vl = constr_a.vl_ptr(); Vertex_list_ptr constr_b_vl = constr_b.vl_ptr(); - constraint_set.erase(constr_a); - constraint_set.erase(constr_b); + constraints_set.erase(constr_a); + constraints_set.erase(constr_b); // We have to look at all subconstraints for(Vertex_it it = constr_b_vl->skip_begin(), succ = it, end = constr_b_vl->skip_end(); ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -848,7 +836,7 @@ Polyline_constraint_hierarchy_2::concatenate(Constraint_id cons for(Vertex_it it = back_it, succ = it, end = constr_a_vl->skip_end(); ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -860,7 +848,7 @@ Polyline_constraint_hierarchy_2::concatenate(Constraint_id cons } } } - constraint_set.insert(constr_a); + constraints_set.insert(constr_a); delete constr_b_vl; return constr_a; @@ -872,13 +860,13 @@ Polyline_constraint_hierarchy_2::concatenate2(Constraint_id con { Vertex_list_ptr constr_a_vl = constr_a.vl_ptr(); Vertex_list_ptr constr_b_vl = constr_b.vl_ptr(); - constraint_set.erase(constr_a); - constraint_set.erase(constr_b); + constraints_set.erase(constr_a); + constraints_set.erase(constr_b); // We have to look at all subconstraints for(Vertex_it it = constr_a_vl->skip_begin(), succ = it, end = constr_a_vl->skip_end(); ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -902,7 +890,7 @@ Polyline_constraint_hierarchy_2::concatenate2(Constraint_id con for(Vertex_it it = constr_b_vl->skip_begin(), succ = it, end = back_it; ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -914,7 +902,7 @@ Polyline_constraint_hierarchy_2::concatenate2(Constraint_id con } } } - constraint_set.insert(constr_b); + constraints_set.insert(constr_b); delete constr_a_vl; return constr_b; @@ -929,7 +917,7 @@ typename Polyline_constraint_hierarchy_2::Constraint_id Polyline_constraint_hierarchy_2::split(Constraint_id constr, Vertex_it vcit) { Constraint_id new_constr = new_constraint_id(); - constraint_set.erase(constr); + constraints_set.erase(constr); Vertex_list_ptr new_vl = new_constr.vl_ptr(); Vertex_list_ptr constr_vl = constr.vl_ptr(); new_vl->splice(new_vl->skip_end(), *(constr_vl), vcit.base(), constr_vl->skip_end()); @@ -939,13 +927,13 @@ Polyline_constraint_hierarchy_2::split(Constraint_id constr, Ve vit = constr_vl->skip_end(); --vit; vit.input() = true; - constraint_set.insert(constr); - constraint_set.insert(new_constr); + constraints_set.insert(constr); + constraints_set.insert(new_constr); // We have to look at all subconstraints for(Vertex_it it = new_vl->skip_begin(), succ = it, end = new_vl->skip_end(); ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -965,7 +953,7 @@ typename Polyline_constraint_hierarchy_2::Constraint_id Polyline_constraint_hierarchy_2::split2(Constraint_id constr, Vertex_it vcit) { Constraint_id new_constr = new_constraint_id(); - constraint_set.erase(constr); + constraints_set.erase(constr); Vertex_list_ptr new_vl = new_constr.vl_ptr(); Vertex_list_ptr constr_vl = constr.vl_ptr(); new_vl->splice(new_vl->skip_end(), *constr_vl, constr_vl->skip_begin(), vcit.base()); @@ -975,13 +963,13 @@ Polyline_constraint_hierarchy_2::split2(Constraint_id constr, V vit.input() = true; vit = constr_vl->skip_begin(); vit.input() = true; - constraint_set.insert(constr); - constraint_set.insert(new_constr); + constraints_set.insert(constr); + constraints_set.insert(new_constr); // We have to look at all subconstraints for(Vertex_it it = new_vl->skip_begin(), succ = it, end = new_vl->skip_end(); ++succ != end; ++it){ - typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); + typename Sc_to_c_map::iterator scit = sc_to_c_map.find(sorted_pair(*it,*succ)); CGAL_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; @@ -1011,17 +999,17 @@ insert_constraint(T va, T vb){ << "C_hierachy.insert_constraint( " << IO::oformat(va) << ", " << IO::oformat(vb) << ")\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS - Edge he = make_edge(va, vb); + Subconstraint sc = sorted_pair(va, vb); Constraint_id cid = new_constraint_id(); auto children = cid.vl_ptr(); - auto& fathers = sc_to_c_map[he]; + auto& fathers = sc_to_c_map[sc]; if(fathers == nullptr){ fathers = new Context_list; } - children->push_front(Node(va, true)); // was he.first - children->push_back(Node(vb, true)); // was he.second - constraint_set.insert(cid); + children->push_front(Node(va, true)); // was sc.first + children->push_back(Node(vb, true)); // was sc.second + constraints_set.insert(cid); Context ctxt; ctxt.enclosing = cid; ctxt.pos = children->skip_begin(); @@ -1049,8 +1037,8 @@ append_constraint(Constraint_id cid, T va, T vb){ << "C_hierachy.append_constraint( ..., " << IO::oformat(va) << ", " << IO::oformat(vb) << ")\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS - Edge he = make_edge(va, vb); - auto& fathers = sc_to_c_map[he]; + Subconstraint sc = sorted_pair(va, vb); + auto& fathers = sc_to_c_map[sc]; if(fathers == nullptr){ fathers = new Context_list; } @@ -1080,7 +1068,7 @@ clear() delete cl_ptr; } sc_to_c_map.clear(); - constraint_set.clear(); + constraints_set.clear(); } @@ -1176,28 +1164,28 @@ add_Steiner(T va, T vb, T vc){ hcl3->splice(hcl3->end(), *hcl); delete hcl; } - else sc_to_c_map.emplace(make_edge(va,vc), hcl); + else sc_to_c_map.emplace(sorted_pair(va,vc), hcl); if (get_contexts(vc,vb,hcl3)) {// (vc,vb) is already a subconstraint hcl3->splice(hcl3->end(),*hcl2); delete hcl2; } - else sc_to_c_map.emplace(make_edge(vc,vb), hcl2); + else sc_to_c_map.emplace(sorted_pair(vc,vb), hcl2); - sc_to_c_map.erase(make_edge(va,vb)); + sc_to_c_map.erase(sorted_pair(va,vb)); return; } template inline -typename Polyline_constraint_hierarchy_2::Edge +typename Polyline_constraint_hierarchy_2::Subconstraint Polyline_constraint_hierarchy_2:: -make_edge(T va, T vb) const +sorted_pair(T va, T vb) const { - return comp(va, vb) ? Edge(va,vb) : Edge(vb,va); + return comp(va, vb) ? Subconstraint(va,vb) : Subconstraint(vb,va); } template @@ -1206,7 +1194,7 @@ bool Polyline_constraint_hierarchy_2:: get_contexts(T va, T vb, Context_list* & hcl) const { - Sc_iterator sc_iter = sc_to_c_map.find(make_edge(va,vb)); + Sc_iterator sc_iter = sc_to_c_map.find(sorted_pair(va,vb)); if( sc_iter == sc_to_c_map.end() ) return(false); hcl = sc_iter->second; return true; @@ -1236,7 +1224,7 @@ Polyline_constraint_hierarchy_2:: get_pos(T va, T vb) const //return pos in the first context { - return (*sc_to_c_map.find(make_edge(va,vb))).second->begin().pos; + return (*sc_to_c_map.find(sorted_pair(va,vb))).second->begin().pos; } template @@ -1299,11 +1287,11 @@ print() const } } std::cout << std::endl; - for(const auto& [edge, _] : subconstraints()) { + for(const auto& subconstraint : subconstraints()) { std::cout << "subconstraint "; - std::cout << vertex_num[edge.first] << " " << vertex_num[edge.second]; + std::cout << vertex_num[subconstraint.first] << " " << vertex_num[subconstraint.second]; Context_iterator cb, ce; - get_contexts(edge.first, edge.second, cb, ce); + get_contexts(subconstraint.first, subconstraint.second, cb, ce); std::cout << " enclosing "; for(; cb != ce; cb++) {