- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

# Using STL algorithms

Since the OpenMesh iterators are (almost) conformant to STL iterators, one can apply the STL algorithms on meshes.

The following example shows how to use the STL `for_each` construct, since it is easier to read and may be more efficient than hand-written loops.

We will define a class which provides the smoothing algorithm, hence define a reusable component. The class must be template class because there is no such thing as a class OpenMesh, but many different types of OpenMesh:

    template <class Mesh> class SmootherT

The class SmootherT has two functors, one that computes the barycenter for a given vertex, and a second that sets the vertex position to the corresponding barycenter. A functor is simply a class with a function `operator()(...)`. The first functor `ComputeCOG` computes the barycenter and store it in a custom vertex property `cog_:`

        void operator()(typename Mesh::Vertex& _v)
        {
          typename Mesh::VertexHandle      vh( mesh_.handle(_v) );
          typename Mesh::VertexVertexIter  vv_it;
          typename Mesh::Scalar            valence(0.0);

          mesh_.property(cog_, vh) = typename Mesh::Point(0.0, 0.0, 0.0);

          for (vv_it=mesh_.vv_iter(vh); vv_it; ++vv_it)
          {
            mesh_.property(cog_, vh) += mesh_.point( vv_it );
            ++valence;
          }

          mesh_.property(cog_, mesh_.handle(_v) ) /= valence;
        }

Note, that `ComputeCOG` needs to have access to the mesh object and the property handle. Here, both are references to member variables of the smoother object.

The second functor `class` `SetCOG`, which sets the vertex position, is constructed analogical.

Using these functors and `std::for_each` from the STL the smoothing algorithm can be realized in a member function of `SmootherT:`

      void smooth(unsigned int _iterations)
      {
        for (unsigned int i=0; i < _iterations; ++i)
        {
          std::for_each(mesh_.vertices_begin(),
                        mesh_.vertices_end(),
                        ComputeCOG(mesh_, cog_));

          std::for_each(mesh_.vertices_begin(),
                        mesh_.vertices_end(),
                        SetCOG(mesh_, cog_));
        }
      }

The complete example looks like this:

    #include <algorithm>
    #include <OpenMesh/Core/Utils/Property.hh>

    #ifndef DOXY_IGNORE_THIS

    template <class Mesh> class SmootherT
    {
    public:

      typedef typename Mesh::Point            cog_t;
      typedef OpenMesh::VPropHandleT< cog_t > Property_cog;

    public:

      // construct with a given mesh
      SmootherT(Mesh& _mesh)
        : mesh_(_mesh)
      {
        mesh_.add_property( cog_ );
      }

      ~SmootherT()
      {
        mesh_.remove_property( cog_ );
      }

      // smooth mesh _iterations times
      void smooth(unsigned int _iterations)
      {
        for (unsigned int i=0; i < _iterations; ++i)
        {
          std::for_each(mesh_.vertices_begin(),
                        mesh_.vertices_end(),
                        ComputeCOG(mesh_, cog_));

          std::for_each(mesh_.vertices_begin(),
                        mesh_.vertices_end(),
                        SetCOG(mesh_, cog_));
        }
      }

    private:

      //--- private classes ---

      class ComputeCOG
      {
      public:
        ComputeCOG(Mesh& _mesh, Property_cog& _cog)
          : mesh_(_mesh), cog_(_cog)
        {}

        void operator()(typename Mesh::Vertex& _v)
        {
          typename Mesh::VertexHandle      vh( mesh_.handle(_v) );
          typename Mesh::VertexVertexIter  vv_it;
          typename Mesh::Scalar            valence(0.0);

          mesh_.property(cog_, vh) = typename Mesh::Point(0.0, 0.0, 0.0);

          for (vv_it=mesh_.vv_iter(vh); vv_it; ++vv_it)
          {
            mesh_.property(cog_, vh) += mesh_.point( vv_it );
            ++valence;
          }

          mesh_.property(cog_, mesh_.handle(_v) ) /= valence;
        }

      private:
        Mesh&         mesh_;
        Property_cog& cog_;
      };

      class SetCOG
      {
      public:
        SetCOG(Mesh& _mesh, Property_cog& _cog)
          : mesh_(_mesh), cog_(_cog)
        {}

        void operator()(typename Mesh::Vertex& _v)
        {
          typename Mesh::VertexHandle vh(mesh_.handle(_v));

          if (!mesh_.is_boundary(vh))
            mesh_.set_point( vh, mesh_.property(cog_, vh) );
        }

      private:

        Mesh&         mesh_;
        Property_cog& cog_;
      };

      //--- private elements ---

      Mesh&        mesh_;
      Property_cog cog_;
    };

    #endif

and

    #include <iostream>
    #include <vector>
    // -------------------- OpenMesh
    #include <OpenMesh/Core/IO/MeshIO.hh>
    #include <OpenMesh/Core/Mesh/Types/TriMesh_ArrayKernelT.hh>
    // --------------------
    #include "smooth_algo.hh"

    // ----------------------------------------------------------------------------

    #ifndef DOXY_IGNORE_THIS

    struct MyTraits : public OpenMesh::DefaultTraits
    {
      HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge);
    };

    #endif

    typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits>  MyMesh;

    // ----------------------------------------------------------------------------

    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;
      }

      // smoothing mesh argv[1] times
      SmootherT<MyMesh> smoother(mesh);
      smoother.smooth(atoi(argv[1]));

      // 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;
    }