From 8ece0770a37d12e6cc78c05f21dfb0b21cab3157 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Sun, 20 Dec 2015 23:07:54 +0100 Subject: [PATCH 1/4] Added a couple of methods to enable more efficient adding of batches of vertices. --- src/OpenMesh/Core/Mesh/ArrayKernel.hh | 14 ++++++++++++++ src/OpenMesh/Core/Mesh/BaseKernel.hh | 1 + src/OpenMesh/Core/Mesh/PolyMeshT.hh | 10 ++++++++++ src/OpenMesh/Core/Utils/PropertyContainer.hh | 17 +++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/src/OpenMesh/Core/Mesh/ArrayKernel.hh b/src/OpenMesh/Core/Mesh/ArrayKernel.hh index b83b2e1e..4bba2893 100644 --- a/src/OpenMesh/Core/Mesh/ArrayKernel.hh +++ b/src/OpenMesh/Core/Mesh/ArrayKernel.hh @@ -217,6 +217,14 @@ public: return handle(vertices_.back()); } + inline VertexHandle new_vertex_dirty() + { + vertices_.push_back(Vertex()); + vprops_resize_if_smaller(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + inline HalfedgeHandle new_edge(VertexHandle _start_vh, VertexHandle _end_vh) { // assert(_start_vh != _end_vh); @@ -479,6 +487,12 @@ public: StatusInfo& status(VertexHandle _vh) { return property(vertex_status_, _vh); } + void reset_status() { + PropertyT &status_prop = property(vertex_status_); + PropertyT::vector_type &sprop_v = status_prop.data_vector(); + std::fill(sprop_v.begin(), sprop_v.begin() + n_vertices(), StatusInfo()); + } + //----------------------------------------------------------- halfedge status const StatusInfo& status(HalfedgeHandle _hh) const { return property(halfedge_status_, _hh); } diff --git a/src/OpenMesh/Core/Mesh/BaseKernel.hh b/src/OpenMesh/Core/Mesh/BaseKernel.hh index 9c6d95af..9f2b7dbb 100644 --- a/src/OpenMesh/Core/Mesh/BaseKernel.hh +++ b/src/OpenMesh/Core/Mesh/BaseKernel.hh @@ -648,6 +648,7 @@ protected: //------------------------------------------- synchronize properties void vprops_reserve(size_t _n) const { vprops_.reserve(_n); } void vprops_resize(size_t _n) const { vprops_.resize(_n); } + void vprops_resize_if_smaller(size_t _n) const { if (vprops_.size() < _n) vprops_.resize(_n); } void vprops_clear() { vprops_.clear(); } diff --git a/src/OpenMesh/Core/Mesh/PolyMeshT.hh b/src/OpenMesh/Core/Mesh/PolyMeshT.hh index 9ea65535..b687d014 100644 --- a/src/OpenMesh/Core/Mesh/PolyMeshT.hh +++ b/src/OpenMesh/Core/Mesh/PolyMeshT.hh @@ -203,9 +203,19 @@ public: return vh; } + inline VertexHandle new_vertex_dirty(const Point& _p) + { + VertexHandle vh(Kernel::new_vertex_dirty()); + this->set_point(vh, _p); + return vh; + } + inline VertexHandle add_vertex(const Point& _p) { return new_vertex(_p); } + inline VertexHandle add_vertex_dirty(const Point& _p) + { return new_vertex_dirty(_p); } + // --- normal vectors --- /** \name Normal vector computation diff --git a/src/OpenMesh/Core/Utils/PropertyContainer.hh b/src/OpenMesh/Core/Utils/PropertyContainer.hh index 1b5ec1c1..662cc1ae 100644 --- a/src/OpenMesh/Core/Utils/PropertyContainer.hh +++ b/src/OpenMesh/Core/Utils/PropertyContainer.hh @@ -200,6 +200,22 @@ public: //---------------------------------------------------- synchronize properties +#if (_MSC_VER >= 1900 || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->reserve(_n); }); + } + + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->resize(_n); }); + } + + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), + [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); }); + } +#else void reserve(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), Reserve(_n)); } @@ -211,6 +227,7 @@ public: void swap(size_t _i0, size_t _i1) const { std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); } +#endif From 63985edd59be09af0356785d0842ab26e881c48a Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Fri, 8 Jan 2016 00:49:04 +0100 Subject: [PATCH 2/4] Fixed allocation bug. --- src/OpenMesh/Core/Mesh/BaseKernel.hh | 2 +- src/OpenMesh/Core/Utils/PropertyContainer.hh | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/Mesh/BaseKernel.hh b/src/OpenMesh/Core/Mesh/BaseKernel.hh index 9f2b7dbb..6370ae63 100644 --- a/src/OpenMesh/Core/Mesh/BaseKernel.hh +++ b/src/OpenMesh/Core/Mesh/BaseKernel.hh @@ -648,7 +648,7 @@ protected: //------------------------------------------- synchronize properties void vprops_reserve(size_t _n) const { vprops_.reserve(_n); } void vprops_resize(size_t _n) const { vprops_.resize(_n); } - void vprops_resize_if_smaller(size_t _n) const { if (vprops_.size() < _n) vprops_.resize(_n); } + void vprops_resize_if_smaller(size_t _n) const { vprops_.resize_if_smaller(_n); } void vprops_clear() { vprops_.clear(); } diff --git a/src/OpenMesh/Core/Utils/PropertyContainer.hh b/src/OpenMesh/Core/Utils/PropertyContainer.hh index 662cc1ae..6af6efe5 100644 --- a/src/OpenMesh/Core/Utils/PropertyContainer.hh +++ b/src/OpenMesh/Core/Utils/PropertyContainer.hh @@ -211,6 +211,11 @@ public: [_n](BaseProperty* p) { if (p) p->resize(_n); }); } + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p && p->n_elements() < _n) p->resize(_n); }); + } + void swap(size_t _i0, size_t _i1) const { std::for_each(properties_.begin(), properties_.end(), [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); }); @@ -224,6 +229,10 @@ public: std::for_each(properties_.begin(), properties_.end(), Resize(_n)); } + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n)); + } + void swap(size_t _i0, size_t _i1) const { std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); } @@ -290,6 +299,13 @@ private: size_t n_; }; + struct ResizeIfSmaller + { + ResizeIfSmaller(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p && _p->n_elements() < n_) _p->resize(n_); } + size_t n_; + }; + struct ClearAll { ClearAll() {} From 3868b351ec031802ec67c52fa16c9e41a66969f5 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 24 Mar 2016 12:58:43 +0100 Subject: [PATCH 3/4] Added a whole bunch of doxygen documentation. --- src/OpenMesh/Core/Mesh/ArrayKernel.hh | 46 +++++++++++++++----- src/OpenMesh/Core/Mesh/BaseKernel.hh | 14 ++++++ src/OpenMesh/Core/Mesh/PolyMeshT.hh | 26 ++++++++++- src/OpenMesh/Core/Utils/PropertyContainer.hh | 40 +++++++++++++++++ 4 files changed, 115 insertions(+), 11 deletions(-) diff --git a/src/OpenMesh/Core/Mesh/ArrayKernel.hh b/src/OpenMesh/Core/Mesh/ArrayKernel.hh index 4bba2893..388c9267 100644 --- a/src/OpenMesh/Core/Mesh/ArrayKernel.hh +++ b/src/OpenMesh/Core/Mesh/ArrayKernel.hh @@ -209,6 +209,15 @@ public: public: + /** + * \brief Add a new vertex. + * + * If you are rebuilding a mesh that you previously erased using clean() or + * clean_keep_reservation() you probably want to use new_vertex_dirty() + * instead. + * + * \sa new_vertex_dirty() + */ inline VertexHandle new_vertex() { vertices_.push_back(Vertex()); @@ -217,6 +226,16 @@ public: return handle(vertices_.back()); } + /** + * Same as new_vertex() but uses PropertyContainer::resize_if_smaller() to + * resize the vertex property container. + * + * If you are rebuilding a mesh that you erased with clean() or + * clean_keep_reservation() using this method instead of new_vertex() saves + * reallocation and reinitialization of property memory. + * + * \sa new_vertex() + */ inline VertexHandle new_vertex_dirty() { vertices_.push_back(Vertex()); @@ -302,23 +321,26 @@ public: std_API_Container_FHandlePointer& fh_to_update, bool _v=true, bool _e=true, bool _f=true); - /** \brief Clear the whole mesh - * - * This will remove all properties and elements from the mesh - */ + /// \brief Does the same as clean() and in addition erases all properties. void clear(); - /** \brief Reset the whole mesh + /** \brief Remove all vertices, edges and faces and deallocates their memory. * - * This will remove all elements from the mesh but keeps the properties + * In contrast to clear() this method does neither erases the properties + * nor clears the property vectors. Depending on how you add any new entities + * to the mesh after calling this method, your properties will be initialized + * with old values. + * + * \sa clean_keep_reservation() */ void clean(); - /** \brief Reset the whole mesh + /** \brief Remove all vertices, edges and faces but keep memory allocated. * - * This will remove all elements from the mesh but keeps the properties. - * In contrast to clean() the memory used for the elements will remain - * allocated. + * This method behaves like clean() (also regarding the properties) but + * leaves the memory used for vertex, edge and face storage allocated. This + * leads to no reduction in memory consumption but allows for faster + * performance when rebuilding the mesh. */ void clean_keep_reservation(); @@ -487,6 +509,10 @@ public: StatusInfo& status(VertexHandle _vh) { return property(vertex_status_, _vh); } + /** + * Reinitializes the status of all vertices using the StatusInfo default + * constructor, i.e. all flags will be set to false. + */ void reset_status() { PropertyT &status_prop = property(vertex_status_); PropertyT::vector_type &sprop_v = status_prop.data_vector(); diff --git a/src/OpenMesh/Core/Mesh/BaseKernel.hh b/src/OpenMesh/Core/Mesh/BaseKernel.hh index 6370ae63..9a452916 100644 --- a/src/OpenMesh/Core/Mesh/BaseKernel.hh +++ b/src/OpenMesh/Core/Mesh/BaseKernel.hh @@ -646,12 +646,26 @@ public: //----------------------------------------------------- element numbers protected: //------------------------------------------- synchronize properties + /// Reserves space for \p _n elements in all vertex property vectors. void vprops_reserve(size_t _n) const { vprops_.reserve(_n); } + + /// Resizes all vertex property vectors to the specified size. void vprops_resize(size_t _n) const { vprops_.resize(_n); } + + /** + * Same as vprops_resize() but ignores vertex property vectors that have + * a size larger than \p _n. + * + * Use this method instead of vprops_resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ void vprops_resize_if_smaller(size_t _n) const { vprops_.resize_if_smaller(_n); } + void vprops_clear() { vprops_.clear(); } + void vprops_swap(unsigned int _i0, unsigned int _i1) const { vprops_.swap(_i0, _i1); } diff --git a/src/OpenMesh/Core/Mesh/PolyMeshT.hh b/src/OpenMesh/Core/Mesh/PolyMeshT.hh index b687d014..04e87def 100644 --- a/src/OpenMesh/Core/Mesh/PolyMeshT.hh +++ b/src/OpenMesh/Core/Mesh/PolyMeshT.hh @@ -192,10 +192,21 @@ public: Use them to assign two meshes of \b equal type. If the mesh types vary, use PolyMeshT::assign() instead. */ - // --- creation --- + // --- creation --- + + /** + * \brief Adds a new default-initialized vertex. + * + * \sa new_vertex(const Point&), new_vertex_dirty() + */ inline VertexHandle new_vertex() { return Kernel::new_vertex(); } + /** + * \brief Adds a new vertex initialized to a custom position. + * + * \sa new_vertex(), new_vertex_dirty() + */ inline VertexHandle new_vertex(const Point& _p) { VertexHandle vh(Kernel::new_vertex()); @@ -203,6 +214,17 @@ public: return vh; } + /** + * Same as new_vertex(const Point&) but never shrinks, only enlarges the + * vertex property vectors. + * + * If you are rebuilding a mesh that you erased with ArrayKernel::clean() or + * ArrayKernel::clean_keep_reservation() using this method instead of + * new_vertex(const Point &) saves reallocation and reinitialization of + * property memory. + * + * \sa new_vertex(const Point &) + */ inline VertexHandle new_vertex_dirty(const Point& _p) { VertexHandle vh(Kernel::new_vertex_dirty()); @@ -210,9 +232,11 @@ public: return vh; } + /// Alias for new_vertex(const Point&). inline VertexHandle add_vertex(const Point& _p) { return new_vertex(_p); } + /// Alias for new_vertex_dirty(). inline VertexHandle add_vertex_dirty(const Point& _p) { return new_vertex_dirty(_p); } diff --git a/src/OpenMesh/Core/Utils/PropertyContainer.hh b/src/OpenMesh/Core/Utils/PropertyContainer.hh index 6af6efe5..53584bb2 100644 --- a/src/OpenMesh/Core/Utils/PropertyContainer.hh +++ b/src/OpenMesh/Core/Utils/PropertyContainer.hh @@ -200,39 +200,79 @@ public: //---------------------------------------------------- synchronize properties +/* + * In C++11 an beyond we can introduce more efficient and more legible + * implementations of the following methods. + */ #if (_MSC_VER >= 1900 || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + /** + * Reserves space for \p _n elements in all property vectors. + */ void reserve(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), [_n](BaseProperty* p) { if (p) p->reserve(_n); }); } + /** + * Resizes all property vectors to the specified size. + */ void resize(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), [_n](BaseProperty* p) { if (p) p->resize(_n); }); } + /** + * Same as resize() but ignores property vectors that have a size larger + * than \p _n. + * + * Use this method instead of resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ void resize_if_smaller(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), [_n](BaseProperty* p) { if (p && p->n_elements() < _n) p->resize(_n); }); } + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ void swap(size_t _i0, size_t _i1) const { std::for_each(properties_.begin(), properties_.end(), [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); }); } #else + /** + * Reserves space for \p _n elements in all property vectors. + */ void reserve(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), Reserve(_n)); } + /** + * Resizes all property vectors to the specified size. + */ void resize(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), Resize(_n)); } + /** + * Same as \sa resize() but ignores property vectors that have a size + * larger than \p _n. + * + * Use this method instead of \sa resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ void resize_if_smaller(size_t _n) const { std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n)); } + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ void swap(size_t _i0, size_t _i1) const { std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); } From 2592f8322a91e203a3cc1c808455eaef0a001b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Thu, 24 Mar 2016 13:10:28 +0100 Subject: [PATCH 4/4] Updated Changelog --- Doc/changelog.docu | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/changelog.docu b/Doc/changelog.docu index 56f07847..820466d7 100644 --- a/Doc/changelog.docu +++ b/Doc/changelog.docu @@ -9,6 +9,11 @@ 6.0 (?/?/?) +Core +
    +
  • Added a couple of methods to enable more efficient adding of batches of vertices (Without resizing property vectors)
  • +
+ IO
  • Obj reader: added texCoord3d functions to objloader