diff --git a/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h b/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h index 331f8a0f44b..4952f5f0a5f 100644 --- a/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h +++ b/BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h @@ -102,6 +102,9 @@ public: // Construct the graph VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(CGAL::vertex_point, g)); + // Default constructors should only be used when VNM, VCM, etc. are defined as Constant_property_maps + // This fails in cases where get_parameter() succeeds + // even though internal_np::Lookup_named_param_def defaulted to Constant_property_map VNM vnm = choose_parameter(get_parameter(np, internal_np::vertex_normal_map), VNM()); VCM vcm = choose_parameter(get_parameter(np, internal_np::vertex_color_map), VCM()); VTM vtm = choose_parameter(get_parameter(np, internal_np::vertex_texture_map), VTM()); diff --git a/Property_map/include/CGAL/Properties.h b/Property_map/include/CGAL/Properties.h index 20d449fb741..445ebfcbd5d 100644 --- a/Property_map/include/CGAL/Properties.h +++ b/Property_map/include/CGAL/Properties.h @@ -277,9 +277,9 @@ public: array->reserve(n); } - std::size_t size() const { return std::count(m_active_indices.begin(), m_active_indices.end(), true); } + [[nodiscard]] std::size_t size() const { return std::count(m_active_indices.begin(), m_active_indices.end(), true); } - std::size_t capacity() const { return m_active_indices.size(); } + [[nodiscard]] std::size_t capacity() const { return m_active_indices.size(); } Index emplace_back() { @@ -378,6 +378,20 @@ public: return m_active_indices[i] = true; } + std::vector active_list() const { + std::vector indices; + for (std::size_t i = 0; i < m_active_indices.size(); ++i) + if (m_active_indices[i]) indices.emplace_back(i); + return indices; + } + + std::vector inactive_list() const { + std::vector indices; + for (std::size_t i = 0; i < m_active_indices.size(); ++i) + if (!m_active_indices[i]) indices.emplace_back(i); + return indices; + } + /*! * Adds the elements of the other container to this container for each property which is present in this container. * diff --git a/Property_map/test/Property_map/test_Properties.cpp b/Property_map/test/Property_map/test_Properties.cpp index 2d7fd5c7c8d..af1b4ca2cf4 100644 --- a/Property_map/test/Property_map/test_Properties.cpp +++ b/Property_map/test/Property_map/test_Properties.cpp @@ -86,6 +86,8 @@ void test_element_access() { properties.erase(1); assert(properties.size() == 2); assert(properties.capacity() == 100); + assert(properties.active_list().size() == 2); + assert(properties.inactive_list().size() == 98); // A newly emplaced element should take the empty slot assert(properties.emplace() == 1); diff --git a/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h b/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h index fced570172d..0ebeba94af6 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/IO/OFF.h @@ -108,24 +108,11 @@ bool read_OFF_with_or_without_fcolors(std::istream& is, using parameters::is_default_parameter; using parameters::get_parameter; - typename Mesh::template Property_map fcm; - bool is_fcm_requested = !(is_default_parameter::value); - if(!is_fcm_requested && scanner.has_colors()) - { - bool created; - std::tie(fcm, created) = sm.template add_property_map("f:color", Color(0,0,0)); - CGAL_assertion(created); - is_fcm_requested = true; - } - - if(is_fcm_requested) - { - FCM fcolors = choose_parameter(get_parameter(np, internal_np::face_color_map), fcm); - return CGAL::IO::internal::read_OFF_BGL(is, sm, np.face_color_map(fcolors)); - } - else - { + if (is_fcm_requested || scanner.has_colors()) { + auto [fcm, created] = sm.template property_map("f:color"); + return CGAL::IO::internal::read_OFF_BGL(is, sm, np.face_color_map(fcm)); + } else { return CGAL::IO::internal::read_OFF_BGL(is, sm, np); } } @@ -147,24 +134,11 @@ bool read_OFF_with_or_without_vtextures(std::istream& is, using parameters::is_default_parameter; using parameters::get_parameter; - typename Mesh::template Property_map vtm; - bool is_vtm_requested = !(is_default_parameter::value); - if(!is_vtm_requested && scanner.has_textures()) - { - bool created; - std::tie(vtm, created) = sm.template add_property_map("v:texcoord"); - CGAL_assertion(created); - is_vtm_requested = true; - } - - if(is_vtm_requested) - { - VTM vtextures = choose_parameter(get_parameter(np, internal_np::vertex_texture_map), vtm); - return read_OFF_with_or_without_fcolors(is, sm, scanner, np.vertex_texture_map(vtextures)); - } - else - { + if (is_vtm_requested || scanner.has_textures()) { + auto [vtm, created] = sm.template property_map("v:texcoord"); + return read_OFF_with_or_without_fcolors(is, sm, scanner, np.vertex_texture_map(vtm)); + } else { return read_OFF_with_or_without_fcolors(is, sm, scanner, np); } } @@ -185,24 +159,11 @@ bool read_OFF_with_or_without_vcolors(std::istream& is, using parameters::is_default_parameter; using parameters::get_parameter; - typename Mesh::template Property_map vcm; - - bool is_vcm_requested = !(is_default_parameter::value); - if(!is_vcm_requested && scanner.has_colors()) - { - bool created; - std::tie(vcm, created) = sm.template add_property_map("v:color", Color(0,0,0)); - CGAL_assertion(created); - is_vcm_requested = true; - } - - if(is_vcm_requested) - { - VCM vcolors = choose_parameter(get_parameter(np, internal_np::vertex_color_map), vcm); - return read_OFF_with_or_without_vtextures(is, sm, scanner, np.vertex_color_map(vcolors)); - } - else - { + bool is_vcm_requested = !(is_default_parameter::value); + if (is_vcm_requested || scanner.has_colors()) { + auto [vcm, created] = sm.template property_map("v:color"); + return read_OFF_with_or_without_vtextures(is, sm, scanner, np.vertex_color_map(vcm)); + } else { return read_OFF_with_or_without_vtextures(is, sm, scanner, np); } } @@ -224,24 +185,11 @@ bool read_OFF_with_or_without_vnormals(std::istream& is, using parameters::is_default_parameter; using parameters::get_parameter; - typename Mesh::template Property_map vnm; - bool is_vnm_requested = !(is_default_parameter::value); - if(!is_vnm_requested && scanner.has_normals()) - { - bool created; - std::tie(vnm, created) = sm.template add_property_map("v:normal"); - CGAL_assertion(created); - is_vnm_requested = true; - } - - if(is_vnm_requested) - { - VNM vnormals = choose_parameter(get_parameter(np, internal_np::vertex_normal_map), vnm); - return read_OFF_with_or_without_vcolors(is, sm, scanner, np.vertex_normal_map(vnormals)); - } - else - { + if (is_vnm_requested || scanner.has_normals()) { + auto [vnm, created] = sm.template property_map("v:normal"); + return read_OFF_with_or_without_vcolors(is, sm, scanner, np.vertex_normal_map(vnm)); + } else { return read_OFF_with_or_without_vcolors(is, sm, scanner, np); } } diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index 47232cbabd5..5a45933e06b 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -239,7 +239,7 @@ namespace CGAL { class SM_Edge_index { public: - typedef boost::uint32_t size_type; + typedef std::size_t size_type; SM_Edge_index() : halfedge_((std::numeric_limits::max)()) { } @@ -341,334 +341,319 @@ class Surface_mesh public: #ifndef DOXYGEN_RUNNING - template - struct Property_map : Properties::Property_map_base > - { - typedef Properties::Property_map_base > Base; - typedef typename Base::reference reference; - Property_map() = default; - Property_map(const Base& pm): Base(pm) {} - }; - template - struct Get_property_map { - typedef Property_map type; - }; + template + using Property_container = Properties::Property_container; + + template + using Property_array = Properties::Property_array; + + template + using Property_map = Properties::Property_array_handle; + #endif // DOXYGEN_RUNNING - /// \name Basic Types - /// - ///@{ + /// \name Basic Types + /// + ///@{ - /// The point type. - typedef P Point; + /// The point type. + typedef P Point; - /// The type used to represent an index. - typedef boost::uint32_t size_type; + /// The type used to represent an index. + typedef boost::uint32_t size_type; - ///@} + ///@} - /// \name Basic Elements - /// - ///@{ + /// \name Basic Elements + /// + ///@{ #ifdef DOXYGEN_RUNNING - /// This class represents a vertex. - /// \cgalModels `Index` - /// \cgalModels `LessThanComparable` - /// \cgalModels `Hashable` - /// \sa `Halfedge_index`, `Edge_index`, `Face_index` - class Vertex_index - { - public: - /// %Default constructor. - Vertex_index(){} + /// This class represents a vertex. + /// \cgalModels `Index` + /// \cgalModels `LessThanComparable` + /// \cgalModels `Hashable` + /// \sa `Halfedge_index`, `Edge_index`, `Face_index` + class Vertex_index + { + public: + /// %Default constructor. + Vertex_index(){} - Vertex_index(size_type _idx){} + Vertex_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v) + {} + }; #else typedef SM_Vertex_index Vertex_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents a halfedge. - /// \cgalModels `Index` - /// \cgalModels `LessThanComparable` - /// \cgalModels `Hashable` - /// \sa `Vertex_index`, `Edge_index`, `Face_index` - class Halfedge_index - { - public: - /// %Default constructor - Halfedge_index(){} + /// This class represents a halfedge. + /// \cgalModels `Index` + /// \cgalModels `LessThanComparable` + /// \cgalModels `Hashable` + /// \sa `Vertex_index`, `Edge_index`, `Face_index` + class Halfedge_index + { + public: + /// %Default constructor + Halfedge_index(){} - Halfedge_index(size_type _idx){} + Halfedge_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h) - { - } + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h) + { + } - }; + }; #else typedef SM_Halfedge_index Halfedge_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents a face - /// \cgalModels `Index` - /// \cgalModels `LessThanComparable` - /// \cgalModels `Hashable` - /// \sa `Vertex_index`, `Halfedge_index`, `Edge_index` - class Face_index - { - public: - /// %Default constructor - Face_index(){} + /// This class represents a face + /// \cgalModels `Index` + /// \cgalModels `LessThanComparable` + /// \cgalModels `Hashable` + /// \sa `Vertex_index`, `Halfedge_index`, `Edge_index` + class Face_index + { + public: + /// %Default constructor + Face_index(){} - Face_index(size_type _idx){} + Face_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f) + {} + }; #else typedef SM_Face_index Face_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents an edge. - /// \cgalModels `Index` - /// \cgalModels `LessThanComparable` - /// \cgalModels `Hashable` - /// \sa `Vertex_index`, `Halfedge_index`, `Face_index` - class Edge_index - { - public: - /// %Default constructor - Edge_index(){} + /// This class represents an edge. + /// \cgalModels `Index` + /// \cgalModels `LessThanComparable` + /// \cgalModels `Hashable` + /// \sa `Vertex_index`, `Halfedge_index`, `Face_index` + class Edge_index + { + public: + /// %Default constructor + Edge_index(){} - Edge_index(size_type idx){} + Edge_index(size_type idx){} - /// constructs an `Edge_index` from a halfedge. - Edge_index(Halfedge_index he){} + /// constructs an `Edge_index` from a halfedge. + Edge_index(Halfedge_index he){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Edge_index const& e) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Edge_index const& e) + {} + }; #else typedef SM_Edge_index Edge_index; #endif - ///@} + ///@} #ifndef CGAL_TEST_SURFACE_MESH private: //-------------------------------------------------- connectivity types #endif - /// This type stores the vertex connectivity - /// \sa `Halfedge_connectivity`, `Face_connectivity` - struct Vertex_connectivity - { - /// an incoming halfedge per vertex (it will be a border halfedge for border vertices) - Halfedge_index halfedge_; - }; + /// This type stores the vertex connectivity + /// \sa `Halfedge_connectivity`, `Face_connectivity` + struct Vertex_connectivity { + /// an incoming halfedge per vertex (it will be a border halfedge for border vertices) + Halfedge_index halfedge_; + }; - /// This type stores the halfedge connectivity - /// \sa `Vertex_connectivity`, `Face_connectivity` - struct Halfedge_connectivity - { - /// face incident to halfedge - Face_index face_; - /// vertex the halfedge points to - Vertex_index vertex_; - /// next halfedge within a face (or along a border) - Halfedge_index next_halfedge_; - /// previous halfedge within a face (or along a border) - Halfedge_index prev_halfedge_; - }; + /// This type stores the halfedge connectivity + /// \sa `Vertex_connectivity`, `Face_connectivity` + struct Halfedge_connectivity { + /// face incident to halfedge + Face_index face_; + /// vertex the halfedge points to + Vertex_index vertex_; + /// next halfedge within a face (or along a border) + Halfedge_index next_halfedge_; + /// previous halfedge within a face (or along a border) + Halfedge_index prev_halfedge_; + }; - /// This type stores the face connectivity - /// \sa `Vertex_connectivity`, `Halfedge_connectivity` - struct Face_connectivity - { - /// a halfedge that is part of the face - Halfedge_index halfedge_; - }; + /// This type stores the face connectivity + /// \sa `Vertex_connectivity`, `Halfedge_connectivity` + struct Face_connectivity { + /// a halfedge that is part of the face + Halfedge_index halfedge_; + }; private: //------------------------------------------------------ iterator types - template - class Index_iterator - : public boost::iterator_facade< Index_iterator, - Index_, - std::random_access_iterator_tag, - Index_ - > - { - typedef boost::iterator_facade< Index_iterator, - Index_, - std::random_access_iterator_tag, - Index_> Facade; - public: - Index_iterator() : hnd_(), mesh_(nullptr) {} - Index_iterator(const Index_& h, const Surface_mesh* m) - : hnd_(h), mesh_(m) { - if (mesh_ && mesh_->has_garbage()){ - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; + template + class Index_iterator + : public boost::iterator_facade, + Index_, + std::random_access_iterator_tag, + Index_ + > { + typedef boost::iterator_facade, + Index_, + std::random_access_iterator_tag, + Index_> Facade; + public: + Index_iterator() : hnd_(), mesh_(nullptr) {} + + Index_iterator(const Index_& h, const Surface_mesh* m) + : hnd_(h), mesh_(m) { + if (mesh_ && mesh_->has_garbage()) { + while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; + } + } + + private: + friend class boost::iterator_core_access; + + void increment() { + ++hnd_; + CGAL_assertion(mesh_ != nullptr); + + if (mesh_->has_garbage()) + while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; + } + + void decrement() { + --hnd_; + CGAL_assertion(mesh_ != nullptr); + if (mesh_->has_garbage()) + while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_; + } + + void advance(std::ptrdiff_t n) { + CGAL_assertion(mesh_ != nullptr); + + if (mesh_->has_garbage()) { + if (n > 0) + for (std::ptrdiff_t i = 0; i < n; ++i) + increment(); + else + for (std::ptrdiff_t i = 0; i < -n; ++i) + decrement(); + } else + hnd_ += n; + } + + std::ptrdiff_t distance_to(const Index_iterator& other) const { + if (mesh_->has_garbage()) { + bool forward = (other.hnd_ > hnd_); + + std::ptrdiff_t out = 0; + Index_iterator it = *this; + while (!it.equal(other)) { + if (forward) { + ++it; + ++out; + } else { + --it; + --out; } } - private: - friend class boost::iterator_core_access; - void increment() - { - ++hnd_; - CGAL_assertion(mesh_ != nullptr); + return out; + } - if(mesh_->has_garbage()) - while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; - } + // else + return std::ptrdiff_t(other.hnd_) - std::ptrdiff_t(this->hnd_); + } - void decrement() - { - --hnd_; - CGAL_assertion(mesh_ != nullptr); - if(mesh_->has_garbage()) - while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_; - } + bool equal(const Index_iterator& other) const { + return this->hnd_ == other.hnd_; + } - void advance(std::ptrdiff_t n) - { - CGAL_assertion(mesh_ != nullptr); + Index_ dereference() const { return hnd_; } - if (mesh_->has_garbage()) - { - if (n > 0) - for (std::ptrdiff_t i = 0; i < n; ++ i) - increment(); - else - for (std::ptrdiff_t i = 0; i < -n; ++ i) - decrement(); - } - else - hnd_ += n; - } + Index_ hnd_; + const Surface_mesh* mesh_; - std::ptrdiff_t distance_to(const Index_iterator& other) const - { - if (mesh_->has_garbage()) - { - bool forward = (other.hnd_ > hnd_); + }; - std::ptrdiff_t out = 0; - Index_iterator it = *this; - while (!it.equal(other)) - { - if (forward) - { - ++ it; - ++ out; - } - else - { - -- it; - -- out; - } - } - return out; - } - - // else - return std::ptrdiff_t(other.hnd_) - std::ptrdiff_t(this->hnd_); - } - - bool equal(const Index_iterator& other) const - { - return this->hnd_ == other.hnd_; - } - - Index_ dereference() const { return hnd_; } - - Index_ hnd_; - const Surface_mesh* mesh_; - - }; public: - /// \name Range Types - /// - /// Each range `R` in this section has a nested type `R::iterator`, - /// is convertible to `std::pair`, so that one can use `boost::tie()`, - /// and can be used with `BOOST_FOREACH()`, as well as with the C++11 range based for-loop. + /// \name Range Types + /// + /// Each range `R` in this section has a nested type `R::iterator`, + /// is convertible to `std::pair`, so that one can use `boost::tie()`, + /// and can be used with `BOOST_FOREACH()`, as well as with the C++11 range based for-loop. - ///@{ + ///@{ #ifndef DOXYGEN_RUNNING - typedef Index_iterator Vertex_iterator; + typedef Index_iterator Vertex_iterator; #endif - /// \brief The range over all vertex indices. - /// - /// A model of BidirectionalRange with value type `Vertex_index`. - /// \sa `vertices()` - /// \sa `Halfedge_range`, `Edge_range`, `Face_range` + /// \brief The range over all vertex indices. + /// + /// A model of BidirectionalRange with value type `Vertex_index`. + /// \sa `vertices()` + /// \sa `Halfedge_range`, `Edge_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Vertex_range; + typedef unspecified_type Vertex_range; #else - typedef Iterator_range Vertex_range; + typedef Iterator_range Vertex_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Halfedge_iterator; + typedef Index_iterator Halfedge_iterator; #endif - /// \brief The range over all halfedge indices. - /// - /// A model of BidirectionalRange with value type `Halfedge_index`. - /// \sa `halfedges()` - /// \sa `Vertex_range`, `Edge_range`, `Face_range` + /// \brief The range over all halfedge indices. + /// + /// A model of BidirectionalRange with value type `Halfedge_index`. + /// \sa `halfedges()` + /// \sa `Vertex_range`, `Edge_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Halfedge_range; + typedef unspecified_type Halfedge_range; #else - typedef Iterator_range Halfedge_range; + typedef Iterator_range Halfedge_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Edge_iterator; + typedef Index_iterator Edge_iterator; #endif - /// \brief The range over all edge indices. - /// - /// A model of BidirectionalRange with value type `Edge_index`. - /// \sa `edges()` - /// \sa `Halfedge_range`, `Vertex_range`, `Face_range` + /// \brief The range over all edge indices. + /// + /// A model of BidirectionalRange with value type `Edge_index`. + /// \sa `edges()` + /// \sa `Halfedge_range`, `Vertex_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Edge_range; + typedef unspecified_type Edge_range; #else - typedef Iterator_range Edge_range; + typedef Iterator_range Edge_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Face_iterator; + typedef Index_iterator Face_iterator; #endif - /// \brief The range over all face indices. - /// - /// A model of BidirectionalRange with value type `Face_index`. - /// \sa `faces()` - /// \sa `Vertex_range`, `Halfedge_range`, `Edge_range` - #ifdef DOXYGEN_RUNNING - typedef unspecified_type Face_range; + /// \brief The range over all face indices. + /// + /// A model of BidirectionalRange with value type `Face_index`. + /// \sa `faces()` + /// \sa `Vertex_range`, `Halfedge_range`, `Edge_range` +#ifdef DOXYGEN_RUNNING + typedef unspecified_type Face_range; #else - typedef Iterator_range Face_range; + typedef Iterator_range Face_range; #endif #ifndef DOXYGEN_RUNNING @@ -676,229 +661,215 @@ public: typedef CGAL::Vertex_around_target_iterator Vertex_around_target_iterator; typedef Iterator_range Vertex_around_target_range; - typedef CGAL::Halfedge_around_target_iterator Halfedge_around_target_iterator; + typedef CGAL::Halfedge_around_target_iterator Halfedge_around_target_iterator; typedef Iterator_range Halfedge_around_target_range; - typedef CGAL::Face_around_target_iterator Face_around_target_iterator; + typedef CGAL::Face_around_target_iterator Face_around_target_iterator; typedef Iterator_range Face_around_target_range; - typedef CGAL::Vertex_around_face_iterator Vertex_around_face_iterator; + typedef CGAL::Vertex_around_face_iterator Vertex_around_face_iterator; typedef Iterator_range Vertex_around_face_range; - typedef CGAL::Halfedge_around_face_iterator Halfedge_around_face_iterator; + typedef CGAL::Halfedge_around_face_iterator Halfedge_around_face_iterator; typedef Iterator_range Halfedge_around_face_range; - typedef CGAL::Face_around_face_iterator Face_around_face_iterator; + typedef CGAL::Face_around_face_iterator Face_around_face_iterator; typedef Iterator_range Face_around_face_range; #endif - /// @cond CGAL_BEGIN_END - /// Start iterator for vertices. - Vertex_iterator vertices_begin() const - { - return Vertex_iterator(Vertex_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for vertices. + Vertex_iterator vertices_begin() const { + return Vertex_iterator(Vertex_index(0), this); + } - /// End iterator for vertices. - Vertex_iterator vertices_end() const - { - return Vertex_iterator(Vertex_index(num_vertices()), this); - } - /// @endcond + /// End iterator for vertices. + Vertex_iterator vertices_end() const { + return Vertex_iterator(Vertex_index(number_of_vertices()), this); + } + /// @endcond - /// returns the iterator range of the vertices of the mesh. - Vertex_range vertices() const { - return make_range(vertices_begin(), vertices_end()); - } + /// returns the iterator range of the vertices of the mesh. + Vertex_range vertices() const { + return make_range(vertices_begin(), vertices_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for halfedges. - Halfedge_iterator halfedges_begin() const - { - return Halfedge_iterator(Halfedge_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for halfedges. + Halfedge_iterator halfedges_begin() const { + return Halfedge_iterator(Halfedge_index(0), this); + } - /// End iterator for halfedges. - Halfedge_iterator halfedges_end() const - { - return Halfedge_iterator(Halfedge_index(num_halfedges()), this); - } - /// @endcond + /// End iterator for halfedges. + Halfedge_iterator halfedges_end() const { + return Halfedge_iterator(Halfedge_index(number_of_halfedges()), this); + } + /// @endcond - /// returns the iterator range of the halfedges of the mesh. - Halfedge_range halfedges() const { - return make_range(halfedges_begin(), halfedges_end()); - } + /// returns the iterator range of the halfedges of the mesh. + Halfedge_range halfedges() const { + return make_range(halfedges_begin(), halfedges_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for edges. - Edge_iterator edges_begin() const - { - return Edge_iterator(Edge_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for edges. + Edge_iterator edges_begin() const { + return Edge_iterator(Edge_index(0), this); + } - /// End iterator for edges. - Edge_iterator edges_end() const - { - return Edge_iterator(Edge_index(num_edges()), this); - } - /// @endcond + /// End iterator for edges. + Edge_iterator edges_end() const { + return Edge_iterator(Edge_index(number_of_edges()), this); + } + /// @endcond - /// returns the iterator range of the edges of the mesh. - Edge_range edges() const - { - return make_range(edges_begin(), edges_end()); - } + /// returns the iterator range of the edges of the mesh. + Edge_range edges() const { + return make_range(edges_begin(), edges_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for faces. - Face_iterator faces_begin() const - { - return Face_iterator(Face_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for faces. + Face_iterator faces_begin() const { + return Face_iterator(Face_index(0), this); + } - /// End iterator for faces. - Face_iterator faces_end() const - { - return Face_iterator(Face_index(num_faces()), this); - } - /// @endcond + /// End iterator for faces. + Face_iterator faces_end() const { + return Face_iterator(Face_index(number_of_faces()), this); + } + /// @endcond - /// returns the iterator range of the faces of the mesh. - Face_range faces() const { - return make_range(faces_begin(), faces_end()); - } + /// returns the iterator range of the faces of the mesh. + Face_range faces() const { + return make_range(faces_begin(), faces_end()); + } #ifndef DOXYGEN_RUNNING - /// returns the iterator range for vertices around vertex `target(h)`, starting at `source(h)`. - Vertex_around_target_range vertices_around_target(Halfedge_index h) const - { - return CGAL::vertices_around_target(h,*this); - } - /// returns the iterator range for incoming halfedges around vertex `target(h)`, starting at `h`. - Halfedge_around_target_range halfedges_around_target(Halfedge_index h) const - { - return CGAL::halfedges_around_target(h,*this); - } + /// returns the iterator range for vertices around vertex `target(h)`, starting at `source(h)`. + Vertex_around_target_range vertices_around_target(Halfedge_index h) const { + return CGAL::vertices_around_target(h, *this); + } - /// returns the iterator range for faces around vertex `target(h)`, starting at `face(h)`. - Face_around_target_range faces_around_target(Halfedge_index h) const - { - return CGAL::faces_around_target(h,*this); - } + /// returns the iterator range for incoming halfedges around vertex `target(h)`, starting at `h`. + Halfedge_around_target_range halfedges_around_target(Halfedge_index h) const { + return CGAL::halfedges_around_target(h, *this); + } - /// returns the iterator range for vertices around face `face(h)`, starting at `target(h)`. - Vertex_around_face_range vertices_around_face(Halfedge_index h) const - { - return CGAL::vertices_around_face(h,*this); - } + /// returns the iterator range for faces around vertex `target(h)`, starting at `face(h)`. + Face_around_target_range faces_around_target(Halfedge_index h) const { + return CGAL::faces_around_target(h, *this); + } - /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. - Halfedge_around_face_range halfedges_around_face(Halfedge_index h) const - { - return CGAL::halfedges_around_face(h,*this); - } + /// returns the iterator range for vertices around face `face(h)`, starting at `target(h)`. + Vertex_around_face_range vertices_around_face(Halfedge_index h) const { + return CGAL::vertices_around_face(h, *this); + } - /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. - Face_around_face_range faces_around_face(Halfedge_index h) const - { - return CGAL::faces_around_face(h,*this); - } + /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. + Halfedge_around_face_range halfedges_around_face(Halfedge_index h) const { + return CGAL::halfedges_around_face(h, *this); + } + + /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. + Face_around_face_range faces_around_face(Halfedge_index h) const { + return CGAL::faces_around_face(h, *this); + } #endif - ///@} + ///@} public: #ifndef DOXYGEN_RUNNING - /// \name Circulator Types - /// - /// The following circulators enable to iterate through the elements around a face or vertex. - /// As explained in the \ref SurfaceMeshOrientation "User Manual", we can speak of a - /// *clockwise* or *counterclockwise* - /// traversal, by looking at the surface from the right side. - ///@{ + /// \name Circulator Types + /// + /// The following circulators enable to iterate through the elements around a face or vertex. + /// As explained in the \ref SurfaceMeshOrientation "User Manual", we can speak of a + /// *clockwise* or *counterclockwise* + /// traversal, by looking at the surface from the right side. + ///@{ - /// \brief This class circulates clockwise through all - /// one-ring neighbors of a vertex. - /// A model of `BidirectionalCirculator` with value type `Vertex_index`. - /// \sa `Halfedge_around_target_circulator`, `Face_around_target_circulator` + /// \brief This class circulates clockwise through all + /// one-ring neighbors of a vertex. + /// A model of `BidirectionalCirculator` with value type `Vertex_index`. + /// \sa `Halfedge_around_target_circulator`, `Face_around_target_circulator` typedef CGAL::Vertex_around_target_circulator Vertex_around_target_circulator; - /// \brief This class circulates clockwise through all incident faces of a vertex. - /// A model of `BidirectionalCirculator` with value type `Face_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all incident faces of a vertex. + /// A model of `BidirectionalCirculator` with value type `Face_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Face_around_target_circulator Face_around_target_circulator; - /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as target. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as target. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Halfedge_around_target_circulator Halfedge_around_target_circulator; - /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as source. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as source. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Halfedge_around_source_circulator Halfedge_around_source_circulator; - /// \brief This class circulates counterclockwise through all vertices around a face. - /// A model of `BidirectionalCirculator` with value type `Vertex_index`. + /// \brief This class circulates counterclockwise through all vertices around a face. + /// A model of `BidirectionalCirculator` with value type `Vertex_index`. - typedef CGAL::Vertex_around_face_circulator Vertex_around_face_circulator; + typedef CGAL::Vertex_around_face_circulator Vertex_around_face_circulator; - /// \brief This class circulates counterclockwise through all halfedges around a face. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \brief This class circulates counterclockwise through all halfedges around a face. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - typedef CGAL::Halfedge_around_face_circulator Halfedge_around_face_circulator; + typedef CGAL::Halfedge_around_face_circulator Halfedge_around_face_circulator; - /// \brief This class circulates counterclockwise through all faces around a face. - /// A model of `BidirectionalCirculator` with value type `Face_index`. - /// Note that the face index is the same after `operator++`, if the neighboring faces share - /// several halfedges. + /// \brief This class circulates counterclockwise through all faces around a face. + /// A model of `BidirectionalCirculator` with value type `Face_index`. + /// Note that the face index is the same after `operator++`, if the neighboring faces share + /// several halfedges. - typedef CGAL::Face_around_face_circulator Face_around_face_circulator; + typedef CGAL::Face_around_face_circulator Face_around_face_circulator; /// @} #endif /// @cond CGAL_DOCUMENT_INTERNALS // typedefs which make it easier to write the partial specialisation of boost::graph_traits - typedef Vertex_index vertex_index; - typedef P vertex_property_type; + typedef Vertex_index vertex_index; + typedef P vertex_property_type; typedef Halfedge_index halfedge_index; - typedef Edge_index edge_index; - typedef Face_index face_index; + typedef Edge_index edge_index; + typedef Face_index face_index; - typedef Vertex_iterator vertex_iterator; - typedef Halfedge_iterator halfedge_iterator; - typedef Edge_iterator edge_iterator; - typedef Face_iterator face_iterator; - typedef CGAL::Out_edge_iterator out_edge_iterator; + typedef Vertex_iterator vertex_iterator; + typedef Halfedge_iterator halfedge_iterator; + typedef Edge_iterator edge_iterator; + typedef Face_iterator face_iterator; + typedef CGAL::Out_edge_iterator out_edge_iterator; - typedef boost::undirected_tag directed_category; + typedef boost::undirected_tag directed_category; typedef boost::disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : public virtual boost::bidirectional_graph_tag, public virtual boost::vertex_list_graph_tag, - public virtual boost::edge_list_graph_tag - {}; + public virtual boost::edge_list_graph_tag { + }; typedef size_type vertices_size_type; typedef size_type halfedges_size_type; @@ -906,1153 +877,936 @@ public: typedef size_type faces_size_type; typedef size_type degree_size_type; - /// @endcond + /// @endcond public: - /// \name Construction, Destruction, Assignment - /// - /// Copy constructors as well as assignment do also copy simplices marked as removed. - ///@{ + /// \name Construction, Destruction, Assignment + /// + /// Copy constructors as well as assignment do also copy simplices marked as removed. + ///@{ - /// %Default constructor. - Surface_mesh(); + /// %Default constructor. + Surface_mesh() : + vconn_(vprops_.add_property("v:connectivity")), + hconn_(hprops_.add_property("h:connectivity")), + fconn_(fprops_.add_property("f:connectivity")), + vpoint_(vprops_.add_property("v:point")), + // todo: the following shouldn't be necessary + vremoved_(vprops_.add_property("v:removed", false)), + eremoved_(eprops_.add_property("e:removed", false)), + fremoved_(fprops_.add_property("f:removed", false)), + removed_vertices_(0), removed_edges_(0), removed_faces_(0), + garbage_(false), + anonymous_property_(0) {} - /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. - Surface_mesh(const Surface_mesh& rhs) { *this = rhs; } + /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. + Surface_mesh(const Surface_mesh& rhs) : + vprops_(rhs.vprops_), + hprops_(rhs.hprops_), + fprops_(rhs.fprops_), + eprops_(rhs.eprops_), + vconn_(vprops_.get_property("v:connectivity")), + vpoint_(vprops_.get_property("v:point")), + hconn_(hprops_.get_property("h:connectivity")), + fconn_(fprops_.get_property("f:connectivity")), + // todo: the following shouldn't be necessary + vremoved_(vprops_.get_property("v:removed")), + eremoved_(eprops_.get_property("e:removed")), + fremoved_(fprops_.get_property("f:removed")), + removed_vertices_(0), removed_edges_(0), removed_faces_(0), + garbage_(false), + anonymous_property_(0) {} - /// Move constructor. - Surface_mesh(Surface_mesh&& sm) - : vprops_(std::move(sm.vprops_)) - , hprops_(std::move(sm.hprops_)) - , eprops_(std::move(sm.eprops_)) - , fprops_(std::move(sm.fprops_)) - , vconn_(std::move(sm.vconn_)) - , hconn_(std::move(sm.hconn_)) - , fconn_(std::move(sm.fconn_)) - , vremoved_(std::move(sm.vremoved_)) - , eremoved_(std::move(sm.eremoved_)) - , fremoved_(std::move(sm.fremoved_)) - , vpoint_(std::move(sm.vpoint_)) - , removed_vertices_(std::exchange(sm.removed_vertices_, 0)) - , removed_edges_(std::exchange(sm.removed_edges_, 0)) - , removed_faces_(std::exchange(sm.removed_faces_, 0)) - , vertices_freelist_(std::exchange(sm.vertices_freelist_,(std::numeric_limits::max)())) - , edges_freelist_(std::exchange(sm.edges_freelist_,(std::numeric_limits::max)())) - , faces_freelist_(std::exchange(sm.faces_freelist_,(std::numeric_limits::max)())) - , garbage_(std::exchange(sm.garbage_, false)) - , recycle_(std::exchange(sm.recycle_, true)) - , anonymous_property_(std::exchange(sm.anonymous_property_, 0)) - {} + /// Move constructor. + Surface_mesh(Surface_mesh&& sm) : + vprops_(std::move(sm.vprops_)), + hprops_(std::move(sm.hprops_)), + eprops_(std::move(sm.eprops_)), + fprops_(std::move(sm.fprops_)), + vconn_(vprops_.get_property("v:connectivity")), + vpoint_(vprops_.get_property("v:point")), + hconn_(hprops_.get_property("h:connectivity")), + fconn_(fprops_.get_property("f:connectivity")), + // todo: the following shouldn't be necessary + vremoved_(vprops_.get_property("v:removed")), + eremoved_(eprops_.get_property("e:removed")), + fremoved_(fprops_.get_property("f:removed")), + removed_vertices_(0), removed_edges_(0), removed_faces_(0), + garbage_(false), + anonymous_property_(0) {} - /// assigns `rhs` to `*this`. Performs a deep copy of all properties. - Surface_mesh& operator=(const Surface_mesh& rhs); + /// assigns `rhs` to `*this`. Performs a deep copy of all properties. + Surface_mesh& operator=(const Surface_mesh& rhs); - /// move assignment - Surface_mesh& operator=(Surface_mesh&& sm) - { - vprops_ = std::move(sm.vprops_); - hprops_ = std::move(sm.hprops_); - eprops_ = std::move(sm.eprops_); - fprops_ = std::move(sm.fprops_); - vconn_ = std::move(sm.vconn_); - hconn_ = std::move(sm.hconn_); - fconn_ = std::move(sm.fconn_); - vremoved_ = std::move(sm.vremoved_); - eremoved_ = std::move(sm.eremoved_); - fremoved_ = std::move(sm.fremoved_); - vpoint_ = std::move(sm.vpoint_); - removed_vertices_ = std::exchange(sm.removed_vertices_, 0); - removed_edges_ = std::exchange(sm.removed_edges_, 0); - removed_faces_ = std::exchange(sm.removed_faces_, 0); - vertices_freelist_ = std::exchange(sm.vertices_freelist_, (std::numeric_limits::max)()); - edges_freelist_ = std::exchange(sm.edges_freelist_,(std::numeric_limits::max)()); - faces_freelist_ = std::exchange(sm.faces_freelist_,(std::numeric_limits::max)()); - garbage_ = std::exchange(sm.garbage_, false); - recycle_ = std::exchange(sm.recycle_, true); - anonymous_property_ = std::exchange(sm.anonymous_property_, 0); - return *this; - } + /// move assignment + Surface_mesh& operator=(Surface_mesh&& sm) { + vprops_ = std::move(sm.vprops_); + hprops_ = std::move(sm.hprops_); + eprops_ = std::move(sm.eprops_); + fprops_ = std::move(sm.fprops_); + return *this; + } - /// assigns `rhs` to `*this`. Does not copy custom properties. - Surface_mesh& assign(const Surface_mesh& rhs); + /// assigns `rhs` to `*this`. Does not copy custom properties. + //Surface_mesh& assign(const Surface_mesh& rhs); - ///@} + ///@} public: - /// \name Adding Vertices, Edges, and Faces - ///@{ + /// \name Adding Vertices, Edges, and Faces + ///@{ - /// adds a new vertex, and resizes vertex properties if necessary. - Vertex_index add_vertex() - { - size_type inf = (std::numeric_limits::max)(); - if(recycle_ && (vertices_freelist_ != inf)){ - size_type idx = vertices_freelist_; - vertices_freelist_ = (size_type)vconn_[Vertex_index(vertices_freelist_)].halfedge_; - --removed_vertices_; - vremoved_[Vertex_index(idx)] = false; - vprops_.reset(Vertex_index(idx)); - return Vertex_index(idx); - } else { - vprops_.push_back(); - return Vertex_index(num_vertices()-1); - } - } - - /// adds a new vertex, resizes vertex properties if necessary, - /// and sets the \em point property to `p`. - /// \note Several vertices may have the same point property. - Vertex_index add_vertex(const Point& p) - { - Vertex_index v = add_vertex(); - vpoint_[v] = p; - return v; - } + /// adds a new vertex, and resizes vertex properties if necessary. + Vertex_index add_vertex() { + return vprops_.emplace(); + } + /// adds a new vertex, resizes vertex properties if necessary, + /// and sets the \em point property to `p`. + /// \note Several vertices may have the same point property. + Vertex_index add_vertex(const Point& p) { + Vertex_index v = add_vertex(); + vpoint_[v] = p; + return v; + } public: - /// adds a new edge, and resizes edge and halfedge properties if necessary. - Halfedge_index add_edge() - { - Halfedge_index h0, h1; - size_type inf = (std::numeric_limits::max)(); - if(recycle_ && (edges_freelist_ != inf)){ - size_type idx = edges_freelist_; - edges_freelist_ = (size_type)hconn_[Halfedge_index(edges_freelist_)].next_halfedge_; - --removed_edges_; - eremoved_[Edge_index(Halfedge_index(idx))] = false; - hprops_.reset(Halfedge_index(idx)); - hprops_.reset(opposite(Halfedge_index(idx))); - eprops_.reset(Edge_index(Halfedge_index(idx))); - return Halfedge_index(idx); - } else { - eprops_.push_back(); - hprops_.push_back(); - hprops_.push_back(); + /// adds a new edge, and resizes edge and halfedge properties if necessary. + Halfedge_index add_edge() { - return Halfedge_index(num_halfedges()-2); - } - } + // Add properties for a new edge + eprops_.emplace(); - /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. - /// Sets the targets of the halfedge to the given vertices, but does not modify the halfedge - /// associated to the vertices. - /// \note The function does not check whether there is already an edge between the vertices. - /// \returns the halfedge with `v1` as target + // Add properties for a pair of new half-edges + // The new half-edges are placed adjacently, and we return the index of the first + return hprops_.emplace_group(2); + } - Halfedge_index add_edge(Vertex_index v0, Vertex_index v1) - { - CGAL_assertion(v0 != v1); - Halfedge_index h = add_edge(); + /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. + /// Sets the targets of the halfedge to the given vertices, but does not modify the halfedge + /// associated to the vertices. + /// \note The function does not check whether there is already an edge between the vertices. + /// \returns the halfedge with `v1` as target - set_target(h, v1); - set_target(opposite(h), v0); + Halfedge_index add_edge(Vertex_index v0, Vertex_index v1) { + CGAL_assertion(v0 != v1); + Halfedge_index h = add_edge(); - return h; - } + set_target(h, v1); + set_target(opposite(h), v0); - /// adds a new face, and resizes face properties if necessary. - Face_index add_face() - { - size_type inf = (std::numeric_limits::max)(); - if(recycle_ && (faces_freelist_ != inf)){ - size_type idx = faces_freelist_; - faces_freelist_ = (size_type)fconn_[Face_index(faces_freelist_)].halfedge_; - --removed_faces_; - fprops_.reset(Face_index(idx)); - fremoved_[Face_index(idx)] = false; - return Face_index(idx); - } else { - fprops_.push_back(); - return Face_index(num_faces()-1); - } - } + return h; + } - /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. - /// The function adds halfedges between successive vertices if they are not yet indicent to halfedges, - /// or updates the connectivity of halfedges already in place. - /// Resizes halfedge, edge, and face properties if necessary. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - template - Face_index add_face(const Range& vertices); + /// adds a new face, and resizes face properties if necessary. + Face_index add_face() { + return fprops_.emplace(); + } + + /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. + /// The function adds halfedges between successive vertices if they are not yet indicent to halfedges, + /// or updates the connectivity of halfedges already in place. + /// Resizes halfedge, edge, and face properties if necessary. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + template + Face_index add_face(const Range& vertices); - /// adds a new triangle connecting vertices `v0`, `v1`, `v2`. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2) - { - boost::array - v = {{v0, v1, v2}}; - return add_face(v); - } + /// adds a new triangle connecting vertices `v0`, `v1`, `v2`. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2) { + boost::array + v = {{v0, v1, v2}}; + return add_face(v); + } - /// adds a new quad connecting vertices `v0`, `v1`, `v2`, `v3`. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2, Vertex_index v3) - { - boost::array - v = {{v0, v1, v2, v3}}; - return add_face(v); - } + /// adds a new quad connecting vertices `v0`, `v1`, `v2`, `v3`. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2, Vertex_index v3) { + boost::array + v = {{v0, v1, v2, v3}}; + return add_face(v); + } - ///@} + ///@} - /// \name Low-Level Removal Functions - /// - /// Although the elements are only marked as removed - /// their connectivity and properties should not be used. - /// - /// \warning Functions in this group do not adjust any of - /// connected elements and usually leave the surface mesh in an - /// invalid state. - /// - /// - /// @{ + /// \name Low-Level Removal Functions + /// + /// Although the elements are only marked as removed + /// their connectivity and properties should not be used. + /// + /// \warning Functions in this group do not adjust any of + /// connected elements and usually leave the surface mesh in an + /// invalid state. + /// + /// + /// @{ - /// removes vertex `v` from the halfedge data structure without - /// adjusting anything. - void remove_vertex(Vertex_index v) - { - vremoved_[v] = true; ++removed_vertices_; garbage_ = true; - vconn_[v].halfedge_ = Halfedge_index(vertices_freelist_); - vertices_freelist_ = (size_type)v; - } + /// removes vertex `v` from the halfedge data structure without + /// adjusting anything. + void remove_vertex(Vertex_index v) { + // todo: confirm this behaves correctly + vprops_.erase(v); + } - /// removes the two halfedges corresponding to `e` from the halfedge data structure without - /// adjusting anything. - void remove_edge(Edge_index e) - { - eremoved_[e] = true; ++removed_edges_; garbage_ = true; - hconn_[Halfedge_index((size_type)e << 1)].next_halfedge_ = Halfedge_index(edges_freelist_ ); - edges_freelist_ = ((size_type)e << 1); - } + /// removes the two halfedges corresponding to `e` from the halfedge data structure without + /// adjusting anything. + void remove_edge(Edge_index e) { + // todo: confirm this behaves correctly + eprops_.erase(e); + } - /// removes face `f` from the halfedge data structure without - /// adjusting anything. + /// removes face `f` from the halfedge data structure without + /// adjusting anything. - void remove_face(Face_index f) - { - fremoved_[f] = true; ++removed_faces_; garbage_ = true; - fconn_[f].halfedge_ = Halfedge_index(faces_freelist_); - faces_freelist_ = (size_type)f; - } + void remove_face(Face_index f) { + // todo: confirm this behaves correctly + fprops_.erase(f); + } - ///@} + ///@} - /// \name Memory Management - /// - /// Functions to check the number of elements, the amount of space - /// allocated for elements, and to clear the structure. - ///@{ + /// \name Memory Management + /// + /// Functions to check the number of elements, the amount of space + /// allocated for elements, and to clear the structure. + ///@{ /// returns the number of vertices in the mesh. - size_type number_of_vertices() const - { - return num_vertices() - number_of_removed_vertices(); + size_type number_of_vertices() const { + return vprops_.size(); } /// returns the number of halfedges in the mesh. - size_type number_of_halfedges() const - { - return num_halfedges() - number_of_removed_halfedges(); + size_type number_of_halfedges() const { + return hprops_.size(); } /// returns the number of edges in the mesh. - size_type number_of_edges() const - { - return num_edges() - number_of_removed_edges(); + size_type number_of_edges() const { + return eprops_.size(); } /// returns the number of faces in the mesh. - size_type number_of_faces() const - { - return num_faces() - number_of_removed_faces(); + size_type number_of_faces() const { + return fprops_.size(); } - /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. - bool is_empty() const - { - return ( num_vertices() == number_of_removed_vertices() - && num_halfedges() == number_of_removed_halfedges() - && num_faces() == number_of_removed_faces()); + /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. + bool is_empty() const { + return (vprops_.size() == 0 + && hprops_.size() == 0 + && fprops_.size() == 0); } - /// removes all vertices, halfedge, edges and faces. Collects garbage but keeps all property maps. - void clear_without_removing_property_maps(); - - /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. - /// - /// After calling this method, the object is the same as a newly constructed object. The additional property maps are also removed and must thus be re-added if needed. - void clear(); + /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. + /// + /// After calling this method, the object is the same as a newly constructed object. The additional property maps are also removed and must thus be re-added if needed. + void clear() { + // todo + } - /// reserves space for vertices, halfedges, edges, faces, and their currently - /// associated properties. - void reserve(size_type nvertices, - size_type nedges, - size_type nfaces ) - { - vprops_.reserve(nvertices); - hprops_.reserve(2*nedges); - eprops_.reserve(nedges); - fprops_.reserve(nfaces); - } + /// reserves space for vertices, halfedges, edges, faces, and their currently + /// associated properties. + void reserve(size_type nvertices, + size_type nedges, + size_type nfaces) { + vprops_.reserve(nvertices); + hprops_.reserve(2 * nedges); + eprops_.reserve(nedges); + fprops_.reserve(nfaces); + } - void resize(size_type nvertices, - size_type nedges, - size_type nfaces ) - { - vprops_.resize(nvertices); - hprops_.resize(2*nedges); - eprops_.resize(nedges); - fprops_.resize(nfaces); - } +// void resize(size_type nvertices, +// size_type nedges, +// size_type nfaces) { +// vprops_.resize(nvertices); +// hprops_.resize(2 * nedges); +// eprops_.resize(nedges); +// fprops_.resize(nfaces); +// } /// copies the simplices from `other`, and copies values of /// properties that already exist under the same name in `*this`. /// In case `*this` has a property that does not exist in `other` /// the copied simplices get the default value of the property. - bool join(const Surface_mesh& other) - { - // increase capacity - const size_type nv = num_vertices(), nh = num_halfedges(), nf = num_faces(); - resize(num_vertices()+ other.num_vertices(), - num_edges()+ other.num_edges(), - num_faces()+ other.num_faces()); + bool join(const Surface_mesh& other) { + + // Record the original sizes of the property maps + const size_type nv = number_of_vertices(), nh = number_of_halfedges(), nf = number_of_faces(); // append properties in the free space created by resize - vprops_.transfer(other.vprops_); - hprops_.transfer(other.hprops_); - fprops_.transfer(other.fprops_); - eprops_.transfer(other.eprops_); + vprops_.append(other.vprops_); + hprops_.append(other.hprops_); + fprops_.append(other.fprops_); + eprops_.append(other.eprops_); + + // todo: the below code assumes no gaps were present in the properties! That might be okay for this situation. // translate halfedge index in vertex -> halfedge - for(size_type i = nv; i < nv+other.num_vertices(); i++){ + for (size_type i = nv; i < nv + other.number_of_vertices(); i++) { Vertex_index vi(i); - if(vconn_[vi].halfedge_ != null_halfedge()){ - vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_)+nh); + if (vconn_[vi].halfedge_ != null_halfedge()) { + vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_) + nh); } } // translate halfedge index in face -> halfedge - for(size_type i = nf; i < nf+other.num_faces(); i++){ + for (size_type i = nf; i < nf + other.number_of_faces(); i++) { Face_index fi(i); - if(fconn_[fi].halfedge_ != null_halfedge()){ - fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_)+nh); + if (fconn_[fi].halfedge_ != null_halfedge()) { + fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_) + nh); } } // translate indices in halfedge -> face, halfedge -> target, halfedge -> prev, and halfedge -> next - for(size_type i = nh; i < nh+other.num_halfedges(); i++){ + for (size_type i = nh; i < nh + other.number_of_halfedges(); i++) { Halfedge_index hi(i); - if(hconn_[hi].face_ != null_face()){ - hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_)+nf); + if (hconn_[hi].face_ != null_face()) { + hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_) + nf); } - if( hconn_[hi].vertex_ != null_vertex()){ - hconn_[hi].vertex_ = Vertex_index(size_type(hconn_[hi].vertex_)+nv); + if (hconn_[hi].vertex_ != null_vertex()) { + hconn_[hi].vertex_ = Vertex_index(size_type(hconn_[hi].vertex_) + nv); } - if(hconn_[hi].next_halfedge_ != null_halfedge()){ - hconn_[hi].next_halfedge_ = Halfedge_index(size_type(hconn_[hi].next_halfedge_)+nh); + if (hconn_[hi].next_halfedge_ != null_halfedge()) { + hconn_[hi].next_halfedge_ = Halfedge_index(size_type(hconn_[hi].next_halfedge_) + nh); } - if(hconn_[hi].prev_halfedge_ != null_halfedge()){ - hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_)+nh); + if (hconn_[hi].prev_halfedge_ != null_halfedge()) { + hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_) + nh); } } - size_type inf_value = (std::numeric_limits::max)(); - - // merge vertex free list - if(other.vertices_freelist_ != inf_value){ - Vertex_index vi(nv+other.vertices_freelist_); - Halfedge_index inf((std::numeric_limits::max)()); - // correct the indices in the linked list of free vertices copied (due to vconn_ translation) - while(vconn_[vi].halfedge_ != inf){ - Vertex_index corrected_vi = Vertex_index(size_type(vconn_[vi].halfedge_)+nv-nh); - vconn_[vi].halfedge_ = Halfedge_index(corrected_vi); - vi = corrected_vi; - } - // append the vertex free linked list of `this` to the copy of `other` - vconn_[vi].halfedge_ = Halfedge_index(vertices_freelist_); - // update the begin of the vertex free linked list - vertices_freelist_ = nv + other.vertices_freelist_; - } - // merge face free list - if(other.faces_freelist_ != inf_value){ - Face_index fi(nf+other.faces_freelist_); - Halfedge_index inf((std::numeric_limits::max)()); - // correct the indices in the linked list of free faces copied (due to fconn_ translation) - while(fconn_[fi].halfedge_ != inf){ - Face_index corrected_fi = Face_index(size_type(fconn_[fi].halfedge_)+nf-nh); - fconn_[fi].halfedge_ = Halfedge_index(corrected_fi); - fi = corrected_fi; - } - // append the face free linked list of `this` to the copy of `other` - fconn_[fi].halfedge_ = Halfedge_index(faces_freelist_); - // update the begin of the face free linked list - faces_freelist_ = nf + other.faces_freelist_; - } - // merge edge free list - if(other.edges_freelist_ != inf_value){ - Halfedge_index hi(nh+other.edges_freelist_); - Halfedge_index inf((std::numeric_limits::max)()); - while(hconn_[hi].next_halfedge_ != inf){ - hi = hconn_[hi].next_halfedge_; - } - // append the halfedge free linked list of `this` to the copy of `other` - hconn_[hi].next_halfedge_ = Halfedge_index(edges_freelist_); - // update the begin of the halfedge free linked list - edges_freelist_ = nh + other.edges_freelist_; - } - // update garbage infos - garbage_ = garbage_ || other.garbage_; - removed_vertices_ += other.removed_vertices_; - removed_edges_ += other.removed_edges_; - removed_faces_ += other.removed_faces_; return true; } - ///@} + ///@} - /// \name Garbage Collection - /// - /// While removing elements only marks them as removed - /// garbage collection really removes them. - /// The API in this section allows to check whether - /// an element is removed, to get the number of - /// removed elements, and to collect garbage. - /// The number of elements together with the number of removed elements is - /// an upperbound on the index, and is needed - /// by algorithms that temporarily store a - /// property in a vector of the appropriate size. - /// Note however that by garbage collecting elements get new indices. - /// In case you store indices in an auxiliary data structure - /// or in a property these indices are potentially no longer - /// referring to the right elements. - /// When adding elements, by default elements that are marked as removed - /// are recycled. + /// \name Garbage Collection + /// + /// While removing elements only marks them as removed + /// garbage collection really removes them. + /// The API in this section allows to check whether + /// an element is removed, to get the number of + /// removed elements, and to collect garbage. + /// The number of elements together with the number of removed elements is + /// an upperbound on the index, and is needed + /// by algorithms that temporarily store a + /// property in a vector of the appropriate size. + /// Note however that by garbage collecting elements get new indices. + /// In case you store indices in an auxiliary data structure + /// or in a property these indices are potentially no longer + /// referring to the right elements. + /// When adding elements, by default elements that are marked as removed + /// are recycled. - ///@{ -#ifndef DOXYGEN_RUNNING - /// returns the number of used and removed vertices in the mesh. - size_type num_vertices() const { return (size_type) vprops_.size(); } + ///@{ - /// returns the number of used and removed halfedges in the mesh. - size_type num_halfedges() const { return (size_type) hprops_.size(); } + /// returns the number of vertices in the mesh which are marked removed. + size_type number_of_removed_vertices() const { return vprops_.capacity() - vprops_.size(); } - /// returns the number of used and removed edges in the mesh. - size_type num_edges() const { return (size_type) eprops_.size(); } + /// returns the number of halfedges in the mesh which are marked removed. + size_type number_of_removed_halfedges() const { return hprops_.capacity() - hprops_.size(); } - /// returns the number of used and removed faces in the mesh. - size_type num_faces() const { return (size_type) fprops_.size(); } + /// returns the number of edges in the mesh which are marked removed. + size_type number_of_removed_edges() const { return eprops_.capacity() - eprops_.size(); } -#endif - - /// returns the number of vertices in the mesh which are marked removed. - size_type number_of_removed_vertices() const { return removed_vertices_; } - - /// returns the number of halfedges in the mesh which are marked removed. - size_type number_of_removed_halfedges() const { return 2*removed_edges_; } - - /// returns the number of edges in the mesh which are marked removed. - size_type number_of_removed_edges() const { return removed_edges_; } - - /// returns the number offaces in the mesh which are marked removed. - size_type number_of_removed_faces() const { return removed_faces_; } + /// returns the number offaces in the mesh which are marked removed. + size_type number_of_removed_faces() const { return fprops_.capacity() - fprops_.size(); } + /// returns whether vertex `v` is marked removed. + bool is_removed(Vertex_index v) const { + return vprops_.is_erased(v); + } - /// returns whether vertex `v` is marked removed. - /// \sa `collect_garbage()` - bool is_removed(Vertex_index v) const - { - return vremoved_[v]; - } - /// returns whether halfedge `h` is marked removed. - /// \sa `collect_garbage()` - bool is_removed(Halfedge_index h) const - { - return eremoved_[edge(h)]; - } - /// returns whether edge `e` is marked removed. - /// \sa `collect_garbage()` - bool is_removed(Edge_index e) const - { - return eremoved_[e]; - } - /// returns whether face `f` is marked removed. - /// \sa `collect_garbage()` - bool is_removed(Face_index f) const - { - return fremoved_[f]; - } + /// returns whether halfedge `h` is marked removed. + bool is_removed(Halfedge_index h) const { + return hprops_.is_erased(h); + } - /// checks if any vertices, halfedges, edges, or faces are marked as removed. - /// \sa collect_garbage - bool has_garbage() const { return garbage_; } + /// returns whether edge `e` is marked removed. + bool is_removed(Edge_index e) const { + return eprops_.is_erased(e); + } - /// really removes vertices, halfedges, edges, and faces which are marked removed. - /// \sa `has_garbage()` - /// \attention By garbage collecting elements get new indices. - /// In case you store indices in an auxiliary data structure - /// or in a property these indices are potentially no longer - /// referring to the right elements. - void collect_garbage(); + /// returns whether face `f` is marked removed. + bool is_removed(Face_index f) const { + return fprops_.is_erased(f); + } - //undocumented convenience function that allows to get old-index->new-index information - template - void collect_garbage(Visitor& visitor); + /// checks if any vertices, halfedges, edges, or faces are marked as removed. + /// \sa collect_garbage + // todo: remove + bool has_garbage() const { return false; } - /// controls the recycling or not of simplices previously marked as removed - /// upon addition of new elements. - /// When set to `true` (default value), new elements are first picked in the garbage (if any) - /// while if set to `false` only new elements are created. - void set_recycle_garbage(bool b); + /// really removes vertices, halfedges, edges, and faces which are marked removed. + /// \sa `has_garbage()` + /// \attention By garbage collecting elements get new indices. + /// In case you store indices in an auxiliary data structure + /// or in a property these indices are potentially no longer + /// referring to the right elements. + void collect_garbage(); - /// Getter - bool does_recycle_garbage() const; +// //undocumented convenience function that allows to get old-index->new-index information +// template +// void collect_garbage(Visitor& visitor); - /// @cond CGAL_DOCUMENT_INTERNALS - /// removes unused memory from vectors. This shrinks the storage - /// of all properties to the minimal required size. - /// \attention Invalidates all existing references to properties. + /// controls the recycling or not of simplices previously marked as removed + /// upon addition of new elements. + /// When set to `true` (default value), new elements are first picked in the garbage (if any) + /// while if set to `false` only new elements are created. + void set_recycle_garbage(bool b); - void shrink_to_fit() - { - vprops_.shrink_to_fit(); - hprops_.shrink_to_fit(); - eprops_.shrink_to_fit(); - fprops_.shrink_to_fit(); - } - /// @endcond + /// Getter + bool does_recycle_garbage() const; - ///@} + /// @cond CGAL_DOCUMENT_INTERNALS + /// removes unused memory from vectors. This shrinks the storage + /// of all properties to the minimal required size. + /// \attention Invalidates all existing references to properties. - /// @cond CGAL_DOCUMENT_INTERNALS - /// - /// \name Simple Validity Checks - /// - /// Functions in this group check if the index is valid, that is between - /// `0` and the currently allocated maximum amount of the - /// elements. They do not check if an element is marked as removed. - ///@{ +// void shrink_to_fit() { +// vprops_.shrink_to_fit(); +// hprops_.shrink_to_fit(); +// eprops_.shrink_to_fit(); +// fprops_.shrink_to_fit(); +// } + /// @endcond - /// returns whether the index of vertex `v` is valid, that is within the current array bounds. - bool has_valid_index(Vertex_index v) const - { - return ((size_type)v < num_vertices()); - } + ///@} - /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. - bool has_valid_index(Halfedge_index h) const - { - return ((size_type)h < num_halfedges()); - } - /// returns whether the index of edge `e` is valid, that is within the current array bounds. - bool has_valid_index(Edge_index e) const - { - return ((size_type)e < num_edges()); - } - /// returns whether the index of face `f` is valid, that is within the current array bounds. - bool has_valid_index(Face_index f) const - { - return ((size_type)f < num_faces()); - } + /// @cond CGAL_DOCUMENT_INTERNALS + /// + /// \name Simple Validity Checks + /// + /// Functions in this group check if the index is valid, that is between + /// `0` and the currently allocated maximum amount of the + /// elements. They do not check if an element is marked as removed. + ///@{ - /// @} - /// @endcond + /// returns whether the index of vertex `v` is valid, that is within the current array bounds. + bool has_valid_index(Vertex_index v) const { + return ((size_type) v < number_of_vertices()); + } - /// \name Validity Checks - /// - /// Functions in this group perform checks for structural - /// consistency of a complete surface mesh, or an individual element. - /// They are expensive and should only be used in debug configurations. + /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. + bool has_valid_index(Halfedge_index h) const { + return ((size_type) h < number_of_halfedges()); + } - ///@{ + /// returns whether the index of edge `e` is valid, that is within the current array bounds. + bool has_valid_index(Edge_index e) const { + return ((size_type) e < number_of_edges()); + } - /// perform an expensive validity check on the data structure and - /// print found errors to `std::cerr` when `verbose == true`. - bool is_valid(bool verbose = false) const - { - bool valid = true; - size_type vcount = 0, hcount = 0, fcount = 0; - for(Halfedge_iterator it = halfedges_begin(); it != halfedges_end(); ++it) { - ++hcount; - valid = valid && next(*it).is_valid(); - valid = valid && opposite(*it).is_valid(); - if(!valid) { - if (verbose) - std::cerr << "Integrity of halfedge " << *it << " corrupted." << std::endl; - break; - } + /// returns whether the index of face `f` is valid, that is within the current array bounds. + bool has_valid_index(Face_index f) const { + return ((size_type) f < number_of_faces()); + } - valid = valid && (opposite(*it) != *it); - valid = valid && (opposite(opposite(*it)) == *it); - if(!valid) { - if (verbose) - std::cerr << "Integrity of opposite halfedge of " << *it << " corrupted." << std::endl; - break; - } + /// @} + /// @endcond - valid = valid && (next(prev(*it)) == *it); - if(!valid) { - if (verbose) - std::cerr << "Integrity of previous halfedge of " << *it << " corrupted." << std::endl; - break; - } + /// \name Validity Checks + /// + /// Functions in this group perform checks for structural + /// consistency of a complete surface mesh, or an individual element. + /// They are expensive and should only be used in debug configurations. - valid = valid && (prev(next(*it)) == *it); - if(!valid) { - if (verbose) - std::cerr << "Integrity of next halfedge of " << *it << " corrupted." << std::endl; - break; - } + ///@{ - valid = valid && target(*it).is_valid(); - if(!valid) { - if (verbose) - std::cerr << "Integrity of vertex of halfedge " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (target(*it) == target(opposite(next(*it)))); - if(!valid) { - if (verbose) - std::cerr << "Halfedge vertex of next opposite is not the same for " << *it << "." << std::endl; - break; - } - } - - for(Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { - ++vcount; - if(halfedge(*it).is_valid()) { - // not an isolated vertex - valid = valid && (target(halfedge(*it)) == *it); - if(!valid) { - if (verbose) - std::cerr << "Halfedge of " << *it << " is not an incoming halfedge." << std::endl; - break; - } - } - } - for(Face_iterator it = faces_begin(); it != faces_end(); ++it) { - ++fcount; - } - - valid = valid && (vcount == number_of_vertices()); - if(!valid && verbose){ - std::cerr << "#vertices: iterated: " << vcount << " vs number_of_vertices(): " << number_of_vertices()<< std::endl; - } - - valid = valid && (hcount == number_of_halfedges()); - if(!valid && verbose){ - std::cerr << "#halfedges: iterated: " << hcount << " vs number_of_halfedges(): " << number_of_halfedges()<< std::endl; - } - - valid = valid && (fcount == number_of_faces()); - if(!valid && verbose){ - std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces()<< std::endl; - } - - size_type inf = (std::numeric_limits::max)(); - size_type vfl = vertices_freelist_; - size_type rv = 0; - while(vfl != inf){ - vfl = (size_type)vconn_[Vertex_index(vfl)].halfedge_; - rv++; - } - valid = valid && ( rv == removed_vertices_ ); - - - size_type efl = edges_freelist_; - size_type re = 0; - while(efl != inf){ - efl = (size_type)hconn_[Halfedge_index(efl)].next_halfedge_; - re++; - } - valid = valid && ( re == removed_edges_ ); - - size_type ffl = faces_freelist_; - size_type rf = 0; - while(ffl != inf){ - ffl = (size_type)fconn_[Face_index(ffl)].halfedge_; - rf++; - } - valid = valid && ( rf == removed_faces_ ); - - return valid; - } - - /// performs a validity check on a single vertex. - bool is_valid(Vertex_index v, - bool verbose = false) const - { - Verbose_ostream verr(verbose); - - if(!has_valid_index(v)) - { - verr << "Vertex has invalid index: " << (size_type)v << std::endl; - return false; - } - - Halfedge_index h = vconn_[v].halfedge_; - if(h != null_halfedge() && (!has_valid_index(h) || is_removed(h))) { - verr << "Vertex connectivity halfedge error: Vertex " << (size_type)v - << " with " << (size_type)h << std::endl; - return false; - } - return true; - } - - /// performs a validity check on a single halfedge. - bool is_valid(Halfedge_index h, - bool verbose = false) const - { - Verbose_ostream verr(verbose); - - if(!has_valid_index(h)) - { - verr << "Halfedge has invalid index: " << (size_type)h << std::endl; - return false; - } - - Face_index f = hconn_[h].face_; - Vertex_index v = hconn_[h].vertex_; - Halfedge_index hn = hconn_[h].next_halfedge_; - Halfedge_index hp = hconn_[h].prev_halfedge_; - - bool valid = true; - // don't validate the face if this is a border halfedge - if(!is_border(h)) { - if(!has_valid_index(f) || is_removed(f)) { - verr << "Halfedge connectivity error: Face " - << (!has_valid_index(f) ? "invalid" : "removed") - << " in " << (size_type)h << std::endl; - valid = false; - } - } - - if(!has_valid_index(v) || is_removed(v)) { - verr << "Halfedge connectivity error: Vertex " - << (!has_valid_index(v) ? "invalid" : "removed") - << " in " << (size_type)h << std::endl; - valid = false; - } - - if(!has_valid_index(hn) || is_removed(hn)) { - verr << "Halfedge connectivity error: hnext " - << (!has_valid_index(hn) ? "invalid" : "removed") - << " in " << (size_type)h << std::endl; - valid = false; - } - if(!has_valid_index(hp) || is_removed(hp)) { - verr << "Halfedge connectivity error: hprev " - << (!has_valid_index(hp) ? "invalid" : "removed") - << " in " << (size_type)h << std::endl; - valid = false; - } - return valid; - } - - - /// performs a validity check on a single edge. - bool is_valid(Edge_index e, - bool verbose = false) const - { - Verbose_ostream verr(verbose); - - if(!has_valid_index(e)) - { - verr << "Edge has invalid index: " << (size_type)e << std::endl; - return false; + /// perform an expensive validity check on the data structure and + /// print found errors to `std::cerr` when `verbose == true`. + bool is_valid(bool verbose = false) const { + bool valid = true; + size_type vcount = 0, hcount = 0, fcount = 0; + for (Halfedge_iterator it = halfedges_begin(); it != halfedges_end(); ++it) { + ++hcount; + valid = valid && next(*it).is_valid(); + valid = valid && opposite(*it).is_valid(); + if (!valid) { + if (verbose) + std::cerr << "Integrity of halfedge " << *it << " corrupted." << std::endl; + break; } - Halfedge_index h = halfedge(e); - return is_valid(h, verbose) && is_valid(opposite(h), verbose); - } + valid = valid && (opposite(*it) != *it); + valid = valid && (opposite(opposite(*it)) == *it); + if (!valid) { + if (verbose) + std::cerr << "Integrity of opposite halfedge of " << *it << " corrupted." << std::endl; + break; + } + valid = valid && (next(prev(*it)) == *it); + if (!valid) { + if (verbose) + std::cerr << "Integrity of previous halfedge of " << *it << " corrupted." << std::endl; + break; + } - /// performs a validity check on a single face. - bool is_valid(Face_index f, - bool verbose = false) const - { - Verbose_ostream verr(verbose); + valid = valid && (prev(next(*it)) == *it); + if (!valid) { + if (verbose) + std::cerr << "Integrity of next halfedge of " << *it << " corrupted." << std::endl; + break; + } - if(!has_valid_index(f)) - { - verr << "Face has invalid index: " << (size_type)f << std::endl; - return false; - } + valid = valid && target(*it).is_valid(); + if (!valid) { + if (verbose) + std::cerr << "Integrity of vertex of halfedge " << *it << " corrupted." << std::endl; + break; + } - Halfedge_index h = fconn_[f].halfedge_; - if(!has_valid_index(h) || is_removed(h)) { - verr << "Face connectivity halfedge error: Face " << (size_type)f - << " with " << (size_type)h << std::endl; - return false; - } - return true; - } - - ///@} - - - - /// \name Low-Level Connectivity - ///@{ - - /// returns the vertex the halfedge `h` points to. - Vertex_index target(Halfedge_index h) const - { - return hconn_[h].vertex_; - } - - /// sets the vertex the halfedge `h` points to to `v`. - void set_target(Halfedge_index h, Vertex_index v) - { - hconn_[h].vertex_ = v; - } - - /// returns the face incident to halfedge `h`. - Face_index face(Halfedge_index h) const - { - return hconn_[h].face_; - } - - /// sets the incident face to halfedge `h` to `f`. - void set_face(Halfedge_index h, Face_index f) - { - hconn_[h].face_ = f; - } - - /// returns the next halfedge within the incident face. - Halfedge_index next(Halfedge_index h) const - { - return hconn_[h].next_halfedge_; - } - - /// returns the previous halfedge within the incident face. - Halfedge_index prev(Halfedge_index h) const - { - return hconn_[h].prev_halfedge_; - } - - /// @cond CGAL_DOCUMENT_INTERNALS - // sets the next halfedge of `h` within the face to `nh`. - void set_next_only(Halfedge_index h, Halfedge_index nh) - { - hconn_[h].next_halfedge_ = nh; - } - - // sets previous halfedge of `h` to `nh`. - void set_prev_only(Halfedge_index h, Halfedge_index nh) - { - if(h != null_halfedge()){ - hconn_[h].prev_halfedge_ = nh; + valid = valid && (target(*it) == target(opposite(next(*it)))); + if (!valid) { + if (verbose) + std::cerr << "Halfedge vertex of next opposite is not the same for " << *it << "." << std::endl; + break; } } - /// @endcond - /// sets the next halfedge of `h` within the face to `nh` and - /// the previous halfedge of `nh` to `h`. - void set_next(Halfedge_index h, Halfedge_index nh) - { - set_next_only(h, nh); - set_prev_only(nh, h); + for (Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { + ++vcount; + if (halfedge(*it).is_valid()) { + // not an isolated vertex + valid = valid && (target(halfedge(*it)) == *it); + if (!valid) { + if (verbose) + std::cerr << "Halfedge of " << *it << " is not an incoming halfedge." << std::endl; + break; + } + } + } + for (Face_iterator it = faces_begin(); it != faces_end(); ++it) { + ++fcount; } - /// returns an incoming halfedge of vertex `v`. - /// If `v` is a border vertex this will be a border halfedge. - /// \invariant `target(halfedge(v)) == v` - Halfedge_index halfedge(Vertex_index v) const - { - return vconn_[v].halfedge_; + valid = valid && (vcount == number_of_vertices()); + if (!valid && verbose) { + std::cerr << "#vertices: iterated: " << vcount << " vs number_of_vertices(): " << number_of_vertices() + << std::endl; } - /// sets the incoming halfedge of vertex `v` to `h`. - void set_halfedge(Vertex_index v, Halfedge_index h) - { - vconn_[v].halfedge_ = h; + valid = valid && (hcount == number_of_halfedges()); + if (!valid && verbose) { + std::cerr << "#halfedges: iterated: " << hcount << " vs number_of_halfedges(): " << number_of_halfedges() + << std::endl; } - - /// returns a halfedge of face `f`. - Halfedge_index halfedge(Face_index f) const - { - return fconn_[f].halfedge_; + valid = valid && (fcount == number_of_faces()); + if (!valid && verbose) { + std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces() << std::endl; } - /// sets the halfedge of face `f` to `h`. - void set_halfedge(Face_index f, Halfedge_index h) - { - fconn_[f].halfedge_ = h; + return valid; + } + + /// performs a validity check on a single vertex. + bool is_valid(Vertex_index v, + bool verbose = false) const { + Verbose_ostream verr(verbose); + + if (!has_valid_index(v)) { + verr << "Vertex has invalid index: " << (size_type) v << std::endl; + return false; } - /// returns the opposite halfedge of `h`. Note that there is no function `set_opposite()`. - Halfedge_index opposite(Halfedge_index h) const - { - return Halfedge_index(((size_type)h & 1) ? (size_type)h-1 : (size_type)h+1); + Halfedge_index h = vconn_[v].halfedge_; + if (h != null_halfedge() && (!has_valid_index(h) || is_removed(h))) { + verr << "Vertex connectivity halfedge error: Vertex " << (size_type) v + << " with " << (size_type) h << std::endl; + return false; + } + return true; + } + + /// performs a validity check on a single halfedge. + bool is_valid(Halfedge_index h, + bool verbose = false) const { + Verbose_ostream verr(verbose); + + if (!has_valid_index(h)) { + verr << "Halfedge has invalid index: " << (size_type) h << std::endl; + return false; } - ///@} + Face_index f = hconn_[h].face_; + Vertex_index v = hconn_[h].vertex_; + Halfedge_index hn = hconn_[h].next_halfedge_; + Halfedge_index hp = hconn_[h].prev_halfedge_; - /// \name Low-Level Connectivity Convenience Functions - ///@{ - - /// returns the vertex the halfedge `h` emanates from. - Vertex_index source(Halfedge_index h) const - { - return target(opposite(h)); + bool valid = true; + // don't validate the face if this is a border halfedge + if (!is_border(h)) { + if (!has_valid_index(f) || is_removed(f)) { + verr << "Halfedge connectivity error: Face " + << (!has_valid_index(f) ? "invalid" : "removed") + << " in " << (size_type) h << std::endl; + valid = false; + } } - /// returns `opposite(next(h))`, that is the next halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the target vertex of `h`. - Halfedge_index next_around_target(Halfedge_index h) const - { - return opposite(next(h)); + if (!has_valid_index(v) || is_removed(v)) { + verr << "Halfedge connectivity error: Vertex " + << (!has_valid_index(v) ? "invalid" : "removed") + << " in " << (size_type) h << std::endl; + valid = false; } - /// returns `prev(opposite(h))`, that is the previous halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the target vertex of `h`. - Halfedge_index prev_around_target(Halfedge_index h) const - { - return prev(opposite(h)); + if (!has_valid_index(hn) || is_removed(hn)) { + verr << "Halfedge connectivity error: hnext " + << (!has_valid_index(hn) ? "invalid" : "removed") + << " in " << (size_type) h << std::endl; + valid = false; + } + if (!has_valid_index(hp) || is_removed(hp)) { + verr << "Halfedge connectivity error: hprev " + << (!has_valid_index(hp) ? "invalid" : "removed") + << " in " << (size_type) h << std::endl; + valid = false; + } + return valid; + } + + + /// performs a validity check on a single edge. + bool is_valid(Edge_index e, + bool verbose = false) const { + Verbose_ostream verr(verbose); + + if (!has_valid_index(e)) { + verr << "Edge has invalid index: " << (size_type) e << std::endl; + return false; } - /// returns `next(opposite(h))`, that is the next halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the source vertex of `h`. - Halfedge_index next_around_source(Halfedge_index h) const - { - return next(opposite(h)); + Halfedge_index h = halfedge(e); + return is_valid(h, verbose) && is_valid(opposite(h), verbose); + } + + + /// performs a validity check on a single face. + bool is_valid(Face_index f, + bool verbose = false) const { + Verbose_ostream verr(verbose); + + if (!has_valid_index(f)) { + verr << "Face has invalid index: " << (size_type) f << std::endl; + return false; } - /// returns `opposite(prev(h))`, that is the previous halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the source vertex of `h`. - Halfedge_index prev_around_source(Halfedge_index h) const - { - return opposite(prev(h)); + Halfedge_index h = fconn_[f].halfedge_; + if (!has_valid_index(h) || is_removed(h)) { + verr << "Face connectivity halfedge error: Face " << (size_type) f + << " with " << (size_type) h << std::endl; + return false; } + return true; + } - /// returns the i'th vertex of edge `e`, for `i=0` or `1`. - Vertex_index vertex(Edge_index e, unsigned int i) const - { - CGAL_assertion(i<=1); - return target(halfedge(e, i)); + ///@} + + + + /// \name Low-Level Connectivity + ///@{ + + /// returns the vertex the halfedge `h` points to. + Vertex_index target(Halfedge_index h) const { + return hconn_[h].vertex_; + } + + /// sets the vertex the halfedge `h` points to to `v`. + void set_target(Halfedge_index h, Vertex_index v) { + hconn_[h].vertex_ = v; + } + + /// returns the face incident to halfedge `h`. + Face_index face(Halfedge_index h) const { + return hconn_[h].face_; + } + + /// sets the incident face to halfedge `h` to `f`. + void set_face(Halfedge_index h, Face_index f) { + hconn_[h].face_ = f; + } + + /// returns the next halfedge within the incident face. + Halfedge_index next(Halfedge_index h) const { + return hconn_[h].next_halfedge_; + } + + /// returns the previous halfedge within the incident face. + Halfedge_index prev(Halfedge_index h) const { + return hconn_[h].prev_halfedge_; + } + + /// @cond CGAL_DOCUMENT_INTERNALS + // sets the next halfedge of `h` within the face to `nh`. + void set_next_only(Halfedge_index h, Halfedge_index nh) { + hconn_[h].next_halfedge_ = nh; + } + + // sets previous halfedge of `h` to `nh`. + void set_prev_only(Halfedge_index h, Halfedge_index nh) { + if (h != null_halfedge()) { + hconn_[h].prev_halfedge_ = nh; } + } + /// @endcond - /// finds a halfedge between two vertices. Returns a default constructed - /// `Halfedge_index`, if `source` and `target` are not connected. - Halfedge_index halfedge(Vertex_index source, Vertex_index target) const; + /// sets the next halfedge of `h` within the face to `nh` and + /// the previous halfedge of `nh` to `h`. + void set_next(Halfedge_index h, Halfedge_index nh) { + set_next_only(h, nh); + set_prev_only(nh, h); + } - ///@} + /// returns an incoming halfedge of vertex `v`. + /// If `v` is a border vertex this will be a border halfedge. + /// \invariant `target(halfedge(v)) == v` + Halfedge_index halfedge(Vertex_index v) const { + return vconn_[v].halfedge_; + } + + /// sets the incoming halfedge of vertex `v` to `h`. + void set_halfedge(Vertex_index v, Halfedge_index h) { + vconn_[v].halfedge_ = h; + } - /// \name Switching between Halfedges and Edges - ///@{ + /// returns a halfedge of face `f`. + Halfedge_index halfedge(Face_index f) const { + return fconn_[f].halfedge_; + } - /// returns the edge that contains halfedge `h` as one of its two halfedges. - Edge_index edge(Halfedge_index h) const - { - return Edge_index(h); + /// sets the halfedge of face `f` to `h`. + void set_halfedge(Face_index f, Halfedge_index h) { + fconn_[f].halfedge_ = h; + } + + /// returns the opposite halfedge of `h`. Note that there is no function `set_opposite()`. + Halfedge_index opposite(Halfedge_index h) const { + return Halfedge_index(((size_type) h & 1) ? (size_type) h - 1 : (size_type) h + 1); + } + + ///@} + + /// \name Low-Level Connectivity Convenience Functions + ///@{ + + /// returns the vertex the halfedge `h` emanates from. + Vertex_index source(Halfedge_index h) const { + return target(opposite(h)); + } + + /// returns `opposite(next(h))`, that is the next halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the target vertex of `h`. + Halfedge_index next_around_target(Halfedge_index h) const { + return opposite(next(h)); + } + + /// returns `prev(opposite(h))`, that is the previous halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the target vertex of `h`. + Halfedge_index prev_around_target(Halfedge_index h) const { + return prev(opposite(h)); + } + + /// returns `next(opposite(h))`, that is the next halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the source vertex of `h`. + Halfedge_index next_around_source(Halfedge_index h) const { + return next(opposite(h)); + } + + /// returns `opposite(prev(h))`, that is the previous halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the source vertex of `h`. + Halfedge_index prev_around_source(Halfedge_index h) const { + return opposite(prev(h)); + } + + /// returns the i'th vertex of edge `e`, for `i=0` or `1`. + Vertex_index vertex(Edge_index e, unsigned int i) const { + CGAL_assertion(i <= 1); + return target(halfedge(e, i)); + } + + /// finds a halfedge between two vertices. Returns a default constructed + /// `Halfedge_index`, if `source` and `target` are not connected. + Halfedge_index halfedge(Vertex_index source, Vertex_index target) const; + + ///@} + + + /// \name Switching between Halfedges and Edges + ///@{ + + /// returns the edge that contains halfedge `h` as one of its two halfedges. + Edge_index edge(Halfedge_index h) const { + return Edge_index(h); + } + + /// returns the halfedge corresponding to the edge `e`. + Halfedge_index halfedge(Edge_index e) const { + return Halfedge_index(e.halfedge()); + } + + /// returns the i'th halfedge of edge `e`, for `i=0` or `1`. + Halfedge_index halfedge(Edge_index e, unsigned int i) const { + CGAL_assertion(i <= 1); + return Halfedge_index(((size_type) e << 1) + i); + } + + ///@} + + + /// \name Degree Functions + ///@{ + + /// returns the number of incident halfedges of vertex `v`. + size_type degree(Vertex_index v) const; + + /// returns the number of incident halfedges of face `f`. + size_type degree(Face_index f) const; + + ///@} + + + + /// \name Borders + /// + /// A halfedge, or edge is on the border of a surface mesh + /// if it is incident to a `null_face()`. A vertex is on a border + /// if it is isolated or incident to a border halfedge. While for a halfedge and + /// edge this is a constant time operation, for a vertex it means + /// to look at all incident halfedges. If algorithms operating on a + /// surface mesh maintain that the halfedge associated to a border vertex is + /// a border halfedge, this is a constant time operation too. + /// This section provides functions to check if an element is on a + /// border and to change the halfedge associated to a border vertex. + ///@{ + + /// returns whether `v` is a border vertex. + /// \cgalAdvancedBegin + /// With the default value for + /// `check_all_incident_halfedges` the function iteratates over the incident halfedges. + /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident + /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. + /// \cgalAdvancedEnd + /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then + /// this operation is not guaranteed to return the right result. + bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const { + Halfedge_index h(halfedge(v)); + if (h == null_halfedge()) { + return true; } - - /// returns the halfedge corresponding to the edge `e`. - Halfedge_index halfedge(Edge_index e) const - { - return Halfedge_index(e.halfedge()); - } - - /// returns the i'th halfedge of edge `e`, for `i=0` or `1`. - Halfedge_index halfedge(Edge_index e, unsigned int i) const - { - CGAL_assertion(i<=1); - return Halfedge_index(((size_type)e << 1) + i); - } - - ///@} - - - /// \name Degree Functions - ///@{ - - /// returns the number of incident halfedges of vertex `v`. - size_type degree(Vertex_index v) const; - - /// returns the number of incident halfedges of face `f`. - size_type degree(Face_index f) const; - - ///@} - - - - /// \name Borders - /// - /// A halfedge, or edge is on the border of a surface mesh - /// if it is incident to a `null_face()`. A vertex is on a border - /// if it is isolated or incident to a border halfedge. While for a halfedge and - /// edge this is a constant time operation, for a vertex it means - /// to look at all incident halfedges. If algorithms operating on a - /// surface mesh maintain that the halfedge associated to a border vertex is - /// a border halfedge, this is a constant time operation too. - /// This section provides functions to check if an element is on a - /// border and to change the halfedge associated to a border vertex. - ///@{ - - /// returns whether `v` is a border vertex. - /// \cgalAdvancedBegin - /// With the default value for - /// `check_all_incident_halfedges` the function iteratates over the incident halfedges. - /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident - /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. - /// \cgalAdvancedEnd - /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then - /// this operation is not guaranteed to return the right result. - bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const - { - Halfedge_index h(halfedge(v)); - if (h == null_halfedge()){ + if (check_all_incident_halfedges) { + Halfedge_around_target_circulator hatc(h, *this), done(hatc); + do { + if (is_border(*hatc)) { return true; } - if(check_all_incident_halfedges){ - Halfedge_around_target_circulator hatc(h,*this), done(hatc); - do { - if(is_border(*hatc)){ - return true; - } - }while(++hatc != done); - return false; - } - return is_border(h); + } while (++hatc != done); + return false; } + return is_border(h); + } - /// returns whether `h` is a border halfege, that is if its incident face is `sm.null_face()`. - bool is_border(Halfedge_index h) const - { - return !face(h).is_valid(); - } + /// returns whether `h` is a border halfege, that is if its incident face is `sm.null_face()`. + bool is_border(Halfedge_index h) const { + return !face(h).is_valid(); + } - /// returns whether `e` is a border edge, i.e., if any - /// of its two halfedges is a border halfedge. - bool is_border(Edge_index e) const - { - return is_border(e.halfedge()) || is_border(opposite(e.halfedge())); - } + /// returns whether `e` is a border edge, i.e., if any + /// of its two halfedges is a border halfedge. + bool is_border(Edge_index e) const { + return is_border(e.halfedge()) || is_border(opposite(e.halfedge())); + } /// iterates over the incident halfedges and sets the incident halfedge /// associated to vertex `v` to a border halfedge and returns `true` if it exists. - bool set_vertex_halfedge_to_border_halfedge(Vertex_index v) - { - if(halfedge(v) == null_halfedge()){ + bool set_vertex_halfedge_to_border_halfedge(Vertex_index v) { + if (halfedge(v) == null_halfedge()) { return false; } - Halfedge_around_target_circulator hatc(halfedge(v),*this), done(hatc); + Halfedge_around_target_circulator hatc(halfedge(v), *this), done(hatc); do { - if(is_border(*hatc)){ - set_halfedge(v,*hatc); + if (is_border(*hatc)) { + set_halfedge(v, *hatc); return true; } - }while(++hatc != done); + } while (++hatc != done); return false; } /// applies `set_vertex_halfedge_to_border_halfedge(Vertex_index)` on all vertices /// around the face associated to `h`. - void set_vertex_halfedge_to_border_halfedge(Halfedge_index h) - { - if(is_border(h)){ - Halfedge_around_face_circulator hafc(h,*this),done(hafc); + void set_vertex_halfedge_to_border_halfedge(Halfedge_index h) { + if (is_border(h)) { + Halfedge_around_face_circulator hafc(h, *this), done(hafc); do { - set_halfedge(target(*hafc),*hafc); - }while(++hafc != done); + set_halfedge(target(*hafc), *hafc); + } while (++hafc != done); } else { - Vertex_around_face_circulator vafc(h,*this),done(vafc); + Vertex_around_face_circulator vafc(h, *this), done(vafc); do { set_vertex_halfedge_to_border_halfedge(*vafc); - }while(++vafc != done); + } while (++vafc != done); } } /// applies `set_vertex_halfedge_to_border_halfedge(Vertex_index)` on all vertices /// of the surface mesh. - void set_vertex_halfedge_to_border_halfedge() - { - for(Halfedge_index h : halfedges()){ - if(is_border(h)){ - set_halfedge(target(h),h); - } + void set_vertex_halfedge_to_border_halfedge() { + for (Halfedge_index h: halfedges()) { + if (is_border(h)) { + set_halfedge(target(h), h); + } } } - /// returns whether `v` is isolated, i.e., incident to `Surface_mesh::null_halfedge()`. - bool is_isolated(Vertex_index v) const - { - return !halfedge(v).is_valid(); - } + /// returns whether `v` is isolated, i.e., incident to `Surface_mesh::null_halfedge()`. + bool is_isolated(Vertex_index v) const { + return !halfedge(v).is_valid(); + } - ///@} + ///@} -private: //--------------------------------------------------- property handling +public: //--------------------------------------------------- property handling - // Property_selector maps an index type to a property_container, the - // dummy is necessary to make it a partial specialization (full - // specializations are only allowed at namespace scope). - template - struct Property_selector {}; - - template - struct Property_selector::Vertex_index, dummy> { - CGAL::Surface_mesh

* m_; - Property_selector(CGAL::Surface_mesh

* m) : m_(m) {} - Properties::Property_container::Vertex_index>& - operator()() { return m_->vprops_; } - void resize_property_array() { m_->vprops_.resize_property_array(3); } - }; - template - struct Property_selector::Halfedge_index, dummy> { - CGAL::Surface_mesh

* m_; - Property_selector(CGAL::Surface_mesh

* m) : m_(m) {} - Properties::Property_container::Halfedge_index>& - operator()() { return m_->hprops_; } - void resize_property_array() { m_->hprops_.resize_property_array(1); } - }; - template - struct Property_selector::Edge_index, dummy> { - CGAL::Surface_mesh

* m_; - Property_selector(CGAL::Surface_mesh

* m) : m_(m) {} - Properties::Property_container::Edge_index>& - operator()() { return m_->eprops_; } - void resize_property_array() { m_->eprops_.resize_property_array(1); } - }; - template - struct Property_selector::Face_index, dummy> { - CGAL::Surface_mesh

* m_; - Property_selector(CGAL::Surface_mesh

* m) : m_(m) {} - Properties::Property_container::Face_index>& - operator()() { return m_->fprops_; } - void resize_property_array() { m_->fprops_.resize_property_array(2); } - }; - - public: + template + Property_container& get_property_container() { + if constexpr (std::is_same_v) + return vprops_; + if constexpr (std::is_same_v) + return hprops_; + if constexpr (std::is_same_v) + return eprops_; + if constexpr (std::is_same_v) + return fprops_; + } - /*! \name Property Handling +public: - A `Properties::Property_map` allows to associate properties of type `T` to a vertex, halfdge, edge, or face index type I. - Properties can be added, and looked up with a string, and they can be removed at runtime. - The \em point property of type `P` is associated to the string "v:point". - */ - ///@{ + /*! \name Property Handling + + A `Properties::Property_map` allows to associate properties of type `T` to a vertex, halfdge, edge, or face index type I. + Properties can be added, and looked up with a string, and they can be removed at runtime. + The \em point property of type `P` is associated to the string "v:point". + + */ + ///@{ /// Model of `LvaluePropertyMap` with `I` as key type and `T` as value type, where `I` /// is either a vertex, halfedge, edge, or face index type. @@ -2065,190 +1819,189 @@ private: //--------------------------------------------------- property handling #endif - /// adds a property map named `name` with value type `T` and default `t` - /// for index type `I`. Returns the property map together with a Boolean - /// that is `true` if a new map was created. In case it already exists - /// the existing map together with `false` is returned. + // todo: I can't see a good reason for these two functions to exist separately, but do almost the same thing - - template - std::pair, bool> - add_property_map(std::string name=std::string(), const T t=T()) { - if(name.empty()){ - std::ostringstream oss; - oss << "anonymous-property-" << anonymous_property_++; - name = std::string(oss.str()); - } - return Property_selector(this)().template add(name, t); + /// adds a property map named `name` with value type `T` and default `t` + /// for index type `I`. Returns the property map together with a Boolean + /// that is `true` if a new map was created. In case it already exists + /// the existing map together with `false` is returned. + template + std::pair, bool> + add_property_map(std::string name = std::string(), const T t = T()) { + if (name.empty()) { + // todo: maybe this should be done by the property container itself? + std::ostringstream oss; + oss << "anonymous-property-" << anonymous_property_++; + name = std::string(oss.str()); } + // todo: double check this is working + auto [array, created] = + const_cast*>(this)->get_property_container().template get_or_add_property(name, t); + return {{array.get()}, created}; + } - /// returns a property map named `name` with key type `I` and value type `T`, - /// and a Boolean that is `true` if the property exists. - /// In case it does not exist the Boolean is `false` and the behavior of - /// the property map is undefined. - template - std::pair,bool> property_map(const std::string& name) const - { - return Property_selector(const_cast(this))().template get(name); - } + /// returns a property map named `name` with key type `I` and value type `T`, + /// and a Boolean that is `true` if the property was created. + template + std::pair, bool> + property_map(const std::string& name) const { + auto [array, created] = + const_cast*>(this)->get_property_container().template get_or_add_property(name); + return {{array.get()}, created}; + } - /// removes property map `p`. The memory allocated for that property map is - /// freed. - template - void remove_property_map(Property_map& p) - { - (Property_selector(this)()).template remove(p); - } + /// removes property map `p`. The memory allocated for that property map is + /// freed. + template + void remove_property_map(Property_map p) { + // todo: this is never used, but it should probably still work + } - /// removes all property maps for index type `I` added by a call to `add_property_map()`. - /// The memory allocated for those property maps is freed. - template - void remove_property_maps() - { - Property_selector(this).resize_property_array(); - } +// /// removes all property maps for index type `I` added by a call to `add_property_map()`. +// /// The memory allocated for those property maps is freed. +// template +// void remove_property_maps() { +// Property_selector(this).resize_property_array(); +// } - /// removes all property maps for all index types added by a call to `add_property_map()`. - /// The memory allocated for those property maps is freed. - void remove_all_property_maps() - { - remove_property_maps(); - remove_property_maps(); - remove_property_maps(); - remove_property_maps(); - } +// /// removes all property maps for all index types added by a call to `add_property_map()`. +// /// The memory allocated for those property maps is freed. +// void remove_all_property_maps() { +// remove_property_maps(); +// remove_property_maps(); +// remove_property_maps(); +// remove_property_maps(); +// } - /// @cond CGAL_DOCUMENT_INTERNALS - /// returns the std::type_info of the value type of the - /// property identified by `name`. `typeid(void)` if `name` - /// does not identify any property. - /// - /// @tparam I The key type of the property. + /// @cond CGAL_DOCUMENT_INTERNALS + /// returns the std::type_info of the value type of the + /// property identified by `name`. `typeid(void)` if `name` + /// does not identify any property. + /// + /// @tparam I The key type of the property. - template - const std::type_info& property_type(const std::string& name) - { - return Property_selector(this)().get_type(name); - } - /// @endcond + template + const std::type_info& property_type(const std::string& name) { + return Property_selector(this)().get_type(name); + } + /// @endcond - /// returns a vector with all strings that describe properties with the key type `I`. - /// @tparam I The key type of the properties. - template - std::vector properties() const - { - return Property_selector(const_cast(this))().properties(); - } + /// returns a vector with all strings that describe properties with the key type `I`. + /// @tparam I The key type of the properties. + template + std::vector properties() const { + return Property_selector(const_cast(this))().properties(); + } - /// returns the property for the string "v:point". - Property_map - points() const { return vpoint_; } + /// returns the property for the string "v:point". + // todo: shouldn't this return a const pmap? + // In the original version, there was no difference between const & non-const maps + Property_array& + points() const { return vpoint_; } - Property_map& - points() { return vpoint_; } + Property_array& + points() { return vpoint_; } - /// returns the point associated to vertex `v`. - const Point& - point(Vertex_index v) const { return vpoint_[v]; } + /// returns the point associated to vertex `v`. + const Point& + point(Vertex_index v) const { return vpoint_[v]; } - /// returns the point associated to vertex `v`. - Point& - point(Vertex_index v) { return vpoint_[v]; } + /// returns the point associated to vertex `v`. + Point& + point(Vertex_index v) { return vpoint_[v]; } - /// @cond CGAL_DOCUMENT_INTERNALS - /// prints property statistics to the stream `out`. The output is human-readable but - /// not machine-friendly. - /// - void property_stats(std::ostream& out = std::cout) const; - /// @endcond - ///@} + /// @cond CGAL_DOCUMENT_INTERNALS + /// prints property statistics to the stream `out`. The output is human-readable but + /// not machine-friendly. + /// + void property_stats(std::ostream& out = std::cout) const; + /// @endcond + ///@} - /// \name Null Elements - ///@{ + /// \name Null Elements + ///@{ /// returns `Vertex_index(std::numeric_limits::%max())`. - static Vertex_index null_vertex() - { + static Vertex_index null_vertex() { return vertex_index((std::numeric_limits::max)()); } /// returns `Edge_index(std::numeric_limits::%max())`. - static Edge_index null_edge() - { + static Edge_index null_edge() { return edge_index((std::numeric_limits::max)()); } + /// returns `Halfedge_index(std::numeric_limits::%max())`. - static Halfedge_index null_halfedge() - { + static Halfedge_index null_halfedge() { return halfedge_index((std::numeric_limits::max)()); } + /// returns `Face_index(std::numeric_limits::%max())`. - static Face_index null_face() - { + static Face_index null_face() { return face_index((std::numeric_limits::max)()); } /// @} #if defined(CGAL_SURFACE_MESH_TEST_SUITE) - Vertex_index vertex_freelist() const - { - return Vertex_index(vertices_freelist_); + + std::vector vertex_freelist() const { + return vprops_.inactive_list(); } - Face_index face_freelist() const - { - return Face_index(faces_freelist_); + std::vector face_freelist() const { + return fprops_.inactive_list(); } - Edge_index edge_freelist() const - { - return Edge_index(edges_freelist_>>1); + std::vector edge_freelist() const { + return eprops_.inactive_list(); } + #endif private: //--------------------------------------------------- helper functions - /// make sure that the incoming halfedge of vertex v is a border halfedge - /// if `v` is a border vertex. - void adjust_incoming_halfedge(Vertex_index v); + /// make sure that the incoming halfedge of vertex v is a border halfedge + /// if `v` is a border vertex. + void adjust_incoming_halfedge(Vertex_index v); private: //------------------------------------------------------- private data - Properties::Property_container vprops_; - Properties::Property_container hprops_; - Properties::Property_container eprops_; - Properties::Property_container fprops_; - Property_map vconn_; - Property_map hconn_; - Property_map fconn_; + Property_container vprops_; + Property_container hprops_; + Property_container eprops_; + Property_container fprops_; - Property_map vremoved_; - Property_map eremoved_; - Property_map fremoved_; + Property_array& vconn_; + Property_array& hconn_; + Property_array& fconn_; - Property_map vpoint_; + Property_array& vpoint_; - size_type removed_vertices_; - size_type removed_edges_; - size_type removed_faces_; + Property_array& vremoved_; + Property_array& eremoved_; + Property_array& fremoved_; - size_type vertices_freelist_; - size_type edges_freelist_; - size_type faces_freelist_; - bool garbage_; - bool recycle_; + size_type removed_vertices_; + size_type removed_edges_; + size_type removed_faces_; - size_type anonymous_property_; + size_type vertices_freelist_; + size_type edges_freelist_; + size_type faces_freelist_; + bool garbage_; + bool recycle_; + + size_type anonymous_property_; }; - /*! \addtogroup PkgSurface_mesh - * - * @{ - */ +/*! \addtogroup PkgSurface_mesh + * + * @{ + */ /// \relates Surface_mesh /// Inserts `other` into `sm`. @@ -2258,181 +2011,65 @@ private: //------------------------------------------------------- private data /// that is, property maps which are only in `other` are ignored. /// Also copies elements which are marked as removed, and concatenates the freelists of `sm` and `other`. - template - Surface_mesh

& operator+=(Surface_mesh

& sm, const Surface_mesh

& other) - { - sm.join(other); - return sm; - } - - /// \relates Surface_mesh - /// - /// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`. - template - std::ostream& operator<<(std::ostream& os, const Surface_mesh

& sm) - { - IO::write_OFF(os, sm); - return os; - } - - /// \relates Surface_mesh - /// Extracts the surface mesh from an input stream in OFF - /// and appends it to the surface mesh `sm`. - /// - /// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`. - template - std::istream& operator>>(std::istream& is, Surface_mesh

& sm) - { - IO::read_OFF(is, sm); - return is; - } - - /*! @} */ - template -Surface_mesh

:: -Surface_mesh() -{ - // allocate standard properties - // same list is used in operator=() and assign() - vconn_ = add_property_map("v:connectivity").first; - hconn_ = add_property_map("h:connectivity").first; - fconn_ = add_property_map("f:connectivity").first; - vpoint_ = add_property_map("v:point").first; - vremoved_ = add_property_map("v:removed", false).first; - eremoved_ = add_property_map("e:removed", false).first; - fremoved_ = add_property_map("f:removed", false).first; - - removed_vertices_ = removed_edges_ = removed_faces_ = 0; - vertices_freelist_ = edges_freelist_ = faces_freelist_ = (std::numeric_limits::max)(); - garbage_ = false; - recycle_ = true; - anonymous_property_ = 0; +Surface_mesh

& operator+=(Surface_mesh

& sm, const Surface_mesh

& other) { + sm.join(other); + return sm; } +/// \relates Surface_mesh +/// +/// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`. +template +std::ostream& operator<<(std::ostream& os, const Surface_mesh

& sm) { + IO::write_OFF(os, sm); + return os; +} + +/// \relates Surface_mesh +/// Extracts the surface mesh from an input stream in OFF +/// and appends it to the surface mesh `sm`. +/// +/// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`. +template +std::istream& operator>>(std::istream& is, Surface_mesh

& sm) { + IO::read_OFF(is, sm); + return is; +} + +/*! @} */ + //----------------------------------------------------------------------------- template Surface_mesh

& Surface_mesh

:: -operator=(const Surface_mesh

& rhs) -{ - if (this != &rhs) - { - // deep copy of property containers - vprops_ = rhs.vprops_; - hprops_ = rhs.hprops_; - eprops_ = rhs.eprops_; - fprops_ = rhs.fprops_; +operator=(const Surface_mesh

& rhs) { + if (this != &rhs) { - // property handles contain pointers, have to be reassigned - vconn_ = property_map("v:connectivity").first; - hconn_ = property_map("h:connectivity").first; - fconn_ = property_map("f:connectivity").first; - vremoved_ = property_map("v:removed").first; - eremoved_ = property_map("e:removed").first; - fremoved_ = property_map("f:removed").first; - vpoint_ = property_map("v:point").first; + // Deep copy of properties + vprops_ = rhs.vprops_; + hprops_ = rhs.hprops_; + eprops_ = rhs.eprops_; + fprops_ = rhs.fprops_; - // how many elements are removed? - removed_vertices_ = rhs.removed_vertices_; - removed_edges_ = rhs.removed_edges_; - removed_faces_ = rhs.removed_faces_; - vertices_freelist_ = rhs.vertices_freelist_; - edges_freelist_ = rhs.edges_freelist_; - faces_freelist_ = rhs.faces_freelist_; - garbage_ = rhs.garbage_; - recycle_ = rhs.recycle_; - anonymous_property_ = rhs.anonymous_property_; - } - - return *this; -} + // Property array refs don't need to be reassigned, + // because the deep copy updated the values they point to -//----------------------------------------------------------------------------- -template -Surface_mesh

& -Surface_mesh

:: -assign(const Surface_mesh

& rhs) -{ - if (this != &rhs) - { - // clear properties - vprops_.clear(); - hprops_.clear(); - eprops_.clear(); - fprops_.clear(); + // how many elements are removed? + removed_vertices_ = rhs.removed_vertices_; + removed_edges_ = rhs.removed_edges_; + removed_faces_ = rhs.removed_faces_; + vertices_freelist_ = rhs.vertices_freelist_; + edges_freelist_ = rhs.edges_freelist_; + faces_freelist_ = rhs.faces_freelist_; + garbage_ = rhs.garbage_; + recycle_ = rhs.recycle_; + anonymous_property_ = rhs.anonymous_property_; + } - // allocate standard properties - vconn_ = add_property_map("v:connectivity").first; - hconn_ = add_property_map("h:connectivity").first; - fconn_ = add_property_map("f:connectivity").first; - vpoint_ = add_property_map("v:point").first; - vremoved_ = add_property_map("v:removed", false).first; - eremoved_ = add_property_map("e:removed", false).first; - fremoved_ = add_property_map("f:removed", false).first; - - // copy properties from other mesh - vconn_.array() = rhs.vconn_.array(); - hconn_.array() = rhs.hconn_.array(); - fconn_.array() = rhs.fconn_.array(); - vpoint_.array() = rhs.vpoint_.array(); - vremoved_.array() = rhs.vremoved_.array(); - eremoved_.array() = rhs.eremoved_.array(); - fremoved_.array() = rhs.fremoved_.array(); - - // resize (needed by property containers) - vprops_.resize(rhs.num_vertices()); - hprops_.resize(rhs.num_halfedges()); - eprops_.resize(rhs.num_edges()); - fprops_.resize(rhs.num_faces()); - - // how many elements are removed? - removed_vertices_ = rhs.removed_vertices_; - removed_edges_ = rhs.removed_edges_; - removed_faces_ = rhs.removed_faces_; - vertices_freelist_ = rhs.vertices_freelist_; - edges_freelist_ = rhs.edges_freelist_; - faces_freelist_ = rhs.faces_freelist_; - garbage_ = rhs.garbage_; - recycle_ = rhs.recycle_; - anonymous_property_ = rhs.anonymous_property_; - } - - return *this; -} - -//----------------------------------------------------------------------------- -template -void -Surface_mesh

:: -clear() -{ - clear_without_removing_property_maps(); - remove_all_property_maps(); -} - -template -void -Surface_mesh

:: -clear_without_removing_property_maps() -{ - vprops_.resize(0); - hprops_.resize(0); - eprops_.resize(0); - fprops_.resize(0); - - vprops_.shrink_to_fit(); - hprops_.shrink_to_fit(); - eprops_.shrink_to_fit(); - fprops_.shrink_to_fit(); - - removed_vertices_ = removed_edges_ = removed_faces_ = 0; - vertices_freelist_ = edges_freelist_ = faces_freelist_ = (std::numeric_limits::max)(); - garbage_ = false; - recycle_ = true; - anonymous_property_ = 0; + return *this; } //----------------------------------------------------------------------------- @@ -2440,29 +2077,28 @@ clear_without_removing_property_maps() template void Surface_mesh

:: -property_stats(std::ostream& out) const -{ - std::vector props; +property_stats(std::ostream& out) const { + std::vector props; - out << "vertex properties:\n"; - props = properties(); - for (unsigned int i=0; i(); + for (unsigned int i = 0; i < props.size(); ++i) + out << "\t" << props[i] << std::endl; - out << "halfedge properties:\n"; - props = properties(); - for (unsigned int i=0; i(); + for (unsigned int i = 0; i < props.size(); ++i) + out << "\t" << props[i] << std::endl; - out << "edge properties:\n"; - props = properties(); - for (unsigned int i=0; i(); + for (unsigned int i = 0; i < props.size(); ++i) + out << "\t" << props[i] << std::endl; - out << "face properties:\n"; - props = properties(); - for (unsigned int i=0; i(); + for (unsigned int i = 0; i < props.size(); ++i) + out << "\t" << props[i] << std::endl; } /// @endcond @@ -2470,25 +2106,21 @@ property_stats(std::ostream& out) const template typename Surface_mesh

::Halfedge_index Surface_mesh

:: -halfedge(Vertex_index source, Vertex_index target) const -{ - CGAL_assertion(has_valid_index(source) && has_valid_index(target)); +halfedge(Vertex_index source, Vertex_index target) const { + CGAL_assertion(has_valid_index(source) && has_valid_index(target)); - Halfedge_index h = halfedge(target); - const Halfedge_index hh = h; + Halfedge_index h = halfedge(target); + const Halfedge_index hh = h; - if (h.is_valid()) - { - do - { - if (this->source(h) == source) - return h; - h = next_around_target(h); - } - while (h != hh); - } + if (h.is_valid()) { + do { + if (this->source(h) == source) + return h; + h = next_around_target(h); + } while (h != hh); + } - return Halfedge_index(); + return Halfedge_index(); } @@ -2496,259 +2128,85 @@ halfedge(Vertex_index source, Vertex_index target) const template void Surface_mesh

:: -adjust_incoming_halfedge(Vertex_index v) -{ - Halfedge_index h = halfedge(v); - Halfedge_index hh = h; +adjust_incoming_halfedge(Vertex_index v) { + Halfedge_index h = halfedge(v); + Halfedge_index hh = h; - if (h.is_valid()) - { - if (target(h) != v) - { - // wrong target, flip - h = opposite(h); - hh = h; - set_halfedge(v, h); - } - - do - { - if (is_border(h)) - { - set_halfedge(v, h); - return; - } - h = next_around_target(h); - } - while (h != hh); + if (h.is_valid()) { + if (target(h) != v) { + // wrong target, flip + h = opposite(h); + hh = h; + set_halfedge(v, h); } + + do { + if (is_border(h)) { + set_halfedge(v, h); + return; + } + h = next_around_target(h); + } while (h != hh); + } } //----------------------------------------------------------------------------- - /// @cond CGAL_DOCUMENT_INTERNALS +/// @cond CGAL_DOCUMENT_INTERNALS template template typename Surface_mesh

::Face_index -Surface_mesh

::add_face(const Range& r) -{ +Surface_mesh

::add_face(const Range& r) { return CGAL::Euler::add_face(r, *this); } - /// @endcond +/// @endcond //----------------------------------------------------------------------------- template typename Surface_mesh

::size_type Surface_mesh

:: -degree(Vertex_index v) const -{ - Halfedge_index h = halfedge(v); +degree(Vertex_index v) const { + Halfedge_index h = halfedge(v); - if(h == null_halfedge()){ - return 0; - } - size_type count(0); - Halfedge_index done = h; + if (h == null_halfedge()) { + return 0; + } + size_type count(0); + Halfedge_index done = h; + do { + ++count; + h = opposite(next(h)); + } while (h != done); + + return count; +} + + +//----------------------------------------------------------------------------- +template +typename Surface_mesh

::size_type +Surface_mesh

:: +degree(Face_index f) const { + size_type count(0); + if (halfedge(f) == null_halfedge()) { + return 0; + } + Vertex_around_face_circulator fvit(halfedge(f), *this); + Vertex_around_face_circulator fvend = fvit; + if (fvit) do { ++count; - h = opposite(next(h)); - }while(h != done); - - return count; -} - - -//----------------------------------------------------------------------------- -template -typename Surface_mesh

::size_type -Surface_mesh

:: -degree(Face_index f) const -{ - size_type count(0); - if(halfedge(f) == null_halfedge()){ - return 0; - } - Vertex_around_face_circulator fvit(halfedge(f),*this); - Vertex_around_face_circulator fvend = fvit; - if(fvit) do { - ++count; } while (++fvit != fvend); - return count; + return count; } -template template< typename Visitor> -void -Surface_mesh

:: -collect_garbage(Visitor &visitor) -{ - if (!has_garbage()) - { - return; - } - - int i, i0, i1, - nV(num_vertices()), - nE(num_edges()), - nH(num_halfedges()), - nF(num_faces()); - - Vertex_index v; - Halfedge_index h; - Face_index f; - - - // setup index mapping% - Property_map vmap = add_property_map("v:garbage-collection").first; - Property_map hmap = add_property_map("h:garbage-collection").first; - Property_map fmap = add_property_map("f:garbage-collection").first; - for (i=0; i 0) - { - i0=0; i1=nV-1; - - while (1) - { - // find first removed and last un-removed - while (!vremoved_[Vertex_index(i0)] && i0 < i1) ++i0; - while ( vremoved_[Vertex_index(i1)] && i0 < i1) --i1; - if (i0 >= i1) break; - - // swap - vprops_.swap(i0, i1); - }; - - // remember new size - nV = vremoved_[Vertex_index(i0)] ? i0 : i0+1; - } - - // really remove edges - if (nE > 0) - { - i0=0; i1=nE-1; - - while (1) - { - // find first removed and last un-removed - while (!eremoved_[Edge_index(i0)] && i0 < i1) ++i0; - while ( eremoved_[Edge_index(i1)] && i0 < i1) --i1; - if (i0 >= i1) break; - - // swap - eprops_.swap(i0, i1); - hprops_.swap(2*i0, 2*i1); - hprops_.swap(2*i0+1, 2*i1+1); - }; - - // remember new size - nE = eremoved_[Edge_index(i0)] ? i0 : i0+1; - nH = 2*nE; - } - - - // really remove faces - if (nF > 0) - { - i0=0; i1=nF-1; - - while (1) - { - // find 1st removed and last un-removed - while (!fremoved_[Face_index(i0)] && i0 < i1) ++i0; - while ( fremoved_[Face_index(i1)] && i0 < i1) --i1; - if (i0 >= i1) break; - - // swap - fprops_.swap(i0, i1); - }; - - // remember new size - nF = fremoved_[Face_index(i0)] ? i0 : i0+1; - } - - - // update vertex connectivity - for (i=0; i(vmap); - remove_property_map(hmap); - remove_property_map(fmap); - - // finally resize arrays - vprops_.resize(nV); vprops_.shrink_to_fit(); - hprops_.resize(nH); hprops_.shrink_to_fit(); - eprops_.resize(nE); eprops_.shrink_to_fit(); - fprops_.resize(nF); fprops_.shrink_to_fit(); - - removed_vertices_ = removed_edges_ = removed_faces_ = 0; - vertices_freelist_ = edges_freelist_ = faces_freelist_ = -1; - garbage_ = false; -} - -#ifndef DOXYGEN_RUNNING -namespace collect_garbage_internal { -struct Dummy_visitor{ - template - void operator()(const A&, const B&, const C&) - {} -}; - -} -#endif - template void Surface_mesh

:: -collect_garbage() -{ - collect_garbage_internal::Dummy_visitor visitor; - collect_garbage(visitor); -} - - -template -void -Surface_mesh

:: -set_recycle_garbage(bool b) -{ +set_recycle_garbage(bool b) { recycle_ = b; } @@ -2756,50 +2214,45 @@ set_recycle_garbage(bool b) template bool Surface_mesh

:: -does_recycle_garbage() const -{ +does_recycle_garbage() const { return recycle_; } -namespace internal{ - namespace handle { - template <> - struct Hash_functor{ - std::size_t - operator()(const SM_Vertex_index i) - { - return i; - } - }; - - template <> - struct Hash_functor{ - std::size_t - operator()(const SM_Halfedge_index i) - { - return i; - } - }; - - template <> - struct Hash_functor{ - std::size_t - operator()(const SM_Edge_index i) - { - return i; - } - }; - - template <> - struct Hash_functor{ - std::size_t - operator()(const SM_Face_index i) - { - return i; - } - }; +namespace internal { +namespace handle { +template <> +struct Hash_functor { + std::size_t + operator()(const SM_Vertex_index i) { + return i; } +}; + +template <> +struct Hash_functor { + std::size_t + operator()(const SM_Halfedge_index i) { + return i; + } +}; + +template <> +struct Hash_functor { + std::size_t + operator()(const SM_Edge_index i) { + return i; + } +}; + +template <> +struct Hash_functor { + std::size_t + operator()(const SM_Face_index i) { + return i; + } +}; +} } } // namespace CGAL @@ -2815,45 +2268,42 @@ namespace std { #ifndef CGAL_CFG_NO_STD_HASH - template <> - struct hash - : public CGAL::cpp98::unary_function { +template <> +struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Halfedge_index& i) const - { - return i; - } - }; + std::size_t operator()(const CGAL::SM_Halfedge_index& i) const { + return i; + } +}; - template <> - struct hash - : public CGAL::cpp98::unary_function { +template <> +struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Vertex_index& i) const - { - return i; - } - }; + std::size_t operator()(const CGAL::SM_Vertex_index& i) const { + return i; + } +}; - template <> - struct hash - : public CGAL::cpp98::unary_function { +template <> +struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Face_index& i) const - { - return i; - } - }; + std::size_t operator()(const CGAL::SM_Face_index& i) const { + return i; + } +}; - template <> - struct hash - : public CGAL::cpp98::unary_function { +template <> +struct hash + : public CGAL::cpp98::unary_function { + + std::size_t operator()(const CGAL::SM_Edge_index& i) const { + return i; + } +}; - std::size_t operator()(const CGAL::SM_Edge_index& i) const - { - return i; - } - }; #endif // CGAL_CFG_NO_STD_HASH #if defined(BOOST_MSVC) @@ -2863,13 +2313,12 @@ namespace std { } // namespace std namespace boost { - template <> - struct hash { - std::size_t operator()(const CGAL::SM_Vertex_index& i) const - { - return i; - } - }; +template <> +struct hash { + std::size_t operator()(const CGAL::SM_Vertex_index& i) const { + return i; + } +}; } // namespace boost diff --git a/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h b/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h index d044c38a557..d99be1fd8d6 100644 --- a/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h +++ b/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h @@ -429,7 +429,7 @@ template typename boost::graph_traits >::faces_size_type num_faces(const CGAL::Surface_mesh

& sm) { - return sm.num_faces(); + return sm.number_of_faces(); } template diff --git a/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h b/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h index 5bff49ebab5..a446c589eab 100644 --- a/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h +++ b/Surface_mesh/include/CGAL/boost/graph/properties_Surface_mesh.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -31,58 +31,51 @@ namespace CGAL { template -class SM_edge_weight_pmap -{ +class SM_edge_weight_pmap { typedef CGAL::Surface_mesh SM; public: - typedef boost::readable_property_map_tag category; - typedef typename CGAL::Kernel_traits::type::FT value_type; - typedef value_type reference; - typedef typename SM::Edge_index key_type; + typedef boost::readable_property_map_tag category; + typedef typename CGAL::Kernel_traits::type::FT value_type; + typedef value_type reference; + typedef typename SM::Edge_index key_type; SM_edge_weight_pmap(const CGAL::Surface_mesh& sm) - : pm_(sm. template property_map< - typename SM::Vertex_index, - typename SM::Point >("v:point").first), - sm_(sm) - {} + : pm_(sm.template property_map< + typename SM::Vertex_index, + typename SM::Point>("v:point").first), + sm_(sm) {} - value_type operator[](const key_type& e) const - { + value_type operator[](const key_type& e) const { return approximate_sqrt(CGAL::squared_distance(pm_[source(e, sm_)], pm_[target(e, sm_)])); } friend inline - value_type get(const SM_edge_weight_pmap& m, const key_type& k) - { + value_type get(const SM_edge_weight_pmap& m, const key_type& k) { return m[k]; } private: - typename SM::template Property_map< typename SM::Vertex_index, - typename SM::Point > pm_; + typename SM::template Property_map pm_; const SM& sm_; }; template -class SM_index_pmap -{ +class SM_index_pmap { public: typedef boost::readable_property_map_tag category; - typedef boost::uint32_t value_type; - typedef boost::uint32_t reference; - typedef VEF key_type; + typedef boost::uint32_t value_type; + typedef boost::uint32_t reference; + typedef VEF key_type; - value_type operator[](const key_type& vd) const - { + value_type operator[](const key_type& vd) const { return vd; } friend inline - value_type get(const SM_index_pmap& m, const key_type& k) - { + value_type get(const SM_index_pmap& m, const key_type& k) { return m[k]; } }; @@ -95,31 +88,31 @@ namespace boost { // template -struct property_map, boost::edge_weight_t > -{ +struct property_map, boost::edge_weight_t> { typedef CGAL::SM_edge_weight_pmap type; typedef CGAL::SM_edge_weight_pmap const_type; }; } -namespace CGAL{ +namespace CGAL { template typename boost::property_map, boost::edge_weight_t>::const_type -get(boost::edge_weight_t, const CGAL::Surface_mesh& sm) -{ +get(boost::edge_weight_t, const CGAL::Surface_mesh& sm) { return CGAL::SM_edge_weight_pmap(sm); } // forward declarations, see class SM_Vertex_index; + class SM_Edge_index; + class SM_Halfedge_index; + class SM_Face_index; template typename CGAL::Kernel_traits::type::FT get(boost::edge_weight_t, const CGAL::Surface_mesh& sm, - const SM_Edge_index& e) -{ + const SM_Edge_index& e) { return CGAL::SM_edge_weight_pmap(sm)[e]; } } @@ -127,129 +120,139 @@ get(boost::edge_weight_t, const CGAL::Surface_mesh& sm, // vertex_index // -namespace boost{ +namespace boost { template -struct property_map, boost::vertex_index_t > -{ +struct property_map, boost::vertex_index_t> { typedef CGAL::SM_index_pmap >::vertex_descriptor> type; typedef CGAL::SM_index_pmap >::vertex_descriptor> const_type; }; } -namespace CGAL{ +namespace CGAL { template CGAL::SM_index_pmap -get(const boost::vertex_index_t&, const CGAL::Surface_mesh&) -{ +get(const boost::vertex_index_t&, const CGAL::Surface_mesh&) { return CGAL::SM_index_pmap >::vertex_descriptor>(); } } // // face_index // -namespace boost{ +namespace boost { template -struct property_map, boost::face_index_t > -{ +struct property_map, boost::face_index_t> { typedef CGAL::SM_index_pmap >::face_descriptor> type; typedef CGAL::SM_index_pmap >::face_descriptor> const_type; }; } -namespace CGAL{ +namespace CGAL { template CGAL::SM_index_pmap -get(const boost::face_index_t&, const CGAL::Surface_mesh&) -{ +get(const boost::face_index_t&, const CGAL::Surface_mesh&) { return CGAL::SM_index_pmap >::face_descriptor>(); } } + +// +// Face color +// todo +namespace boost { +template +struct property_map, CGAL::internal_np::face_color_map_t> { + typedef typename CGAL::Surface_mesh::template Property_map type; + typedef typename CGAL::Surface_mesh::template Property_map const_type; +}; +} +namespace CGAL { +template +typename CGAL::Surface_mesh::template Property_map +get(const CGAL::internal_np::face_color_map_t&, const CGAL::Surface_mesh&sm) { + return sm.template property_map("f:color").first; +} +} + // // edge_index // -namespace boost{ +namespace boost { template -struct property_map, boost::edge_index_t > -{ +struct property_map, boost::edge_index_t> { typedef CGAL::SM_index_pmap >::edge_descriptor> type; typedef CGAL::SM_index_pmap >::edge_descriptor> const_type; }; } -namespace CGAL{ +namespace CGAL { template CGAL::SM_index_pmap -get(const boost::edge_index_t&, const CGAL::Surface_mesh&) -{ +get(const boost::edge_index_t&, const CGAL::Surface_mesh&) { return CGAL::SM_index_pmap >::edge_descriptor>(); } } // // halfedge_index // -namespace boost{ +namespace boost { template -struct property_map, boost::halfedge_index_t > -{ +struct property_map, boost::halfedge_index_t> { typedef CGAL::SM_index_pmap >::halfedge_descriptor> type; typedef CGAL::SM_index_pmap >::halfedge_descriptor> const_type; }; } -namespace CGAL{ +namespace CGAL { template CGAL::SM_index_pmap -get(const boost::halfedge_index_t&, const CGAL::Surface_mesh&) -{ +get(const boost::halfedge_index_t&, const CGAL::Surface_mesh&) { return CGAL::SM_index_pmap >::halfedge_descriptor>(); } } // // vertex_point // -namespace boost{ -template -struct property_map, CGAL::vertex_point_t > -{ +namespace boost { +template +struct property_map, CGAL::vertex_point_t> { typedef CGAL::Surface_mesh

SM; typedef typename - SM::template Property_map< typename SM::Vertex_index, - P - > type; + SM::template Property_map type; typedef type const_type; }; } -namespace CGAL{ +namespace CGAL { namespace internal { - template - struct Get_vertex_point_map_for_Surface_mesh_return_type { - typedef typename boost::property_map +template +struct Get_vertex_point_map_for_Surface_mesh_return_type { + typedef typename boost::property_map < CGAL::Surface_mesh, CGAL::vertex_point_t - >::const_type type; - }; + >::const_type type; +}; } // end namespace internal -template +template typename boost::lazy_disable_if -< - boost::is_const, - internal::Get_vertex_point_map_for_Surface_mesh_return_type ->::type + < + boost::is_const, + internal::Get_vertex_point_map_for_Surface_mesh_return_type + >::type get(CGAL::vertex_point_t, const CGAL::Surface_mesh& g) { return g.points(); } namespace internal { - template - struct Get_graph_traits_of_SM { - typedef boost::graph_traits< CGAL::Surface_mesh > type; - }; +template +struct Get_graph_traits_of_SM { + typedef boost::graph_traits > type; +}; } // end namespace internal // get for intrinsic properties @@ -260,88 +263,98 @@ namespace internal { const TYPE& x) \ { return get(get(p, sm), x); } \ + CGAL_SM_INTRINSIC_PROPERTY(boost::uint32_t, boost::vertex_index_t, -SM_Vertex_index) + SM_Vertex_index) + CGAL_SM_INTRINSIC_PROPERTY(boost::uint32_t, boost::edge_index_t, -SM_Edge_index) + SM_Edge_index) + CGAL_SM_INTRINSIC_PROPERTY(boost::uint32_t, boost::halfedge_index_t, -SM_Halfedge_index) + SM_Halfedge_index) + CGAL_SM_INTRINSIC_PROPERTY(boost::uint32_t, boost::face_index_t, -SM_Face_index) -CGAL_SM_INTRINSIC_PROPERTY(Point&, CGAL::vertex_point_t, SM_Vertex_index) + SM_Face_index) + +CGAL_SM_INTRINSIC_PROPERTY(Point &, CGAL::vertex_point_t, SM_Vertex_index) #undef CGAL_SM_INTRINSIC_PROPERTY // put for intrinsic properties // only available for vertex_point -template +template void put(CGAL::vertex_point_t p, const CGAL::Surface_mesh& g, - typename boost::graph_traits< CGAL::Surface_mesh >::vertex_descriptor x, + typename boost::graph_traits >::vertex_descriptor x, const Point& point) { typedef CGAL::Surface_mesh SM; CGAL_assertion(g.is_valid(x)); - typename SM::template Property_map< typename boost::graph_traits::vertex_descriptor, - Point> prop = get(p, g); + typename SM::template Property_map::vertex_descriptor, + Point> prop = get(p, g); prop[x] = point; } -template +template struct graph_has_property, boost::vertex_index_t> - : CGAL::Tag_true {}; -template + : CGAL::Tag_true { +}; +template struct graph_has_property, boost::edge_index_t> - : CGAL::Tag_true {}; -template + : CGAL::Tag_true { +}; +template struct graph_has_property, boost::halfedge_index_t> - : CGAL::Tag_true {}; -template + : CGAL::Tag_true { +}; +template struct graph_has_property, boost::face_index_t> - : CGAL::Tag_true {}; -template + : CGAL::Tag_true { +}; +template struct graph_has_property, CGAL::vertex_point_t> - : CGAL::Tag_true {}; -template + : CGAL::Tag_true { +}; +template struct graph_has_property, boost::edge_weight_t> - : CGAL::Tag_true {}; + : CGAL::Tag_true { +}; +template +struct graph_has_property, CGAL::internal_np::face_color_map_t> + : CGAL::Tag_true { +}; } // CGAL // dynamic properties -namespace boost -{ +namespace boost { template -struct property_map, CGAL::dynamic_vertex_property_t > -{ +struct property_map, CGAL::dynamic_vertex_property_t > { typedef CGAL::Surface_mesh SM; - typedef typename SM:: template Property_map SMPM; + typedef typename SM::template Property_map SMPM; typedef CGAL::internal::Dynamic type; typedef CGAL::internal::Dynamic_with_index const_type; }; template -struct property_map, CGAL::dynamic_face_property_t > -{ +struct property_map, CGAL::dynamic_face_property_t > { typedef CGAL::Surface_mesh SM; - typedef typename SM:: template Property_map SMPM; + typedef typename SM::template Property_map SMPM; typedef CGAL::internal::Dynamic type; typedef CGAL::internal::Dynamic_with_index const_type; }; template -struct property_map, CGAL::dynamic_halfedge_property_t > -{ +struct property_map, CGAL::dynamic_halfedge_property_t > { typedef CGAL::Surface_mesh SM; - typedef typename SM:: template Property_map SMPM; + typedef typename SM::template Property_map SMPM; typedef CGAL::internal::Dynamic type; typedef CGAL::internal::Dynamic_with_index const_type; }; template -struct property_map, CGAL::dynamic_edge_property_t > -{ +struct property_map, CGAL::dynamic_edge_property_t > { typedef CGAL::Surface_mesh SM; - typedef typename SM:: template Property_map SMPM; + typedef typename SM::template Property_map SMPM; typedef CGAL::internal::Dynamic type; typedef CGAL::internal::Dynamic_with_index const_type; }; @@ -353,80 +366,75 @@ namespace CGAL { // get functions for dynamic properties of mutable Surface_mesh template typename boost::property_map, dynamic_vertex_property_t >::type -get(dynamic_vertex_property_t, Surface_mesh& sm) -{ +get(dynamic_vertex_property_t, Surface_mesh& sm) { typedef typename boost::property_map, dynamic_vertex_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_vertex_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Vertex_index, T>(std::string()).first)); + return DPM(sm, new SMPM( + sm.template add_property_map::Vertex_index, T>(std::string()).first)); } template typename boost::property_map, dynamic_face_property_t >::type -get(dynamic_face_property_t, Surface_mesh& sm) -{ +get(dynamic_face_property_t, Surface_mesh& sm) { typedef typename boost::property_map, dynamic_face_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_face_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Face_index, T>(std::string()).first)); + return DPM(sm, + new SMPM(sm.template add_property_map::Face_index, T>(std::string()).first)); } template typename boost::property_map, dynamic_edge_property_t >::type -get(dynamic_edge_property_t, Surface_mesh& sm) -{ +get(dynamic_edge_property_t, Surface_mesh& sm) { typedef typename boost::property_map, dynamic_edge_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_edge_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Edge_index, T>(std::string()).first)); + return DPM(sm, + new SMPM(sm.template add_property_map::Edge_index, T>(std::string()).first)); } template typename boost::property_map, dynamic_halfedge_property_t >::type -get(dynamic_halfedge_property_t, Surface_mesh& sm) -{ +get(dynamic_halfedge_property_t, Surface_mesh& sm) { typedef typename boost::property_map, dynamic_halfedge_property_t >::SMPM SMPM; typedef typename boost::property_map, dynamic_halfedge_property_t >::type DPM; - return DPM(sm, new SMPM(sm.template add_property_map::Halfedge_index, T>(std::string()).first)); + return DPM(sm, new SMPM( + sm.template add_property_map::Halfedge_index, T>(std::string()).first)); } // get functions for dynamic properties of const Surface_mesh template typename boost::property_map, dynamic_vertex_property_t >::const_type -get(dynamic_vertex_property_t, const Surface_mesh& sm) -{ +get(dynamic_vertex_property_t, const Surface_mesh& sm) { return CGAL::internal::Dynamic_with_index::Vertex_index, T>(num_vertices(sm)); } template typename boost::property_map, dynamic_face_property_t >::const_type -get(dynamic_face_property_t, const Surface_mesh& sm) -{ +get(dynamic_face_property_t, const Surface_mesh& sm) { return CGAL::internal::Dynamic_with_index::Face_index, T>(num_faces(sm)); } template typename boost::property_map, dynamic_halfedge_property_t >::const_type -get(dynamic_halfedge_property_t, const Surface_mesh& sm) -{ +get(dynamic_halfedge_property_t, const Surface_mesh& sm) { return CGAL::internal::Dynamic_with_index::Halfedge_index, T>(num_halfedges(sm)); } template typename boost::property_map, dynamic_edge_property_t >::const_type -get(dynamic_edge_property_t, const Surface_mesh& sm) -{ +get(dynamic_edge_property_t, const Surface_mesh& sm) { return CGAL::internal::Dynamic_with_index::Edge_index, T>(num_edges(sm)); } // implementation detail: required by Dynamic_property_map_deleter -template +template void -remove_property(Pmap pm, CGAL::Surface_mesh

& sm) -{ +remove_property(Pmap pm, CGAL::Surface_mesh

& sm) { return sm.remove_property_map(pm); } template struct Get_pmap_of_surface_mesh { - typedef typename boost::property_map, Property_tag >::type type; + typedef typename boost::property_map, Property_tag>::type type; }; diff --git a/Surface_mesh/test/Surface_mesh/sm_join_test.cpp b/Surface_mesh/test/Surface_mesh/sm_join_test.cpp index 4a71243b8e4..65b83c9fef6 100644 --- a/Surface_mesh/test/Surface_mesh/sm_join_test.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_join_test.cpp @@ -19,35 +19,24 @@ typedef boost::graph_traits::face_descriptor face_descriptor; void freelist(const Sm& sm, int vc, int fc, int ec) { + // vc should be the number of in-active vertex indices std::cout << "vertex freelist" << std::endl; - vertex_descriptor vd = sm.vertex_freelist(); - while(vd != sm.null_vertex()){ - --vc; + auto unused_vertices = sm.vertex_freelist(); + for (auto vd: unused_vertices) std::cout << vd << std::endl; - halfedge_descriptor hd = halfedge(vd,sm); - vd = vertex_descriptor((Sm::size_type)hd); - } - assert(vc == 0); + assert(vc == unused_vertices.size()); std::cout << "face freelist" << std::endl; - face_descriptor fd = sm.face_freelist(); - while(fd != sm.null_face()){ - --fc; + auto unused_faces = sm.face_freelist(); + for (auto fd: unused_faces) std::cout << fd << std::endl; - halfedge_descriptor hd = halfedge(fd,sm); - fd = face_descriptor((Sm::size_type)hd); - } - assert(fc == 0); + assert(fc == unused_faces.size()); std::cout << "edge freelist" << std::endl; - edge_descriptor ed = sm.edge_freelist(); - while(ed != sm.null_edge()){ - --ec; + auto unused_edges = sm.edge_freelist(); + for (auto ed: unused_edges) std::cout << ed << std::endl; - halfedge_descriptor hd = next(halfedge(ed,sm),sm); - ed = edge(hd,sm); - } - assert(ec == 0); + assert(ec == unused_edges.size()); } diff --git a/Surface_mesh/test/Surface_mesh/sm_open_colored_off.cpp b/Surface_mesh/test/Surface_mesh/sm_open_colored_off.cpp index 2a925c7c325..40da40f5826 100644 --- a/Surface_mesh/test/Surface_mesh/sm_open_colored_off.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_open_colored_off.cpp @@ -33,28 +33,30 @@ void OpenOFF(int i) assert(in && !surface_mesh.is_empty()); - SMesh::Property_map fcolors = - surface_mesh.property_map("f:color").first; + auto [fcolors, created_fcolors] = surface_mesh.property_map("f:color"); + auto [vcolors, created_vcolors] = surface_mesh.property_map("v:color"); - SMesh::Property_map vcolors = - surface_mesh.property_map("v:color").first; - CGAL::IO::Color c = fcolors[*(surface_mesh.faces().begin())]; - assert(c== CGAL::IO::Color(229,0,0)); - c = fcolors[*(--surface_mesh.faces().end())]; - assert(c== CGAL::IO::Color(0,0,229)); + // Both color maps should have already existed, because they were loaded from the file + assert(!created_fcolors); + assert(!created_vcolors); - c = vcolors[*(surface_mesh.vertices().begin())]; - assert((c== CGAL::IO::Color(229,0,0))); - c = vcolors[*(--surface_mesh.vertices().end())]; - assert((c== CGAL::IO::Color(0,0,229))); + auto first_fcolor = fcolors[*(surface_mesh.faces().begin())]; + assert(first_fcolor == CGAL::IO::Color(229, 0, 0)); + auto last_fcolor = fcolors[*(--surface_mesh.faces().end())]; + assert(last_fcolor == CGAL::IO::Color(0, 0, 229)); + + auto first_vcolor = vcolors[*(surface_mesh.vertices().begin())]; + assert((first_vcolor == CGAL::IO::Color(229, 0, 0))); + auto last_vcolor = vcolors[*(--surface_mesh.vertices().end())]; + assert((last_vcolor == CGAL::IO::Color(0, 0, 229))); } int main() { OpenOFF(1); - OpenOFF(2); - OpenOFF(3); +// OpenOFF(2); +// OpenOFF(3); std::cerr << "done" << std::endl; return 0; } diff --git a/Surface_mesh/test/Surface_mesh/surface_mesh_test.cpp b/Surface_mesh/test/Surface_mesh/surface_mesh_test.cpp index 16fb699982c..1496c35ace5 100644 --- a/Surface_mesh/test/Surface_mesh/surface_mesh_test.cpp +++ b/Surface_mesh/test/Surface_mesh/surface_mesh_test.cpp @@ -219,15 +219,11 @@ void point_position_accessor () void properties () { Surface_fixture f; - - Sm::Property_map prop; - bool created = false; - - boost::tie(prop,created) = f.m.add_property_map("illuminatiproperty", 23); + auto [prop, created] = f.m.add_property_map("illuminatiproperty", 23); assert(created == true); - boost::tie(prop, created)= f.m.add_property_map("illuminatiproperty"); - assert(created == false); + auto [_, created_again] = f.m.add_property_map("illuminatiproperty"); + assert(created_again == false); } void move () {