// Copyright (c) 2012 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0+ // // // Author(s) : Andreas Fabri, Olivier Billet, Mariette Yvinec #ifndef CGAL_POLYLINE_CONSTRAINT_HIERARCHY_2_H #define CGAL_POLYLINE_CONSTRAINT_HIERARCHY_2_H #include #include #include #include #include #include #include #include namespace CGAL { // T is expected to be Vertex_handle // Compare is a comparison operator for type T // Data is intended to store info on a Vertex template class Polyline_constraint_hierarchy_2 { public: typedef Data Point; typedef T Vertex_handle; typedef std::pair Edge; typedef std::pair Constraint; typedef std::pair Subconstraint; private: class Node { public: explicit Node(Vertex_handle vh, bool input = false) : vertex_(vh), point_(vh->point()), id(-1), input(input) {} Point& point() { return point_; } const Point& point() const { return point_; } Vertex_handle vertex() const { return vertex_; } private: Vertex_handle vertex_; Point point_; public: int id; bool input; }; typedef CGAL::Skiplist Vertex_list; typedef std::list Constraint_list; public: // the base line is always class Point_it : public boost::iterator_adaptor< Point_it , typename Vertex_list::all_iterator , Point > { public: Point_it() : Vertex_it::iterator_adaptor_() {} Point_it(typename Vertex_list::all_iterator it) : Point_it::iterator_adaptor_(it) {} private: friend class boost::iterator_core_access; Point& dereference() const { return this->base()->point(); } }; // only nodes with a vertex_handle that is still in the triangulation class Vertex_it : public boost::iterator_adaptor< Vertex_it , typename Vertex_list::skip_iterator , Vertex_handle , boost::use_default , Vertex_handle> { public: Vertex_it() : Vertex_it::iterator_adaptor_() {} Vertex_it(typename Vertex_list::skip_iterator it) : Vertex_it::iterator_adaptor_(it) {} operator Point_it() const { return Point_it(this->base()); } bool& input() { return this->base()->input; } private: friend class boost::iterator_core_access; Vertex_handle dereference() const { return this->base()->vertex(); } }; typedef typename Constraint_list::iterator Constraint_it; struct Constraint_id { Vertex_list* second; Constraint_id(): second(NULL) {} Constraint_id(Vertex_list* vl) : second(vl) {} Vertex_list* vl_ptr() const {return second;} operator std::pair,Vertex_list*>() { if (second!=NULL){ return std::make_pair(std::make_pair(second->front().vertex(), second->back().vertex()),second); } return std::make_pair(std::make_pair(Vertex_handle(),Vertex_handle()),second); } bool operator == (const Constraint_id& other) const { return second == other.second; } bool operator != (const Constraint_id& other) const { return second != other.second; } bool operator<(const Constraint_id& other) const{ return second < other.second; } }; class Pair_compare { Compare comp; public: Pair_compare(const Compare& comp) : comp(comp) {} bool operator()(const Edge& e1, const Edge& e2) const { if(comp(e1.first, e2.first)) { return true; } else if((! comp(e2.first, e1.first)) && // !less(e1,e2) && !less(e2,e1) == equal comp(e1.second, e2.second)) { return true; } else { return false; } } }; class Context { friend class Polyline_constraint_hierarchy_2; private: Vertex_list* enclosing; Vertex_it pos; public: Context() : enclosing(NULL) {} Context(const Context& hc) : enclosing(hc.enclosing), pos(hc.pos) {} Vertex_it vertices_begin() { return enclosing->skip_begin();} Vertex_it current() {return pos;} Vertex_it vertices_end() {return enclosing->skip_end();} Constraint_id id() { return enclosing; } std::size_t number_of_vertices() const {return enclosing->skip_size(); } }; typedef std::list Context_list; typedef typename Context_list::iterator Context_iterator; typedef std::set Constraint_set; typedef std::map Sc_to_c_map; typedef typename Constraint_set::iterator C_iterator; typedef typename Sc_to_c_map::const_iterator Sc_iterator; typedef Sc_iterator Subconstraint_iterator; private: // data for the 1d hierarchy Compare comp; Constraint_set constraint_set; Sc_to_c_map sc_to_c_map; typedef std::map, Constraint_id, Pair_compare> Constraint_map; Constraint_map constraint_map; public: Polyline_constraint_hierarchy_2(const Compare& comp) : comp(comp) , sc_to_c_map(Pair_compare(comp)) , constraint_map(Pair_compare(comp)) { } Polyline_constraint_hierarchy_2(const Polyline_constraint_hierarchy_2& ch); ~Polyline_constraint_hierarchy_2(){ clear();} void clear(); Polyline_constraint_hierarchy_2& operator=(const Polyline_constraint_hierarchy_2& ch); // Query bool is_subconstrained_edge(T va, T vb) const; bool is_constrained_edge(T va, T vb) const; bool is_constrained_vertex(T v) const; Vertex_it vertices_in_constraint_begin(Constraint_id cid) const { return cid.vl_ptr()->skip_begin(); } Vertex_it vertices_in_constraint_end(Constraint_id cid) const { return cid.vl_ptr()->skip_end(); } Vertex_it vertices_in_constraint_begin(Vertex_handle va, Vertex_handle vb) const { Constraint_id cid = constraint_map.find(make_edge(va,vb))->second; return cid.vl_ptr()->skip_begin(); } Vertex_it vertices_in_constraint_end(Vertex_handle va, Vertex_handle vb) const { Constraint_id cid = constraint_map.find(make_edge(va,vb))->second; return cid.vl_ptr()->skip_end(); } Point_it points_in_constraint_begin(Constraint_id cid) const { return cid.vl_ptr()->all_begin(); } 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 enclosing_constraints(T vaa, T vbb, Constraint_list& hcl) const; bool next_along_sc(T va, T vb, T& w) const; void oriented_end(T va, T vb, T& vc) const; Context context(T va, T vb); std::size_t number_of_enclosing_constraints(T va, T vb) const; Context_iterator contexts_begin(T va, T vb) const; Context_iterator contexts_end(T va, T vb) const; std::size_t number_of_constraints() const { return constraint_set.size();} std::size_t number_of_subconstraints()const {return sc_to_c_map.size();} // insert/remove void add_Steiner(T va, T vb, T vx); Vertex_list* insert_constraint(T va, T vb); void append_constraint(Constraint_id cid, T va, T vb); void swap(Constraint_id first, Constraint_id second); void remove_constraint(Constraint_id cid); void remove_constraint(Vertex_handle va, Vertex_handle vb) { remove_constraint(constraint_map[make_edge(va,vb)]); } void split_constraint(T va, T vb, T vc); void simplify(Vertex_it u, Vertex_it v, Vertex_it w); std::size_t remove_points_without_corresponding_vertex(Constraint_id); std::size_t remove_points_without_corresponding_vertex(); Constraint_id concatenate(Constraint_id first, Constraint_id second); Constraint_id concatenate2(Constraint_id first, Constraint_id second); Constraint_id split(Constraint_id first, Vertex_it vcit); Constraint_id split2(Constraint_id first, Vertex_it vcit); void remove_Steiner(T v, T va, T vb); // iterators Subconstraint_iterator subconstraint_begin() const { return sc_to_c_map.begin(); } Subconstraint_iterator subconstraint_end() const { return sc_to_c_map.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(); } // Helper functions void copy(const Polyline_constraint_hierarchy_2& ch); void copy(const Polyline_constraint_hierarchy_2& ch, std::map& vmap); void swap(Polyline_constraint_hierarchy_2& ch); private: Edge make_edge(T va, T vb) const; Vertex_it get_pos(T va, T vb) const; bool get_contexts(T va, T vb, Context_iterator& ctxt, Context_iterator& past) const; bool get_contexts(T va, T vb, Context_list*&) const; //to_debug public: void print() const; }; template Polyline_constraint_hierarchy_2:: Polyline_constraint_hierarchy_2(const Polyline_constraint_hierarchy_2& ch) : comp(ch.comp) , sc_to_c_map(Pair_compare(comp)) , constraint_map(Pair_compare(comp)) { copy(ch); } template Polyline_constraint_hierarchy_2& Polyline_constraint_hierarchy_2:: operator=(const Polyline_constraint_hierarchy_2& ch){ copy(ch); return *this; } template void Polyline_constraint_hierarchy_2:: copy(const Polyline_constraint_hierarchy_2& ch1) { // create a identity transfer vertex map std::map vmap; C_iterator cit1 = ch1.c_begin(); for( ; cit1 != ch1.c_end(); ++cit1) { Vertex_it vit = cit1->second->begin(); for( ; vit != cit1->second->end(); ++vit) { vmap[*vit] = *vit; } } copy(ch1, vmap); } template void Polyline_constraint_hierarchy_2:: copy(const Polyline_constraint_hierarchy_2& ch1, std::map& vmap) // copy with a transfer vertex map { std::map vlmap; clear(); // copy constraint_set C_iterator cit1 = ch1.c_begin(); for( ; cit1 != ch1.c_end(); ++cit1) { Vertex_list* hvl1 = cit1->vl_ptr(); Vertex_list* hvl2 = new Vertex_list; vlmap[hvl1] = hvl2; Vertex_it vit = hvl1->skip_begin(), end = hvl1->skip_end(); for( ; vit != end; ++vit) hvl2->push_back(Node(vmap[*vit])); constraint_set.insert(hvl2); } // copy sc_to_c_map Sc_iterator scit1 = ch1.sc_begin(); for( ; scit1 != ch1.sc_end(); ++scit1) { //vertices of the subconstraints Vertex_handle uu2 = vmap[scit1->first.first]; Vertex_handle vv2 = vmap[scit1->first.second]; Context_list* hcl1 = scit1->second; Context_list* hcl2 = new Context_list; Context_iterator cit1 = hcl1->begin(); for( ; cit1 != hcl1->end(); ++cit1){ // vertices of the enclosing constraints Context ctxt2; ctxt2.enclosing = vlmap[cit1->enclosing]; ctxt2.pos = ctxt2.enclosing->skip_begin(); Vertex_it aux = cit1->enclosing->skip_begin(); while( aux != cit1->pos) { ++aux; ++ctxt2.pos; } hcl2->push_back(ctxt2); } sc_to_c_map[make_edge(uu2,vv2)] = hcl2; } comp = ch1.comp; return; } template void Polyline_constraint_hierarchy_2:: swap(Polyline_constraint_hierarchy_2& ch) { constraint_set.swap(ch.constraint_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 { 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; } // used by Constrained_triangulation_plus_2::intersect with Exact_intersection_tag template bool Polyline_constraint_hierarchy_2:: enclosing_constraint(T vaa, T vbb, T& va, T& vb) const { Context_iterator hcit, past; if ( !get_contexts(vaa,vbb, hcit ,past)) return false; // va = hcit->enclosing->front().vertex(); // vb = hcit->enclosing->back().vertex(); // Vertex_list* vl = hcit->enclosing; Vertex_it pos = hcit->pos; if(vaa != *pos){ std::swap(vaa,vbb); } while(!pos.input()){ --pos; } va = *pos; pos = hcit->pos; ++pos; CGAL_triangulation_assertion(vbb == *pos); while(!pos.input()){ ++pos; } vb = *pos; return true; } // af: obsolete template bool Polyline_constraint_hierarchy_2:: enclosing_constraints(T vaa, T vbb , Constraint_list& hcl) const { Context_iterator hcit, past; if ( !get_contexts(vaa,vbb, hcit ,past)) return false; for (; hcit!=past; hcit++) { hcl.push_back(make_edge(hcit->enclosing->front(), hcit->enclosing->back())); } return true; } template typename Polyline_constraint_hierarchy_2::Context Polyline_constraint_hierarchy_2:: context(T va, T vb) { Context_iterator hcit, past; if(!get_contexts(va,vb, hcit ,past)) CGAL_triangulation_assertion(false); return *hcit; } template std::size_t Polyline_constraint_hierarchy_2:: number_of_enclosing_constraints(T va, T vb) const { Context_list* hcl = NULL; CGAL_triangulation_assertion_code( bool found = ) get_contexts(va,vb,hcl); CGAL_triangulation_assertion(found); return hcl->size(); } template typename Polyline_constraint_hierarchy_2::Context_iterator Polyline_constraint_hierarchy_2:: contexts_begin(T va, T vb) const { Context_iterator first, last; if( !get_contexts(va,vb,first,last)) CGAL_triangulation_assertion(false); return first; } template typename Polyline_constraint_hierarchy_2::Context_iterator Polyline_constraint_hierarchy_2:: contexts_end(T va, T vb) const { Context_iterator first, last; if( !get_contexts(va,vb,first,last)) CGAL_triangulation_assertion(false); return last; } template void Polyline_constraint_hierarchy_2:: swap(Constraint_id first, Constraint_id second){ // We have to look at all subconstraints for(Vertex_it it = first.vl_ptr()->skip_begin(), succ = it, end = first.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == first.vl_ptr()){ ctit->enclosing = 0; break; } } } // We have to look at all subconstraints for(Vertex_it it = second.vl_ptr()->skip_begin(), succ = it, end = second.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == second.vl_ptr()){ ctit->enclosing = first.vl_ptr(); break; } } } // We have to look at all subconstraints for(Vertex_it it = first.vl_ptr()->skip_begin(), succ = it, end = first.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == 0){ ctit->enclosing = second.vl_ptr(); break; } } } first.vl_ptr()->swap(*second.vl_ptr()); } template void Polyline_constraint_hierarchy_2:: remove_constraint(Constraint_id cid){ constraint_set.erase(cid); // We have to look at all subconstraints for(Vertex_it it = cid.vl_ptr()->skip_begin(), succ = it, end = cid.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and remove the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == cid.vl_ptr()){ hcl->erase(ctit); break; } } // If the constraint passes several times through the same subconstraint, // the above loop maybe removes them in the wrong order // If this was the only context in the list, delete the context list if(hcl->empty()){ sc_to_c_map.erase(scit); delete hcl; } } delete cid.vl_ptr(); } // This function removes vertex v from the polyline constraint // It only works for one polyline passing through v // 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_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)); CGAL_assertion_msg( uv_sc_iter != sc_to_c_map.end(), "not a subconstraint" ); Context_list* uv_hcl = uv_sc_iter->second; CGAL_assertion_msg((u == w) || (uv_hcl->size() == 1), "more than one constraint passing through the subconstraint" ); if(*(uv_hcl->front().current()) != u) { std::swap(u,w); uv_sc_iter = sc_to_c_map.find(make_edge(u, v)); CGAL_assertion_msg( uv_sc_iter != sc_to_c_map.end(), "not a subconstraint" ); uv_hcl = (*uv_sc_iter).second; CGAL_assertion_msg((u == w) || (uv_hcl->size() == 1), "more than one constraint passing through the subconstraint" ); } // now u,v, and w are ordered along the polyline constraint if(vc.input()){ uc.input() = true; wc.input() = true; } typename Sc_to_c_map::iterator vw_sc_iter = sc_to_c_map.find(make_edge(v, w)); CGAL_assertion_msg( vw_sc_iter != sc_to_c_map.end(), "not a subconstraint" ); Context_list* vw_hcl = vw_sc_iter->second; CGAL_assertion_msg((u == w) || (vw_hcl->size() == 1), "more than one constraint passing through the subconstraint" ); Vertex_list* vertex_list = uv_hcl->front().id().vl_ptr(); CGAL_assertion_msg(vertex_list == vw_hcl->front().id().vl_ptr(), "subconstraints from different polyline constraints" ); // Remove the list item which points to v vertex_list->skip(vc.base()); if(u != w){ // Remove the entries for [u,v] and [v,w] sc_to_c_map.erase(uv_sc_iter); sc_to_c_map.erase(vw_sc_iter); delete vw_hcl; // reuse other context list sc_to_c_map[make_edge(u,w)] = uv_hcl; }else{ sc_to_c_map.erase(uv_sc_iter); delete vw_hcl; } } template std::size_t Polyline_constraint_hierarchy_2::remove_points_without_corresponding_vertex(Constraint_id cid) { std::size_t n = 0; for(Point_it it = points_in_constraint_begin(cid); it != points_in_constraint_end(cid); ++it) { if(cid.vl_ptr()->is_skipped(it.base())) { it = cid.vl_ptr()->erase(it.base()); ++n; } } return n; } template std::size_t Polyline_constraint_hierarchy_2::remove_points_without_corresponding_vertex() { std::size_t n = 0; for(C_iterator it = constraint_set.begin(); it!= constraint_set.end(); ++it){ n+= remove_points_without_corresponding_vertex(*it); } return n; } template typename Polyline_constraint_hierarchy_2::Constraint_id Polyline_constraint_hierarchy_2::concatenate(Constraint_id first, Constraint_id second) { constraint_set.erase(first); constraint_set.erase(second); // We have to look at all subconstraints for(Vertex_it it = second.vl_ptr()->skip_begin(), succ = it, end = second.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == second.vl_ptr()){ ctit->enclosing = first.vl_ptr(); break; } } } // now we really concatenate the vertex lists // Note that all iterators pointing into second remain valid. // This concerns user code, as well as the data member "pos" of the Context class first.vl_ptr()->pop_back(); // because it is the same as second.front() Vertex_it back_it = first.vl_ptr()->skip_end(); --back_it; first.vl_ptr()->splice(first.vl_ptr()->skip_end(), *(second.vl_ptr()), second.vl_ptr()->skip_begin(), second.vl_ptr()->skip_end()); // Note that for VC8 with iterator debugging the iterators pointing into second // are NOT valid So we have to update them for(Vertex_it it = back_it, succ = it, end = first.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and update pos in the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == first.vl_ptr()){ ctit->pos = it; break; } } } constraint_set.insert(first); delete second.vl_ptr(); return first; } template typename Polyline_constraint_hierarchy_2::Constraint_id Polyline_constraint_hierarchy_2::concatenate2(Constraint_id first, Constraint_id second) { constraint_set.erase(first); constraint_set.erase(second); // We have to look at all subconstraints for(Vertex_it it = first.vl_ptr()->skip_begin(), succ = it, end = first.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == first.vl_ptr()){ ctit->enclosing = second.vl_ptr(); break; } } } // now we really concatenate the vertex lists // Note that all iterators pointing into second remain valid. first.vl_ptr()->pop_back(); // because it is the same as second.front() Vertex_it back_it = first.vl_ptr()->skip_end(); --back_it; second.vl_ptr()->splice(second.vl_ptr()->skip_begin(), *(first.vl_ptr()), first.vl_ptr()->skip_begin(), first.vl_ptr()->skip_end()); // Note that for VC8 with iterator debugging the iterators pointing into second // are NOT valid So we have to update them for(Vertex_it it = back_it, succ = it, end = first.vl_ptr()->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and update pos in the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == second.vl_ptr()){ ctit->pos = it; break; } } } constraint_set.insert(second); delete first.vl_ptr(); return second.vl_ptr(); } // split a constraint in two constraints, so that vcit becomes the first // vertex of the new constraint // returns the new constraint template typename Polyline_constraint_hierarchy_2::Constraint_id Polyline_constraint_hierarchy_2::split(Constraint_id first, Vertex_it vcit) { constraint_set.erase(first); Vertex_list* second = new Vertex_list; second->splice(second->skip_end(), *(first.vl_ptr()), vcit.base(), first.vl_ptr()->skip_end()); first.vl_ptr()->push_back(second->front()); // Duplicate the common vertex Vertex_it vit = second->skip_begin(); vit.input() = true; vit = first.vl_ptr()->skip_end(); --vit; vit.input() = true; constraint_set.insert(first); constraint_set.insert(second); // We have to look at all subconstraints for(Vertex_it it = second->skip_begin(), succ = it, end = second->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == first.vl_ptr()){ ctit->enclosing = second; break; } } } return second; } template typename Polyline_constraint_hierarchy_2::Constraint_id Polyline_constraint_hierarchy_2::split2(Constraint_id first, Vertex_it vcit) { constraint_set.erase(first); Vertex_list* second = new Vertex_list; second->splice(second->skip_end(), *first.vl_ptr(), first.vl_ptr()->skip_begin(), vcit.base()); second->push_back(first.vl_ptr()->front()); // Duplicate the common vertex Vertex_it vit = second->skip_end(); --vit; vit.input() = true; vit = first.vl_ptr()->skip_begin(); vit.input() = true; constraint_set.insert(first); constraint_set.insert(second); // We have to look at all subconstraints for(Vertex_it it = second->skip_begin(), succ = it, end = second->skip_end(); ++succ != end; ++it){ typename Sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); Context_list* hcl = scit->second; // and replace the context of the constraint for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == first.vl_ptr()){ ctit->enclosing = second; break; } } } return second; } /* when a constraint is inserted, it is, at first, both a constraint and a subconstraint */ template typename Polyline_constraint_hierarchy_2::Vertex_list* Polyline_constraint_hierarchy_2:: insert_constraint(T va, T vb){ Edge he = make_edge(va, vb); // First, check if the constraint was already inserted. // If it was not, then the iterator to the lower bound will serve as // the hint of the insertion. typename Constraint_map::iterator c_map_it = constraint_map.lower_bound(he); if(c_map_it != constraint_map.end() && he == c_map_it->first) return 0; Vertex_list* children = new Vertex_list; Context_list* fathers; typename Sc_to_c_map::iterator scit = sc_to_c_map.find(he); if(scit == sc_to_c_map.end()){ fathers = new Context_list; sc_to_c_map.insert(std::make_pair(he,fathers)); } else { fathers = scit->second; } children->push_front(Node(va, true)); // was he.first children->push_back(Node(vb, true)); // was he.second constraint_set.insert(children); Context ctxt; ctxt.enclosing = children; ctxt.pos = children->skip_begin(); fathers->push_front(ctxt); constraint_map.insert(c_map_it, typename Constraint_map::value_type(he, children)); return children; } template void Polyline_constraint_hierarchy_2:: append_constraint(Constraint_id cid, T va, T vb){ Edge he = make_edge(va, vb); Context_list* fathers; typename Sc_to_c_map::iterator scit = sc_to_c_map.find(he); if(scit == sc_to_c_map.end()){ fathers = new Context_list; sc_to_c_map.insert(std::make_pair(he,fathers)); } else { fathers = scit->second; } typename Vertex_list::skip_iterator bit = cid.vl_ptr()->skip_end(); --bit; cid.vl_ptr()->push_back(Node(vb, true)); Context ctxt; ctxt.enclosing = cid.vl_ptr(); ctxt.pos = bit; fathers->push_front(ctxt); } template void Polyline_constraint_hierarchy_2:: clear() { C_iterator cit; Sc_iterator scit; // clean and delete vertices lists for(cit=constraint_set.begin(); cit != constraint_set.end(); cit++){ cit->vl_ptr()->clear(); delete cit->vl_ptr(); } // clean and delete context lists for(scit=sc_to_c_map.begin(); scit != sc_to_c_map.end(); scit++){ (*scit).second->clear(); delete (*scit).second; } sc_to_c_map.clear(); constraint_set.clear(); constraint_map.clear(); } template bool Polyline_constraint_hierarchy_2:: next_along_sc(T va, T vb, T& w) const { // find the next vertex after vb along any enclosing constrained // return false if there is no .... Context_iterator ctxtit, past; if(!get_contexts(va, vb, ctxtit, past)) CGAL_triangulation_assertion(false); Vertex_it pos; for( ; ctxtit != past; ctxtit++){ pos = ctxtit->pos; if((*pos)==va) { ++pos; ++pos; if (pos != ctxtit->enclosing->end()) { w=(*pos); return true;} } else { if (pos != ctxtit->enclosing->begin()) {--pos; w=(*pos); return true;} } } return false; } /* Attention, le point v DOIT etre un point de Steiner, et les segments va,v et v,vb sont des sous contraintes. */ template void Polyline_constraint_hierarchy_2:: remove_Steiner(T v, T va, T vb) { // remove a Steiner point CGAL_precondition(!is_constrained_vertex(v)); Context_list* hcl1; Context_list* hcl2; if(!get_contexts(va,v,hcl1)) CGAL_triangulation_assertion(false); if(!get_contexts(v,vb,hcl2)) CGAL_triangulation_assertion(false); Vertex_it pos; for(Context_iterator ctit=hcl1->begin(); ctit != hcl1->end(); ctit++){ pos = ctit->pos; if((*pos)==va) pos++; pos = ctit->enclosing->erase(pos); ctit->pos = --pos; } sc_to_c_map.erase(make_edge(va,v)); sc_to_c_map.erase(make_edge(v,vb)); delete hcl2; sc_to_c_map.insert(std::make_pair(make_edge(va,vb),hcl1)); } /* same as add_Steiner precondition : va,vb est une souscontrainte. */ template void Polyline_constraint_hierarchy_2:: split_constraint(T va, T vb, T vc){ add_Steiner(va, vb, vc); } template void Polyline_constraint_hierarchy_2:: add_Steiner(T va, T vb, T vc){ Context_list* hcl=NULL; if(!get_contexts(va,vb,hcl)) CGAL_triangulation_assertion(false); Context_list* hcl2 = new Context_list; Vertex_it pos; Context ctxt; for(Context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { // insert vc in enclosing constraint pos = ctit->current(); ++pos; pos = ctit->enclosing->insert(pos.base(), Node(vc)); --pos; // set ctxt to the context of (vc,vb) // change *ctit in hcl to the context of (va,vc) // add ctxt to hcl2 list ctxt.enclosing = ctit->enclosing; if(*pos == va) { ctit->pos = pos; ctxt.pos = ++pos; } else { //(*pos)==vb ctxt.pos = pos; ctit->pos = ++pos; } hcl2->push_back(ctxt); } Context_list* hcl3; if (get_contexts(va,vc,hcl3)) { // (va,vc) is already a subconstraint hcl3->splice(hcl3->end(), *hcl); delete hcl; } else sc_to_c_map.insert(std::make_pair(make_edge(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.insert(std::make_pair(make_edge(vc,vb), hcl2)); sc_to_c_map.erase(make_edge(va,vb)); return; } template inline typename Polyline_constraint_hierarchy_2::Edge Polyline_constraint_hierarchy_2:: make_edge(T va, T vb) const { return comp(va, vb) ? Edge(va,vb) : Edge(vb,va); } template inline 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)); if( sc_iter == sc_to_c_map.end() ) return(false); hcl = (*sc_iter).second; return true; } template inline bool Polyline_constraint_hierarchy_2:: get_contexts(T va, T vb, Context_iterator& ctxt, Context_iterator& past) const { Context_list* hcl; if (!get_contexts(va,vb,hcl)) return false; ctxt = hcl->begin(); past = hcl->end(); return true; } template inline typename Polyline_constraint_hierarchy_2::Vertex_it 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; } template void Polyline_constraint_hierarchy_2:: oriented_end(T va, T vb, T& vc) const { Context_iterator ctxt, past; if(!get_contexts(va,vb, ctxt, past) ) CGAL_triangulation_assertion(false); if(*(ctxt->pos) == va) vc = ctxt->enclosing->back(); else vc = ctxt->enclosing->front(); } template void Polyline_constraint_hierarchy_2:: print() const { C_iterator hcit; std::map vertex_num; int num = 0; for(hcit = c_begin(); hcit != c_end(); hcit++) { Constraint_id cid = (*hcit); Vertex_it vit =cid.vl_ptr()->skip_begin(), end = cid.vl_ptr()->skip_end(); for (;vit != end; vit++){ num ++; vertex_num.insert(std::make_pair((*vit), num)); } } // typename std::map::iterator vnit = vertex_num.begin(); // for(; vnit != vertex_num.end(); vnit++) { // vnit->second = ++num; // std::cerr << "vertex num " << num << " " << vnit->first->point() // << std::endl; // } C_iterator cit=c_begin(); Sc_iterator scit=sc_begin(); for(; cit != c_end(); cit++){ std::cout << std::endl ; std::cout << "constraint " ; std::cout << cit->vl_ptr(); std::cout << " subconstraints " ; Vertex_it vit = (*cit).vl_ptr()->skip_begin(), end = (*cit).vl_ptr()->skip_end(); for(; vit != end; vit++){ std::cout << vertex_num[*vit] <<" "; } vit = (*cit).vl_ptr()->skip_begin(), end = (*cit).vl_ptr()->skip_end(); for(; vit != end; vit++){ std::cout << (*vit)->point() <<" "; } } std::cout << std::endl ; for(;scit != sc_end(); scit++){ std::cout << "subconstraint " ; std::cout << vertex_num[scit->first.first] << " " << vertex_num[scit->first.second]; Context_iterator cb, ce; get_contexts(scit->first.first, scit->first.second, cb, ce); std::cout << " enclosing " ; for(; cb != ce; cb++) { std::cout << cb->id().vl_ptr(); std::cout << " " ; } std::cout << std::endl ; } return; } } //namespace CGAL #endif // CGAL_POLYLINE_CONSTRAINT_HIERARCHY_2_H