From 82708a3533fa6172e42b585f91a69b5a3221950f Mon Sep 17 00:00:00 2001 From: Janis Born Date: Fri, 30 Nov 2018 20:13:37 +0100 Subject: [PATCH] update custom properties tutorial to use PropertyManager and the new factory functions --- Doc/Tutorial/03-properties/smooth.cc | 114 ++++++++++++--------------- Doc/tutorial_03.docu | 83 ++++++++++++------- 2 files changed, 103 insertions(+), 94 deletions(-) diff --git a/Doc/Tutorial/03-properties/smooth.cc b/Doc/Tutorial/03-properties/smooth.cc index 8756c492..11866db7 100644 --- a/Doc/Tutorial/03-properties/smooth.cc +++ b/Doc/Tutorial/03-properties/smooth.cc @@ -1,74 +1,58 @@ -#include -#include -// -------------------- #include #include +#include -typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh; +#include +#include +using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>; -int main(int argc, char **argv) +int main(int argc, char** argv) { - MyMesh mesh; - - - // check command line options - if (argc != 4) - { - std::cerr << "Usage: " << argv[0] << " #iterations infile outfile\n"; - return 1; - } - - - - // read mesh from stdin - if ( ! OpenMesh::IO::read_mesh(mesh, argv[2]) ) - { - std::cerr << "Error: Cannot read mesh from " << argv[2] << std::endl; - return 1; - } - - - - // this vertex property stores the computed centers of gravity - OpenMesh::VPropHandleT cogs; - mesh.add_property(cogs); - - // smoothing mesh argv[1] times - MyMesh::VertexIter v_it, v_end(mesh.vertices_end()); - MyMesh::VertexVertexIter vv_it; - MyMesh::Point cog; - MyMesh::Scalar valence; - unsigned int i, N(atoi(argv[1])); - - - for (i=0; i < N; ++i) - { - for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) - { - mesh.property(cogs,*v_it).vectorize(0.0f); - valence = 0.0; - - for (vv_it=mesh.vv_iter( *v_it ); vv_it; ++vv_it) - { - mesh.property(cogs,*v_it) += mesh.point( *vv_it ); - ++valence; - } - mesh.property(cogs,*v_it) /= valence; + // Read command line options + MyMesh mesh; + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " #iterations infile outfile" << std::endl; + return 1; } + const int iterations = argv[1]; + const std::string infile = argv[2]; + const std::string outfile = argv[3]; - for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) - if ( !mesh.is_boundary( *v_it ) ) - mesh.set_point( *v_it, mesh.property(cogs,*v_it) ); - } - - - // write mesh to stdout - if ( ! OpenMesh::IO::write_mesh(mesh, argv[3]) ) - { - std::cerr << "Error: cannot write mesh to " << argv[3] << std::endl; - return 1; - } - - return 0; + // Read mesh file + if (!OpenMesh::IO::read_mesh(mesh, infile)) { + std::cerr << "Error: Cannot read mesh from " << infile << std::endl; + return 1; + } + + { + // Add a vertex property storing the computed centers of gravity + auto cog = OpenMesh::makeTemporaryProperty(mesh); + + // Smooth the mesh several times + for (int i = 0; i < iterations; ++i) { + // Iterate over all vertices to compute centers of gravity + for (const auto& vh : mesh.vertices()) { + cog[vv] = {0,0,0}; + int valence = 0; + // Iterate over all 1-ring vertices around vh + for (const auto& vvh : mesh.vv_range(vh)) { + cog[vv] += mesh.point(vvh); + ++valence; + } + cog[vv] /= valence; + } + // Move all vertices to the previously computed positions + for (const auto& vh : mesh.vertices()) { + mesh.point(vv) = cog[vv]; + } + } + // The cog vertex property is removed from the mesh at the end of this scope + } + + // Write mesh file + if (!OpenMesh::IO::read_mesh(mesh, outfile)) { + std::cerr << "Error: Cannot write mesh to " << outfile << std::endl; + return 1; + } } diff --git a/Doc/tutorial_03.docu b/Doc/tutorial_03.docu index 7d8fb228..9333b210 100644 --- a/Doc/tutorial_03.docu +++ b/Doc/tutorial_03.docu @@ -1,7 +1,7 @@ /** \page tutorial_03 Using (custom) properties This examples shows: -- How to add and remove custom properties, +- How to add and remove custom properties - How to get and set the value of a custom property In the last example we computed the barycenter of each vertex' @@ -11,44 +11,69 @@ let %OpenMesh manage the data. It would be even more helpful if we could attach such properties dynamically to the mesh. -%OpenMesh provides dynamic properties, which can be attached to each -mesh entity (vertex, face, edge, halfedge, and the mesh itself). We -distinguish between custom and standard properties. A custom property -is any user-defined property and is accessed via the member function -\c property(..) via a handle and an entity handle -(e.g. VertexHandle). Whereas the standard properties are accessed via -special member functions, e.g. the vertex position is accessed with \c -point(..) and a vertex handle. +Custom properties can be conveniently created and attached to meshes with the following functions: +- makeTemporaryProperty() creates a property that is temporary to the current scope. +- getOrMakeProperty() is used for creating and accessing permanent named properties on a mesh. +- getProperty() is used for accessing an existing permanent named property on a mesh. -In this example we will store the \c cog-value (see previous example) -in an additional vertex property instead of keeping it in a separate -array. To do so we define first a so-called property handle with the desired -type (\c MyMesh::Point) and register the handle at the mesh: +All three functions take two template arguments: +- First, the type of the mesh element that the property is attached to (i.e. OpenMesh::VertexHandle, OpenMesh::HalfedgeHandle, OpenMesh::EdgeHandle, or OpenMesh::FaceHandle). +- Second, the type of the property value that is attached to each element (e.g., \p int, \p double, etc.). + +All three functions return a handle object (of type PropertyManager) that manages the lifetime of the property and provides read / write access to its values. + +In this example, we will store the \c cog value (see previous example) in a vertex property instead of keeping it in a separate array. +To do so, we first add a (temporary) property of the desired element type (OpenMesh::VertexHandle) and value type (\c %MyMesh::Point) to the mesh: \dontinclude 03-properties/smooth.cc -\skipline vertex property stores -\until mesh.add +\skipline makeTemporaryProperty -
The \c mesh allocates enough memory to hold as many elements of type -\c MyMesh::Point as number of vertices exist, and of course the mesh -synchronizes all insert and delete operations on the vertices with the -vertex properties. +Enough memory is allocated to hold as many values of \c %MyMesh::Point as there are vertices. +All insert and delete operations on the mesh are synchronized with the attached properties. -Once the wanted property is registered we can use the property to -calculate the barycenter of the neighborhood of each vertex \c v_it +Once the property is created, we can use it to compute the centers of the neighborhood of each vertex: -\dontinclude 03-properties/smooth.cc -\skipline vv_it= +\skipline mesh.vertices +\until cog[vv] /= valence \until } -\until mesh.prop -
and finally set the new position for each vertex \c v_it +Finally, we set the new position for each vertex: -\dontinclude 03-properties/smooth.cc -\skipline mesh.set_point +\skipline mesh.vertices +\until mesh.point +\until } + +--- + +Since we chose to use makeTemporaryProperty(), the created property is automatically removed from the mesh as soon as we leave the scope of the associated handle variable \c cog. + +If, instead, a property is desired to survive its local scope, it should be created with using getOrMakeProperty(). In that case, the property must be given a name that can later be used to retrieve the property. For example: + +\code + auto face_area = OpenMesh::makeTemporaryProperty(mesh, 'face_area'); +\endcode + +At a later time, we can use the getProperty() function to obtain a handle to a property that was previously created by refering to its name: +\code + try { + auto face_area = OpenMesh::getProperty(mesh, 'face_area'); + // Use the face_area property. + } + catch (const std::runtime_error& e) { + // Property not found. Handle the error here. + } +\endcode + +--- + +The functions makeTemporaryProperty(), getOrMakeProperty(), and getProperty() are the convenient high-level interface for creating and accessing mesh properties. + +Beneath these convenience functions, there is also a low-level property interface where handle and property lifetime must be managed manually. This interface is accessed through a mesh's add_property(), remove_property(), and property() functions and several property handle classes (OpenMesh::VPropHandleT, OpenMesh::HPropHandleT, OpenMesh::EPropHandleT, OpenMesh::FPropHandleT, OpenMesh::MPropHandleT). + +--- -
Below is the complete source code: +Below is the complete source code: \include 03-properties/smooth.cc -*/ \ No newline at end of file +*/ -- GitLab