Using iterators and circulators

xx.xx·2023년 8월 28일
3

오픈매쉬

목록 보기
2/5

open Mesh

Using iterators and circulators


iterators && circulators 는 메쉬의 모든 꼭지점 등을 선형으로 열거하고 꼭지점 주위를 순환하는 기능, 즉 모든 one-ring neighbors 열거하는 기능을 제공

삼각형 메시를 사용합니다.

#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
typedef  OpenMesh::TriMesh_ArrayKernelT<>   MyMesh;

vertices_begin(), v_end 정점 반복자를 사용하여 구현 가능합니다.

  for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)

현재 꼭지점의 one-ring neighbors 근처를 반복하는 코드

 MyMesh::VertexVertexIter    vv_it;
      for (vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)

vv_iter는 OpenMesh 라이브러리에서 제공하는 메소드 중 하나로, 주어진 정점의 이웃 정점들을 순회하는 데 사용되는 반복자(iterator)입니다. "vv"는 "vertex-vertex"의 약자로, 정점의 이웃 정점들을 나타냅니다. 이 반복자를 사용하여 정점의 이웃 정점들을 순회하고 조작할 수 있습니다.

Mesh::VertexVertexIter vv_it = mesh.vv_iter(v_handle);

Q.one-ring neighbor을 구하지 않아도 vv_it로 이웃 정점을 알 수 있는가?

A. OpenMesh에서 add_vertex로 정점을 추가하고, push_back(face_vhandle)로 면을 구성하면, 해당 정점의 one-ring neighborhood을 알 수 있습니다. (따로 구현하지 않아도 된다...!!!!!!!!!!!!!!!! OMG)

즉, add_vertex로 정점을 추가하면, 해당 정점의 Handle이 반환됩니다. 그리고 push_back(face_vhandle)로 면을 구성할 때, 면을 구성하는 정점들의 Handle을 사용하게 됩니다. 이러한 구성을 통해 정점과 면 간의 연결 관계가 형성되며, 이 정보를 기반으로 정점의 one-ring neighborhood를 파악할 수 있습니다.

정리하자면, add_vertex와 push_back(face_vhandle)를 사용하여 정점과 면을 구성하면, 각 정점의 주변 이웃 정점들을 해당 면들의 구성 정보를 통해 파악할 수 있습니다. 이것이 OpenMesh에서 one-ring neighborhood를 알아내는 방법 중 하나입니다.

Q. mesh.vv_iter.begin()으로 쓰면 안 되나요?

A. vv_iter는 반복자(iterator)가 아닌 메소드(method)입니다. 따라서 mesh.vv_iter.begin()과 같이 직접 .begin() 메소드를 호출할 수 없습니다.

vv_iter는 mesh.vv_iter(v_handle)와 같이 호출되어야 합니다. 이 메소드는 주어진 정점의 이웃 정점들을 순회하는 반복자(iterator)를 반환합니다. mesh.vv_iter(v_handle)와 같이 사용하여 반복자를 얻은 후, 해당 반복자를 사용하여 주변의 이웃 정점들을 순회하고 조작할 수 있습니다.

따라서 for (vv_it = mesh.vv_iter(v_handle); vv_it.is_valid(); ++vv_it)와 같이 메소드를 호출하여야 하며, 그렇게 해야 주변 이웃 정점을 순회할 수 있습니다.

각 정점의 무게 중심을 계산하고 이를 배열에 저장하는 코드

std::vector<MyMesh::Point>  cogs; //Center of Gravity는 MyMesh::Point 타입의 벡터

    for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) //메쉬의 모든 정점을 순회하기 위한 반복문, v_it는 정점을 가리키는 Iterator입니다.
    {
      cog[0] = cog[1] = cog[2] = valence = 0.0;
      // 각 정점에 대한 중심점 계산을 위해 초기화
	 // valence는 현재 정점의 이웃 정점 개수를 나타내는 변수
      
      for (vv_it=mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)// vv_it는 이웃 정점을 가리키는 Iterator
     {
     	cog += mesh.point( *vv_it );
        ++valence;
      }
      cogs.push_back(cog / valence);
    }

full code

#include <iostream>
#include <vector>
// -------------------- OpenMesh
#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;
  // 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 vector stores the computed centers of gravity
  std::vector<MyMesh::Point>  cogs;
  std::vector<MyMesh::Point>::iterator cog_it;
  cogs.reserve(mesh.n_vertices());
  // 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)
  {
    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 );
  }
  // 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;
}

0개의 댓글