// Copyright (c) 2017 CNRS and LIRIS' Establishments (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 Lesser 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: LGPL-3.0+ // // Author(s) : Guillaume Damiand // #ifndef CGAL_PATH_ON_SURFACE_H #define CGAL_PATH_ON_SURFACE_H 1 #include #include #include #include namespace CGAL { template class Path_on_surface { public: typedef Map_ Map; typedef typename Map::Dart_handle Dart_handle; typedef typename Map::Dart_const_handle Dart_const_handle; typedef Path_on_surface Self; Path_on_surface(const Map& amap) : m_map(amap), m_is_closed(false) {} void swap(Self& p2) { assert(&m_map==&(p2.m_map)); m_path.swap(p2.m_path); std::swap(m_is_closed, p2.m_is_closed); } /// @Return true if this path is equal to other path, identifying dart 0 of /// this path with dart start in other path. bool are_same_paths_from(const Self& other, std::size_t start) const { assert(start==0 || start0) { return false; } for(std::size_t i=0; i0) { return false; } for(std::size_t i=0; i>nb; if (nb!=m_map.darts().index(get_ith_dart(start))) { return false; } start=next_index(start); } iss>>nb; if (iss.good()) { return false; } // There are more elements in other than in this path return true; } /// @return true if this path is equal to other path. For closed paths, test /// all possible starting darts. other path is given by index of its /// darts, in text format. bool operator==(const char* other) const { if (!is_closed()) { return are_same_paths_from(other, 0); } for(std::size_t start=0; start=length()) return; m_path.resize(n); if (update_isclosed) { update_is_closed(); } } std::size_t next_index(std::size_t i) const { return (is_closed() && i==m_path.size()-1?0:i+1); } std::size_t prev_index(std::size_t i) const { return (is_closed() && i==0?m_path.size()-1:i-1); } Dart_const_handle get_ith_dart(std::size_t i) const { assert(i (m_map, m_map.other_extremity(back()), dh))); */ m_path.push_back(dh); if (update_isclosed) { update_is_closed(); } } // @return true iff the path is valid; i.e. a sequence of edges two by // two adjacent. bool is_valid() const { for (unsigned int i=1; i(m_map, m_path[i], pend)) { return false; } } if (is_closed()) { Dart_const_handle pend=m_map.other_extremity(m_path[m_path.size()-1]); if (pend==Map::null_handle) { return false; } if (!CGAL::template belong_to_same_cell(m_map, pend, m_path[0])) { return false; } } return true; } // Update m_is_closed to true iff the path is closed (i.e. the second // extremity of the last dart of the path is the same vertex than the one // of the first dart of the path). void update_is_closed() { if (is_empty()) { m_is_closed=false; } // or true by vacuity ? else if (!is_valid()) { m_is_closed=false; } // Interest ?? else { Dart_const_handle pend=m_map.other_extremity(back()); if (pend==Map::null_handle) { m_is_closed=false; } else { m_is_closed=CGAL::belong_to_same_cell(m_map, m_path[0], pend); } } } // @return true iff the path does not pass twice through a same edge // or a same vertex. bool is_simple() const { typename Map::size_type markvertex=m_map.get_new_mark(); typename Map::size_type markedge=m_map.get_new_mark(); bool res=true; unsigned int i=0; for (i=0; res && i(m_path[i], markvertex); CGAL::mark_cell(m_path[i], markedge); } i=0; while(m_map.number_of_marked_darts(markedge)>0) { assert(i(m_path[i], markvertex); CGAL::unmark_cell(m_path[i], markedge); ++i; } m_map.free_mark(markvertex); m_map.free_mark(markedge); return res; } void reverse() { std::vector new_path(m_path.size()); for (std::size_t i=0; i(m_path[i]); } new_path.swap(m_path); } /// If the given path is opened, close it by doing the same path that the /// first one in reverse direction. void close() { if (!is_closed()) { for (int i=m_path.size()-1; i>=0; --i) { m_path.push_back(m_map.template beta<2>(get_ith_dart(i))); } m_is_closed=true; } } /// @return the turn between dart number i and dart number i+1. /// (turn is position of the second edge in the cyclic ordering of /// edges starting from the first edge around the second extremity /// of the first dart) std::size_t next_positive_turn(std::size_t i) const { assert(is_valid()); assert(i(d1)!=d2) { ++res; d1=m_map.template beta<1, 2>(d1); } // std::cout<<"next_positive_turn="<(get_ith_dart(i)); Dart_const_handle d2=m_map.template beta<2>(get_next_dart(i)); assert(d1!=d2); std::size_t res=1; while (m_map.template beta<0>(d1)!=d2) { ++res; d1=m_map.template beta<0, 2>(d1); } // std::cout<<"next_negative_turn="<=length()-1) { return begin; } // begin is the before last dart while ((positive && next_positive_turn(end)==2) || (!positive && next_negative_turn(end)==2)) { end=next_index(end); } if ((positive && next_positive_turn(end)==1) || (!positive && next_negative_turn(end)==1)) // We are on the end of a bracket { end=next_index(end); } else { end=begin; } return end; } void transform_positive_bracket(std::size_t begin, std::size_t end, Self& new_path) { // There is a special case for (1 2^r). In this case, we need to ignore // the two darts begin and end Dart_const_handle d1=(next_index(begin)!=end? m_map.template beta<0>(get_ith_dart(begin)): m_map.template beta<1,2,0>(get_ith_dart(end))); Dart_const_handle d2=(next_index(begin)!=end? m_map.template beta<2,0,2>(get_ith_dart(end)): m_map.template beta<0,0,2>(get_ith_dart(begin))); new_path.push_back(m_map.template beta<2>(d1)); CGAL::extend_straight_negative_until(new_path, d2); } void transform_negative_bracket(std::size_t begin, std::size_t end, Self& new_path) { // There is a special case for (-1 -2^r). In this case, we need to ignore // the two darts begin and end Dart_const_handle d1=(next_index(begin)!=end? m_map.template beta<2,1>(get_ith_dart(begin)): m_map.template beta<2,0,2,1>(get_ith_dart(end))); Dart_const_handle d2=(next_index(begin)!=end? m_map.template beta<1>(get_ith_dart(end)): m_map.template beta<2,1,1>(get_ith_dart(begin))); new_path.push_back(d1); CGAL::extend_straight_positive_until(new_path, d2); } void transform_bracket(std::size_t begin, std::size_t end, Self& new_path, bool positive) { if (positive) { transform_positive_bracket(begin, end, new_path); } else { transform_negative_bracket(begin, end, new_path); } } // copy all darts starting from begin and going to the dart before end // from this path to new_path. void copy_rest_of_path(std::size_t begin, std::size_t end, Self& new_path) { assert(end<=length()); assert(begin<=end); while(begin!=end) { new_path.push_back(get_ith_dart(begin)); ++begin; } } bool bracket_flattening_one_step() { if (is_empty()) return false; #ifndef NDEBUG bool is_even=length()%2; #endif // NDEBUG Self new_path(m_map); bool positive=false; std::size_t begin, end; std::size_t lastturn=m_path.size()-(is_closed()?0:1); for (begin=0; begin(m_path[next_index(i)])) { res=true; } } if (!res) { return false; } #ifndef NDEBUG bool is_even=length()%2; #endif // NDEBUG --i; // Because we did a ++ before to leave the loop // Here there is a spur at position i in the path Self new_path(m_map); // Special case, the spur is between last dart of the path and the first dart if (is_closed() && i==m_path.size()-1) { copy_rest_of_path(1, m_path.size()-1, new_path); // copy path between 1 and m_path.size()-2 } else { // Otherwise copy darts before the spur if (i>0) { copy_rest_of_path(0, i, new_path); } // copy path between 0 and i-1 // and the darts after if (i+2(get_ith_dart(begin)); } else { d1=m_map.template beta<2,1,2,0>(get_ith_dart(begin)); } new_path.push_back(d1); if (begin!=middle) { if (!case_seven) { CGAL::extend_uturn_positive(new_path, 1); } d1=m_map.template beta<2,1,1>(get_ith_dart(middle)); CGAL::extend_straight_positive_until(new_path, d1); if (next_index(middle)!=end) { CGAL::extend_uturn_positive(new_path, 3); } else { CGAL::extend_straight_positive(new_path, 1); } } if (next_index(middle)!=end) { d1=m_map.template beta<2,0,2,1>(get_ith_dart(end)); CGAL::extend_straight_positive_until(new_path, d1); if (!case_seven) { CGAL::extend_uturn_positive(new_path, 1); } else { CGAL::extend_straight_positive(new_path, 1); } } if (begin==middle && next_index(middle)==end) { // TODO: check if we need to do also something for !case_seven ? // if (case_seven) { CGAL::extend_uturn_positive(new_path, 1); } /* else { assert(false); } // We think (?) that this case is not possible */ } } void push_l_shape_cycle_2() { Dart_const_handle d1= m_map.template beta<2,1,1>(get_ith_dart(0)); clear(); push_back(d1); CGAL::extend_straight_positive(*this, 1); CGAL::extend_straight_positive_until(*this, d1); } bool push_l_shape_2darts() { Dart_const_handle d1=NULL; if (next_negative_turn(0)==1) d1=m_map.template beta<2,1>(get_ith_dart(0)); else if (next_negative_turn(1)==1) d1=m_map.template beta<2,1>(get_ith_dart(1)); else return false; clear(); push_back(d1); CGAL::extend_uturn_positive(*this, 1); //push_back(m_map.template beta<1>(d1)); return true; } bool right_push_one_step() { if (is_empty()) { return false; } if (length()==2) { return push_l_shape_2darts(); } #ifndef NDEBUG bool is_even=length()%2; #endif // NDEBUG std::size_t begin, middle, end; std::size_t lastturn=m_path.size()-(is_closed()?0:1); std::size_t next_turn; std::size_t val_x=0; // value of turn before the beginning of a l-shape bool prev2=false; for (middle=0; middle0) { val_x=next_negative_turn(prev_index(begin)); } // And here now we can push the path Self new_path(m_map); if (end compute_positive_turns() const { std::vector res; if (is_empty()) return res; std::size_t i; for (i=0; i(m_path[i+1])) { res.push_back(0); } else { res.push_back(next_positive_turn(i)); } } if (is_closed()) { if (m_path[i]==m_map.template beta<2>(m_path[0])) { res.push_back(0); } else { res.push_back(next_positive_turn(i)); } } return res; } std::vector compute_negative_turns() const { std::vector res; if (is_empty()) return res; std::size_t i; for (i=0; i(m_path[i+1])) { res.push_back(0); } else { res.push_back(next_negative_turn(i)); } } if (is_closed()) { if (m_path[i]==m_map.template beta<2>(m_path[0])) { res.push_back(0); } else { res.push_back(next_negative_turn(i)); } } return res; } std::vector compute_turns(bool positive) const { return (positive?compute_positive_turns():compute_negative_turns()); } bool same_turns_from(const char* turns, const std::vector& resplus, const std::vector& resmoins, std::size_t start) const { assert(start==0 || start>nb; if ((nb>=0 && resplus[start]!=nb) || (nb<0 && resmoins[start]!=-nb)) { return false; } start=next_index(start); } iss>>nb; if (iss.good()) { return false; } // There are more elements in turns than in res return true; } bool same_turns(const char* turns) const { std::vector resplus=compute_positive_turns(); std::vector resmoins=compute_negative_turns(); if (!is_closed()) { return same_turns_from(turns, resplus, resmoins, 0); } for (std::size_t start=0; start res=compute_positive_turns(); for (std::size_t i=0; i res=compute_negative_turns(); for (std::size_t i=0; i m_path; // The sequence of darts bool m_is_closed; // True iff the path is a cycle }; } // namespace CGAL #endif // CGAL_PATH_ON_SURFACE_H // // EOF //