使用标准的属性

正如我们已经看到的,我们可以通过属性将其他数据绑定到网格实体。 OpenMesh提供了一组所谓的标准属性。 与自定义属性不同,它们具有一些特殊功能和不同的界面。下表列出了所有可用的标准属性以及可以使用它的合适实体。

使用标准的属性

要向实体添加标准属性,只需使用适当的请求方法,例如request_face_normals()。 唯一的例外是位置(*)。 它无法添加,因为它永久可用,因此也无法删除。

在这个例子中我们将做如下工作:

  • 将顶点法线添加到网格对象
  • 加载文件
  • 检查文件是否提供顶点法线,否则计算它们
  • 沿着法线方向移动每个顶点一个单位长度
  • 将结果位置打印到std :: cout

让我们从向网格添加顶点法线开始:

使用标准的属性

以类似的方式,我们可以请求其他标准属性。 例如,面法线:

使用标准的属性

我们需要它们用update_normals()计算顶点法线,如果文件没有提供任何可用的信息。我们可以使用标准属性做更多事情。 我们可以验证网格是否已经具有属性顶点法线。

使用标准的属性

使用后我们再次删除它们

使用标准的属性

如果例如顶点状态属性已被请求两次会发生什么? 第一个版本什么都不做,但第二个版本将删除它。 标准属性有一个引用计数器,每个请求递增1,每个版本递减1。 如果计数器达到0,则属性将从内存中删除。

常用的申请属性与释放属性以及测试属性存在的函数

使用标准的属性

使用标准的属性

使用标准的属性

status属性用于标记几何元素,即选择或删除。

现在我们知道如何添加和删除标准属性,但我们如何访问它们? 我们再次需要网格对象。 与自定义属性不同,我们使用网格成员函数property()访问它,对于每个标准属性,网格提供了get和set方法。 我们在前三个教程中已经使用了一对get / set方法,我们计算了顶点位置的新位置。 在这里,我们沿着法线方向移动所有顶点的单位长度:使用标准的属性

get-methods接受实体句柄并返回所需属性的值,set-methods需要一个额外的参数来将新值传递给属性。 根据该表,并非每对get / set方法都适用于每个实体。 例如,face通常没有纹理坐标,因此在编译代码时调用mesh.texcoord2D(_face_handle)将导致错误。

具体的示例代码如下所示:

#include <iostream>
// --------------------
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
typedef OpenMesh::TriMesh_ArrayKernelT<>  MyMesh;
int main(int argc, char **argv)
{
  MyMesh  mesh;
  if (argc!=2)
  {
    std::cerr << "Usage: " << argv[0] << " <input>\n";
    return 1;
  }
  // request vertex normals, so the mesh reader can use normal information
  // if available
  mesh.request_vertex_normals();
  // assure we have vertex normals
  if (!mesh.has_vertex_normals())
  {
    std::cerr << "ERROR: Standard vertex property 'Normals' not available!\n";
    return 1;
  }
  OpenMesh::IO::Options opt;
  if ( ! OpenMesh::IO::read_mesh(mesh,argv[1], opt))
  {
    std::cerr << "Error loading mesh from file " << argv[1] << std::endl;
    return 1;
  }
  // If the file did not provide vertex normals, then calculate them
  if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) )
  {
    // we need face normals to update the vertex normals
    mesh.request_face_normals();
    // let the mesh update the normals
    mesh.update_normals();
    // dispose the face normals, as we don't need them anymore
    mesh.release_face_normals();
  }
  // move all vertices one unit length along it's normal direction
  for (MyMesh::VertexIter v_it = mesh.vertices_begin();
       v_it != mesh.vertices_end(); ++v_it)
  {
    std::cout << "Vertex #" << *v_it << ": " << mesh.point( *v_it );
    mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
    std::cout << " moved to " << mesh.point( *v_it ) << std::endl;
  }
  // don't need the normals anymore? Remove them!
  mesh.release_vertex_normals();
  // just check if it really works
  if (mesh.has_vertex_normals())
  {
    std::cerr << "Ouch! ERROR! Shouldn't have any vertex normals anymore!\n";
    return 1;
  }
  return 0;
}