// Copyright (c) 2019 CNRS and LIRIS' Establishments (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Surface_mesh_topology/include/CGAL/Polygonal_schema.h $ // $Id: Polygonal_schema.h 52186a0 2020-05-14T11:38:15+02:00 Guillaume Damiand // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Guillaume Damiand // #ifndef CGAL_POLYGONAL_SCHEMA_H #define CGAL_POLYGONAL_SCHEMA_H 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace CGAL { namespace Surface_mesh_topology { namespace internal { /// @return opposite label of label s /// (i.e. add/remove - depending if s is positive or negative) inline std::string opposite_label(const std::string& s) { CGAL_assertion(!s.empty()); if (s[0]=='-') { return s.substr(1, std::string::npos); } return std::string("-")+s; } template struct Polygonal_schema_tools {}; template struct Polygonal_schema_tools { typedef typename CMap::Dart_handle Dart_handle; static Dart_handle add_edge_to_face(CMap& cmap, const std::string& s, Dart_handle prev_dart, Dart_handle dart_same_label, Dart_handle dart_opposite_label, std::unordered_map& edge_label_to_dart) { if (dart_same_label!=CMap::null_handle && dart_opposite_label!=CMap::null_handle) { std::cerr<<"Polygonal_schema ERROR: "<<"both labels "<(prev_dart, res); } if (dart_opposite_label!=CMap::null_handle) { cmap.template link_beta<2>(res, dart_opposite_label); } return res; } const std::string& get_label(CMap& cmap, Dart_handle dh) const { return cmap.info(dh).m_label; } }; template struct Polygonal_schema_tools { typedef typename GMap::Dart_handle Dart_handle; // In a GMap, if an edge is 2-free, only one of its two dart has one label. // Otherwise, d has one label and alpha<0,2>(d) the opposite label. static Dart_handle add_edge_to_face(GMap& gmap, const std::string& s, Dart_handle prev_dart, Dart_handle dart_same_label, Dart_handle dart_opposite_label, std::unordered_map& edge_label_to_dart) { if (dart_same_label!=GMap::null_handle && dart_opposite_label!=GMap::null_handle) { std::cerr<<"Polygonal_schema ERROR: "<<"both labels "<(res, dh2); if (prev_dart!=gmap.null_handle) { gmap.template link_alpha<1>(res, gmap.template alpha<0>(prev_dart)); } if (dart_same_label!=GMap::null_handle) { // Here dart_same_label!=GMap::null_handle std::string s2=internal::opposite_label(s); edge_label_to_dart[s2]=dh2; gmap.info(dh2).m_label=s2; gmap.template sew<2>(res, dart_same_label); } else { // Here either dart_opposite_label!=GMap::null_handle, or both are GMap::null_handle edge_label_to_dart[s]=res; gmap.info(res).m_label=s; if (dart_opposite_label!=GMap::null_handle) { std::string s2=internal::opposite_label(s); edge_label_to_dart[s2]=res; gmap.info(res).m_label=s2; gmap.template sew<2>(dh2, dart_opposite_label); } } return res; } std::string get_label(GMap& gmap, Dart_handle dh) const { if (gmap.info(dh).m_label.empty()) { if (!gmap.template is_free<2>(dh)) { return gmap.info(gmap.template alpha<2>(dh)).m_label; } else { return internal::opposite_label(gmap.info(gmap.template alpha<0>(dh))); } } return gmap.info(dh).m_label; } }; } // end namespace internal struct Combinatorial_map_tag; struct Generalized_map_tag; template < class BaseModel > class Polygonal_schema_base: public BaseModel { public: typedef BaseModel Base; typedef Polygonal_schema_base Self; typedef BaseModel Map; // Either a GMap or a CMap typedef typename Map::Dart_handle Dart_handle; typedef typename Map::Dart_const_handle Dart_const_handle; typedef typename Map::size_type size_type; Polygonal_schema_base() : Base(), mark_perforated(this->get_new_mark()), first_dart(this->null_handle), prev_dart(this->null_handle), facet_started(false) {} /// Start a new facet. void init_facet() { if (facet_started) { std::cerr<<"Polygonal_schema ERROR: " <<"you try to start a facet" <<" but the previous facet is not yet ended."<null_handle; prev_dart = this->null_handle; facet_started=true; } /// Add one edge to the current facet, given by its label /// (any string, using minus sign for orientation) void add_edge_to_facet(const std::string& s) { if (!facet_started) { std::cerr<<"Polygonal_schema ERROR: " <<"you try to add an edge to a facet" <<" but the facet is not yet started."<:: add_edge_to_face(*this, s, prev_dart, dart_same_label, dart_opposite_label, edge_label_to_dart); if (prev_dart==this->null_handle) { first_dart=cur; } prev_dart=cur; } /// add all the given edges to the current facet. /// @param s the sequence of labels of edges to add. void add_edges_to_facet(const std::string& s) { if (!facet_started) { std::cerr<<"Polygonal_schema ERROR: " <<"you try to add edges to a facet" <<" but the facet is not yet started."< l) { if (!facet_started) { std::cerr<<"Polygonal_schema ERROR: " <<"you try to add edges to a facet" <<" but the facet is not yet started."< l) { if (facet_started) { std::cerr<<"Polygonal_schema ERROR: " <<"you try to add a new facet" <<" but the previous facet is not yet ended."<null_handle && prev_dart!=this->null_handle ); this->set_next(prev_dart, first_dart); facet_started=false; return first_dart; } /// @return dart with the given label, Map::null_handle if this dart does not exist. Dart_handle get_dart_labeled(const std::string& s) const { auto ite=edge_label_to_dart.find(s); if (ite==edge_label_to_dart.end()) { return Map::null_handle; } return ite->second; } std::string get_label(Dart_handle dh) const { return internal::Polygonal_schema_tools::get_label(dh); } /// marks the whole facet containing dh as perforated /// @return the number of darts of the marked face size_type perforate_facet(Dart_handle dh) { if (this->is_marked(dh, mark_perforated)) { return 0; } return this->template mark_cell<2>(dh, mark_perforated); } /// same method but using a label size_type perforate_facet(const std::string& s) { auto ite=edge_label_to_dart.find(s); if (ite==edge_label_to_dart.end()) {// maybe there is no need to put an error message std::cerr<<"Polygonal_schema ERROR: " <<"you try to label "<second); } /// unmark the facet as being perforated, now the facet is filled /// @return the number of darts of the unmarked face size_type fill_facet(Dart_handle dh) { if (!this->is_marked(dh, mark_perforated)) { return 0; } return this->template unmark_cell<2>(dh, mark_perforated); } /// same fonciton but using a label size_type fill_facet(const std::string& s) { auto ite=edge_label_to_dart.find(s); if (ite==edge_label_to_dart.end()) {// maybe there is no need to put an error message std::cerr<<"Polygonal_schema ERROR: " <<"you try to label "<second); } /// @return true iff dh is on a perforated facet bool is_perforated(Dart_const_handle dh) const { return this->is_marked(dh, mark_perforated); } /// same thing but using a label instead of a dart bool is_perforated(const std::string& s) const { auto ite=edge_label_to_dart.find(s); if (ite==edge_label_to_dart.end()) {// maybe there is no need to put an error message std::cerr<<"Polygonal_schema ERROR: " <<"you ask if label "<second); } std::size_t get_perforated_mark() const { return mark_perforated; } void display_perforated_darts() const { std::cout<<"labels is_free<2> is_perforated"<first<<" "<(it->second) <<" "<second)< edge_label_to_dart; std::size_t mark_perforated; // mark for perforated facets. // Data members used when we create a facet. Dart_handle first_dart; Dart_handle prev_dart; bool facet_started; }; /// Polygonal schema with combinatorial map. template class Polygonal_schema_with_combinatorial_map: public Polygonal_schema_base, Items_, Alloc_, Storage_> > { public: typedef Polygonal_schema_with_combinatorial_map Self; typedef Combinatorial_map_base<2, Self, Items_, Alloc_, Storage_> CMap_base; typedef Polygonal_schema_base Base; typedef typename Base::Dart_handle Dart_handle; typedef typename Base::Dart_const_handle Dart_const_handle; Polygonal_schema_with_combinatorial_map() : Base() {} Polygonal_schema_with_combinatorial_map(const Self& amap) : Base(amap) {} template Polygonal_schema_with_combinatorial_map(const Combinatorial_map_base & amap) : Base(amap) {} template Polygonal_schema_with_combinatorial_map(const Combinatorial_map_base & amap, const Converters& converters) : Base(amap, converters) {} template Polygonal_schema_with_combinatorial_map(const Combinatorial_map_base & amap, const Converters& converters, const DartInfoConverter& dartinfoconverter) : Base(amap, converters, dartinfoconverter) {} template Polygonal_schema_with_combinatorial_map(const Combinatorial_map_base & amap, const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter) : Base(amap, converters, dartinfoconverter, pointconverter) {} }; /// Polygonal schema with generalized map. template class Polygonal_schema_with_generalized_map: public Polygonal_schema_base, Items_, Alloc_, Storage_> > { public: typedef Polygonal_schema_with_generalized_map Self; typedef Generalized_map_base<2, Self, Items_, Alloc_, Storage_> GMap_base; typedef Polygonal_schema_base Base; typedef typename Base::Dart_handle Dart_handle; typedef typename Base::Dart_const_handle Dart_const_handle; Polygonal_schema_with_generalized_map() : Base() {} Polygonal_schema_with_generalized_map(const Self& amap) : Base(amap) {} template Polygonal_schema_with_generalized_map(const Generalized_map_base & amap) : Base(amap) {} template Polygonal_schema_with_generalized_map(const Generalized_map_base & amap, const Converters& converters) : Base(amap, converters) {} template Polygonal_schema_with_generalized_map(const Generalized_map_base & amap, const Converters& converters, const DartInfoConverter& dartinfoconverter) : Base(amap, converters, dartinfoconverter) {} template Polygonal_schema_with_generalized_map(const Generalized_map_base & amap, const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter) : Base(amap, converters, dartinfoconverter, pointconverter) {} }; /// Generate a random polygonal schema ps. /// @param nb_labels the number of labels used to generate ps. /// @param seed the seed used for random /// @param max_dart_per_face maximal number of darts per face /// @param closed if true generates a closed polygonal schema. /// @param percentage_of_perforated percentage of perforated faces. If 0 /// no perforated faces. template void generate_random_polygonal_schema(PS& ps, std::size_t nb_labels, unsigned int seed =static_cast(std::time(nullptr)), std::size_t max_dart_per_face=30, bool closed=true, std::size_t percentage_of_perforated=20) { CGAL::Random random(seed); std::vector all_labels(nb_labels*2); for (std::size_t i=0; i(i)+1); all_labels[(2*i)+1]=std::to_string(-(static_cast(i)+1)); } std::shuffle(all_labels.begin(), all_labels.end(), std::default_random_engine(seed)); std::size_t endlabel=all_labels.size(); if (!closed) { endlabel-=(all_labels.size()/10); } // We remove 10% of labels. for (std::size_t i=0; i (random.get_int(1, static_cast(max_dart_per_face))); i(rand()%100)