// Copyright (c) 1999 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) : Olivier Billet, Mariette Yvinec #ifndef CGAL_CONSTRAINT_HIERARCHY_2_H #define CGAL_CONSTRAINT_HIERARCHY_2_H #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 Constraint_hierarchy_2 { public: typedef std::pair H_edge; typedef T H_vertex; typedef Constraint_hierarchy_2 Hierarchy; typedef std::pair H_constraint; typedef std::list H_vertex_list; typedef std::list H_constraint_list; typedef typename std::list::iterator H_vertex_it; typedef typename std::list::iterator H_constraint_it; class Pair_compare { Compare comp; public: Pair_compare(const Compare& comp) : comp(comp) {} bool operator()(const H_edge& e1, const H_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 H_context { friend class Constraint_hierarchy_2; private: H_vertex_list* enclosing; H_vertex_it pos; public: H_vertex_it vertices_begin() { return enclosing->begin();} H_vertex_it current() {return pos;} H_vertex_it vertices_end() {return enclosing->end();} std::size_t number_of_vertices() {return enclosing->size();} }; typedef std::list H_context_list; typedef typename std::list::iterator H_context_iterator; typedef std::map H_vertex_map; typedef std::map H_c_to_sc_map; typedef std::map H_sc_to_c_map; typedef typename H_c_to_sc_map::const_iterator H_c_iterator; typedef typename H_sc_to_c_map::const_iterator H_sc_iterator; typedef typename H_vertex_map::const_iterator H_v_iterator; typedef std::pair H_c_value; typedef std::pair H_sc_value; private: Compare comp; // data for the 1d hierarchy H_c_to_sc_map c_to_sc_map; H_sc_to_c_map sc_to_c_map; // data for the 0d hierarchy H_vertex_map vertex_map; public: Constraint_hierarchy_2(const Compare& comp_ = Compare()) : comp(comp_) , c_to_sc_map(Pair_compare(comp)) , sc_to_c_map(Pair_compare(comp)) { } Constraint_hierarchy_2(const Constraint_hierarchy_2& ch); ~Constraint_hierarchy_2(){ clear();} void clear(); Constraint_hierarchy_2& operator=(const 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; bool vertices_in_constraint(H_constraint hc, H_vertex_it& v_first, H_vertex_it& v_past) const; H_vertex_it vertices_in_constraint_begin(T va, T vb); H_vertex_it vertices_in_constraint_end(T va, T vb); bool enclosing_constraint(H_edge he, H_constraint& hc) const; bool enclosing_constraint(T vaa, T vbb, T& va, T& vb) const; bool enclosing_constraints(T vaa, T vbb, H_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; H_context context(T va, T vb); std::size_t number_of_enclosing_constraints(T va, T vb); H_context_iterator contexts_begin(T va, T vb); H_context_iterator contexts_end(T va, T vb); std::size_t number_of_constraints() { return c_to_sc_map.size();} std::size_t number_of_subconstraints() {return sc_to_c_map.size();} // insert/remove void add_Steiner(T va, T vb, T vx); bool insert_constraint(T va, T vb); void remove_constraint(T va, T vb); void split_constraint(T va, T vb, T vc); void constrain_vertex(T v, Data data=Data()); void unconstrain_vertex(T v); void set_data(T v, Data data); Data get_data(T v); void remove_Steiner(T v, T va, T vb); // iterators H_sc_iterator sc_begin() const{ return sc_to_c_map.begin(); } H_sc_iterator sc_end() const{ return sc_to_c_map.end(); } H_c_iterator c_begin() const{ return c_to_sc_map.begin(); } H_c_iterator c_end() const{ return c_to_sc_map.end(); } H_v_iterator v_begin() const{ return vertex_map.begin(); } H_v_iterator v_end() const{ return vertex_map.end(); } //Helping functions void copy(const Constraint_hierarchy_2& ch); void copy(const Constraint_hierarchy_2& ch, std::map& vmap); void swap(Constraint_hierarchy_2& ch); private: H_edge make_edge(T va, T vb) const; H_vertex_it get_pos(T va, T vb) const; bool get_contexts(T va, T vb, H_context_iterator& ctxt, H_context_iterator& past) const; H_context_list * get_contexts(T va, T vb) const; //to_debug public: void print() const; }; template Constraint_hierarchy_2:: Constraint_hierarchy_2(const Constraint_hierarchy_2& ch) : comp(ch.comp) , c_to_sc_map(Pair_compare(comp)) , sc_to_c_map(Pair_compare(comp)) { copy(ch); } template Constraint_hierarchy_2& Constraint_hierarchy_2:: operator=(const Constraint_hierarchy_2& ch){ copy(ch); return *this; } template void Constraint_hierarchy_2:: copy(const Constraint_hierarchy_2& ch1) { // create a identity transfer vertex map std::map vmap; H_c_iterator cit1 = ch1.c_begin(); for( ; cit1 != ch1.c_end(); ++cit1) { H_vertex_it vit = cit1->second->begin(); for( ; vit != cit1->second->end(); ++vit) { vmap[*vit] = *vit; } } copy(ch1, vmap); } template void Constraint_hierarchy_2:: copy(const Constraint_hierarchy_2& ch1, std::map& vmap) // copy with a tranfer vertex map { clear(); // copy c_to_sc_map H_c_iterator cit1 = ch1.c_begin(); for( ; cit1 != ch1.c_end(); ++cit1) { H_vertex u2 = vmap[cit1->first.first]; H_vertex v2 = vmap[cit1->first.second]; H_vertex_list* hvl1 = cit1->second; H_vertex_list* hvl2 = new H_vertex_list; H_vertex_it vit = hvl1->begin(); for( ; vit != hvl1->end(); ++vit) hvl2->push_back(vmap[*vit]); c_to_sc_map[make_edge(u2,v2)] = hvl2; } // copy sc_to_c_map H_sc_iterator scit1 = ch1.sc_begin(); for( ; scit1 != ch1.sc_end(); ++scit1) { //vertices of the subconstraints H_vertex uu2 = vmap[scit1->first.first]; H_vertex vv2 = vmap[scit1->first.second]; H_context_list* hcl1 = scit1->second; H_context_list* hcl2 = new H_context_list; H_context_iterator cit1 = hcl1->begin(); for( ; cit1 != hcl1->end(); ++cit1){ // vertices of the enclosing constraints H_vertex u2 = vmap[cit1->enclosing->front()]; H_vertex v2 = vmap[cit1->enclosing->back()]; H_context ctxt2; ctxt2.enclosing = c_to_sc_map[make_edge(u2,v2)]; ctxt2.pos = ctxt2.enclosing->begin(); H_vertex_it aux = cit1->enclosing->begin(); while( aux != cit1->pos) { ++aux; ++ctxt2.pos; } hcl2->push_back(ctxt2); } sc_to_c_map[make_edge(uu2,vv2)] = hcl2; } // copy of vertex_map H_v_iterator hvit1 = ch1.vertex_map.begin(); for ( ; hvit1 != ch1.vertex_map.end(); ++hvit1){ vertex_map[vmap[hvit1->first]] = hvit1->second; } return; } template void Constraint_hierarchy_2:: swap(Constraint_hierarchy_2& ch) { c_to_sc_map.swap(ch.c_to_sc_map); sc_to_c_map.swap(ch.sc_to_c_map); vertex_map.swap(ch.vertex_map); } template bool Constraint_hierarchy_2:: is_constrained_vertex(T v) const { return( vertex_map.find(v) != vertex_map.end() ); } template bool 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 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() ); } #if 0 template bool Constraint_hierarchy_2:: vertices_in_constraint(H_constraint hc, H_vertex_it& v_first, H_vertex_it& v_past ) const { H_sc_iterator sc_iter = sc_to_c_map.find(hc); if( sc_iter == sc_to_c_map.end() ) return false; v_first = (*sc_iter).second; return true; } #endif template bool Constraint_hierarchy_2:: enclosing_constraint(H_edge he, H_constraint& hc) const { H_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; } template bool Constraint_hierarchy_2:: enclosing_constraint(T vaa, T vbb, T& va, T& vb) const { H_context_iterator hcit, past; if ( !get_contexts(vaa,vbb, hcit ,past)) return false; va = hcit->enclosing->front(); vb = hcit->enclosing->back(); return true; } template bool Constraint_hierarchy_2:: enclosing_constraints(T vaa, T vbb , H_constraint_list& hcl) const { H_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 Constraint_hierarchy_2::H_context Constraint_hierarchy_2:: context(T va, T vb) { H_context_iterator hcit, past; if(!get_contexts(va,vb, hcit ,past)) CGAL_triangulation_assertion(false); return *hcit; } template std::size_t Constraint_hierarchy_2:: number_of_enclosing_constraints(T va, T vb) { H_context_list* hcl = get_contexts(va, vb); CGAL_triangulation_assertion(hcl != NULL); return hcl->size(); } template typename Constraint_hierarchy_2::H_context_iterator Constraint_hierarchy_2:: contexts_begin(T va, T vb) { H_context_iterator first, last; if( !get_contexts(va,vb,first,last)) CGAL_triangulation_assertion(false); return first; } template typename Constraint_hierarchy_2::H_context_iterator Constraint_hierarchy_2:: contexts_end(T va, T vb) { H_context_iterator first, last; if( !get_contexts(va,vb,first,last)) CGAL_triangulation_assertion(false); return last; } template typename Constraint_hierarchy_2::H_vertex_it Constraint_hierarchy_2:: vertices_in_constraint_begin(T va, T vb) { H_c_iterator cit = c_to_sc_map.find(make_edge(va,vb)); CGAL_triangulation_assertion( cit != c_to_sc_map.end()); return cit->second->begin(); } template typename Constraint_hierarchy_2::H_vertex_it Constraint_hierarchy_2:: vertices_in_constraint_end(T va, T vb) { H_c_iterator cit = c_to_sc_map.find(make_edge(va,vb)); CGAL_triangulation_assertion( cit != c_to_sc_map.end()); return cit->second->end(); } /* when a constraint is inserted, it is, at first, both a constraint and a subconstraint */ template bool Constraint_hierarchy_2:: insert_constraint(T va, T vb){ H_edge he = make_edge(va, vb); H_vertex_list* children = new H_vertex_list; children->push_front(he.first); children->push_back(he.second); bool insert_ok = (c_to_sc_map.insert(std::make_pair(he,children))).second; if (insert_ok) { H_context ctxt; ctxt.enclosing = children; ctxt.pos = children->begin(); // It may happen that the sub-constraint he is already in the map. The // following variable 'fathers' is a reference to a pointer. If the // sub-constraint he is already in the map, 'fathers' will be the // pointer to its fathers list. If the sub-constraint he is new, // std::make_pair(he, 0) is inserted in the map (that is what does // map::operator[]), 'fathers' will be a default-constructed pointer // (that is the NULL pointer), and it will re-assigned to a newly // created context list. As 'father' is a reference (to a pointer), // there is no need to modify the map after that. H_context_list*& fathers = sc_to_c_map[he]; if(fathers == 0) { fathers = new H_context_list; } fathers->push_front(ctxt); return true; } delete children; return false; //duplicate constraint - no insertion } template void Constraint_hierarchy_2:: remove_constraint(T va, T vb){ H_edge he = make_edge(va, vb); typename H_c_to_sc_map::iterator c_to_sc_it = c_to_sc_map.find(he); CGAL_triangulation_assertion(c_to_sc_it != c_to_sc_map.end()); H_vertex_list *hvl = c_to_sc_it->second; // We have to look at all subconstraints for(H_vertex_it it = hvl->begin(), succ = it; ++succ != hvl->end(); ++it){ typename H_sc_to_c_map::iterator scit = sc_to_c_map.find(make_edge(*it,*succ)); CGAL_triangulation_assertion(scit != sc_to_c_map.end()); H_context_list* hcl = scit->second; // and remove the contraint from the context list of the subcontraint for(H_context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { if(ctit->enclosing == hvl){ hcl->erase(ctit); break; } } // If this was the only context in the list, delete the context list if(hcl->empty()){ sc_to_c_map.erase(scit); delete hcl; } } c_to_sc_map.erase(c_to_sc_it); delete hvl; } template void Constraint_hierarchy_2:: constrain_vertex(T v, Data data){ vertex_map.insert(std::make_pair(v,data)); } template void Constraint_hierarchy_2:: unconstrain_vertex(T v){ vertex_map.erase(v); } template Data Constraint_hierarchy_2:: get_data(T v){ CGAL_precondition( is_constrained_vertex(v) ); return (*vertex_map.find(v)).second; } template void Constraint_hierarchy_2:: set_data(T v, Data data){ vertex_map.erase(v); vertex_map.insert(std::make_pair(v,data)); } template void Constraint_hierarchy_2:: clear() { H_c_iterator cit; H_sc_iterator scit; // clean and delete vertices lists for(cit=c_to_sc_map.begin(); cit != c_to_sc_map.end(); cit++){ (*cit).second->clear(); delete (*cit).second; } // 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(); c_to_sc_map.clear(); vertex_map.clear(); } template bool 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 .... H_context_iterator ctxtit, past; if(!get_contexts(va, vb, ctxtit, past)) CGAL_triangulation_assertion(false); H_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 Constraint_hierarchy_2:: remove_Steiner(T v, T va, T vb) { // remove a Steiner point CGAL_precondition(!is_constrained_vertex(v)); H_context_list* hcl1 = get_contexts(va, v); CGAL_triangulation_assertion(hcl1 != NULL); H_context_list* hcl2 = get_contexts(v, vb); CGAL_triangulation_assertion(hcl2 != NULL); H_vertex_it pos; for(H_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 Constraint_hierarchy_2:: split_constraint(T va, T vb, T vc){ add_Steiner(va, vb, vc); } template void Constraint_hierarchy_2:: add_Steiner(T va, T vb, T vc){ H_context_list* hcl = get_contexts(va, vb); CGAL_triangulation_assertion(hcl != NULL); H_context_list* hcl2 = new H_context_list; H_vertex_it pos; H_context ctxt; for(H_context_iterator ctit=hcl->begin(); ctit != hcl->end(); ctit++) { // insert vc in enclosing constraint pos = ctit->pos; ++pos; pos = ctit->enclosing->insert(pos, 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); } if (H_context_list* hcl3 = get_contexts(va,vc)) { // (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 (H_context_list* hcl3 = get_contexts(vc,vb)) {// (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 Constraint_hierarchy_2::H_edge Constraint_hierarchy_2:: make_edge(T va, T vb) const { return comp(va, vb) ? H_edge(va,vb) : H_edge(vb,va); } template inline typename Constraint_hierarchy_2::H_context_list* Constraint_hierarchy_2:: get_contexts(T va, T vb) const { H_sc_iterator sc_iter = sc_to_c_map.find(make_edge(va,vb)); if ( sc_iter == sc_to_c_map.end() ) return NULL; return (*sc_iter).second; } template inline bool Constraint_hierarchy_2:: get_contexts(T va, T vb, H_context_iterator& ctxt, H_context_iterator& past) const { if (H_context_list * hcl = get_contexts(va, vb)) { ctxt = hcl->begin(); past = hcl->end(); return true; } return false; } template inline typename Constraint_hierarchy_2::H_vertex_it 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 Constraint_hierarchy_2:: oriented_end(T va, T vb, T& vc) const { H_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 Constraint_hierarchy_2:: print() const { H_c_iterator hcit; std::map vertex_num; int num = 0; for(hcit = c_begin(); hcit != c_end(); hcit++) { H_vertex_it vit = (*hcit).second->begin(); for (; vit != (*hcit).second->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; // } H_c_iterator cit=c_begin(); H_sc_iterator scit=sc_begin(); for(; cit != c_end(); cit++){ std::cout << std::endl ; std::cout << "constraint " ; std::cout << vertex_num[cit->first.first] << " " << vertex_num[cit->first.second]; std::cout << " subconstraints " ; H_vertex_it vit = cit->second->begin(); for(; vit != cit->second->end(); vit++){ std::cout << vertex_num[*vit] <<" "; } } std::cout << std::endl ; for(;scit != sc_end(); scit++){ std::cout << "subconstraint " ; std::cout << vertex_num[scit->first.first] << " " << vertex_num[scit->first.second]; H_constraint_list hcl; enclosing_constraints( scit->first.first, scit->first.second, hcl); H_constraint_it hcit=hcl.begin(); std::cout << " enclosing " ; for(; hcit != hcl.end(); hcit++) { std::cout << vertex_num[hcit->first] <<" " << vertex_num[hcit->second] ; std::cout << " " ; } std::cout << std::endl ; } return; } } //namespace CGAL #endif // CGAL_CONSTRAINT_HIERARCHY_2_H