This examples shows:
- How to use iterators,
- How to use circulators.
This example is the first version of the simple mesh smoother(光滑体). Here we will introduce iterators and circulators. These two concepts provide functionality to linearly enumerate(线性枚举) e.g. all vertices(顶点) of a mesh(网), and to circulate around a vertex, i.e. to enumerate all its one-ring neighbors. For a more detailed description, seeMesh Iterators and Circulators.
First we have to define the mesh type we want to use. This time we use a triangle mesh instead of a polygonal(多边形) mesh:
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
We read the mesh to be smoothed from a file:
One smoothing iteration is done in two steps:
- For each vertex: calculate the barycenter of its one-ring neighbors.
- For each vertex: move the vertex to the computed barycenter.
This can easily be implemented using vertex iterators. The mesh provides begin and end iterators by vertices_begin()
and vertices_end()
.
MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
For calculating the barycenter, we have to iterate through the one-ring neighborhood of the current vertex. This functionality is provided by theVertexVertexIter
:
for (vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
Now we can calculate the barycenters for each vertex and store them in the array cogs
:
std::vector<MyMesh::Point> cogs;
for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
{
cog[0] = cog[1] = cog[2] = valence = 0.0;
for (vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
{
cog += mesh.point( *vv_it );
++valence;
}
cogs.push_back(cog / valence);
}
After we have calculated the barycenters all that is left to do is to move the vertices to the corresponding barycenters. The complete source code is listed below.
#include <iostream>
#include <vector>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
int main(
int argc,
char **argv)
{
MyMesh mesh;
if (argc != 4)
{
std::cerr <<
"Usage: " << argv[0] <<
" #iterations infile outfile\n";
return 1;
}
{
std::cerr <<
"Error: Cannot read mesh from " << argv[2] << std::endl;
return 1;
}
std::vector<MyMesh::Point> cogs;
std::vector<MyMesh::Point>::iterator cog_it;
cogs.reserve(mesh.n_vertices());
MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
unsigned
int i, N(atoi(argv[1]));
for (i=0; i < N; ++i)
{
cogs.clear();
for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
{
cog[0] = cog[1] = cog[2] = valence = 0.0;
for (vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
{
cog += mesh.point( *vv_it );
++valence;
}
cogs.push_back(cog / valence);
}
for (v_it=mesh.vertices_begin(), cog_it=cogs.begin();
v_it!=v_end; ++v_it, ++cog_it)
if ( !mesh.is_boundary( *v_it ) )
mesh.set_point( *v_it, *cog_it );
}
{
std::cerr <<
"Error: cannot write mesh to " << argv[3] << std::endl;
return 1;
}
return 0;
}