update custom properties tutorial to use PropertyManager and the new factory functions
This commit is contained in:
@@ -1,74 +1,58 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
// --------------------
|
||||
#include <OpenMesh/Core/IO/MeshIO.hh>
|
||||
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
|
||||
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||
|
||||
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
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<MyMesh::Point> 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];
|
||||
|
||||
// Read mesh file
|
||||
if (!OpenMesh::IO::read_mesh(mesh, infile)) {
|
||||
std::cerr << "Error: Cannot read mesh from " << infile << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
{
|
||||
// Add a vertex property storing the computed centers of gravity
|
||||
auto cog = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, MyMesh::Point>(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
<br>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
|
||||
|
||||
<br>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 }
|
||||
|
||||
<br>Below is the complete source code:
|
||||
---
|
||||
|
||||
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<OpenMesh::FaceHandle, double>(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<OpenMesh::FaceHandle, double>(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:
|
||||
|
||||
\include 03-properties/smooth.cc
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user