OpenMesh入門4(譯自OpenMesh6.3 Documents)

使用標準模板庫算法

由於OpenMesh迭代器(幾乎)是於標準模板庫(STL)迭代器一致的,因此,可以將標準模板庫的算法應用於mesh

下面的例子演示瞭如何使用標準模板庫中的for_each結構,而這種結構要比手寫循環高效的多。

我們將定義一個類,這個類提供mesh的光滑算法,然後定義一個可重用組件。由於STL中沒有類似於OpenMesh這樣的類,因此,我們要定義的這個類必須是模板類:

template <class Mesh> class SmootherT

SmootherT類有兩個函數,一個用於計算指定點單環領域節點的重心,第二個將節點位置設置爲相關的重心位置。仿函數是一種類似於operator()(...)形式的操作符重載函數。第一個仿函數ComputeCOG計算重心位置,並存儲於自定義屬性cog_中:

void operator()(consttypename Mesh::VertexHandle& _vh)

{

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.is_valid(); ++vv_it)

{

mesh_.property(cog_, _vh) += mesh_.point(*vv_it );

++valence;

}

mesh_.property(cog_, _vh ) /= valence;

}

注意:ComputeCOG函數需要訪問mesh對象及其屬性句柄。這兩者都是smoother對象的成員變量的引用。

第二個仿函數classSetCOG,用於設置節點位置,構造方法類似。

使用這些仿函數均實現了對標準模板庫中的std::for_each循環形式的應用。

void smooth(unsignedint _iterations)

{

for (unsignedint 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_));

}

}

完整代碼如下:

#include <algorithm>

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

#ifndef DOXY_IGNORE_THIS

template <class Mesh> class SmootherT

{

public:

typedeftypename 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(unsignedint _iterations)

{

for (unsignedint 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()(consttypename Mesh::VertexHandle& _vh)

{

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.is_valid(); ++vv_it)

{

mesh_.property(cog_, _vh) += mesh_.point(*vv_it );

++valence;

}

mesh_.property(cog_, _vh ) /= valence;

}

private:

Mesh& mesh_;

Property_cog& cog_;

};

class SetCOG

{

public:

SetCOG(Mesh& _mesh, Property_cog&_cog)

: mesh_(_mesh), cog_(_cog)

{}

void operator()(consttypename Mesh::VertexHandle& _vh)

{

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

}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章