【Серия CGAL】 --- Понимание Surface_Mesh

Предисловие: С сегодняшнего дня Xiaoyi начал делиться знаниями о CGAL, в основном потому, что библиотека vtk не соответствует потребностям.Если у моих друзей такие же потребности, как у меня, то давайте учиться вместе.

Основное содержание: эта статья включена в колонку [Серия CGAL], в основном объясняющая создание, доступ, проверку и другой контент, связанный с Surface_Mesh в рамках CGAL! Основная цель состоит в том, что после понимания принципа построения Surface_Mesh его можно преобразовать с другими типами данных и преобразовать между различными библиотеками.

Спасибо за ваши лайки + внимание, Сяойи будет продолжать делиться и вместе добиваться прогресса!

Оглавление

Ядро CGAL

Surface_Mesh

Новая сетка

проверить ориентацию

Проверить на самопересечение

диапазоны и итераторы

Получить все точки Surface_Mesh 

Получите связанные точки точек, ребер и граней Surface_Mesh

Атрибуты


Ядро CGAL

Когда мы изучаем библиотеку CGAL, мы должны сначала понять концепцию ядра, которая в основном определяет три вида точности ядра:

typedef CGAL::Simple_cartesian<double> K;

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;

typedef CGAL::Exact_predicates_exact_constructions_kernel K;

Для подробного объяснения ядра вы можете использовать следующую ссылку, чтобы узнать о нем:

Алгоритм компьютерной графики Точность расчета CGAL Обработка ядерной графики Обработка 2D и 3D данных_哔哩哔哩_bilibili

 

Surface_Mesh

Чтобы понять Surface_Mesh, вам сначала нужно понять такие понятия, как BGL (библиотека Boost Graph) и половина ребра (half edge) в CGAL. ​​Ссылки ниже приведены для справки:

Алгоритм компьютерной графики CGAL BGL HalfedgeGraph Halfedge Surface_mesh PropertyMaps Обработка графики 2D и 3D Data Processing_哔哩哔哩_bilibili

 CGAL 5.5.2 - Структура данных Halfedge: Руководство пользователя

CGAL 5.5.2 - CGAL и графическая библиотека Boost: руководство пользователя 

CGAL 5.5.2 — Поверхностные сетки: руководство пользователя 

Новая сетка

структура данных:

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>

typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;

int main()
{
  Mesh m;

  // Add the points as vertices
  vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
  vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor w = m.add_vertex(K::Point_3(1,1,0));
  vertex_descriptor x = m.add_vertex(K::Point_3(1,0,0));

  m.add_face(u,v,w);
  int num = num_faces(m); //结果num = 1

  return 0;
}

В это время создается новая сетка, состоящая из поверхностей, состоящих из u, v и w.

проверить ориентацию

  face_descriptor f = m.add_face(u,v,x);
  num = num_faces(m); //结果num = 1

  Вопрос: Добавляются две грани, почему получается только одна грань?

  Причина: Неправильная ориентация.

  if(f == Mesh::null_face())
  {
    std::cerr<<"The face could not be added because of an orientation error."<<std::endl;
    f = m.add_face(u,x,v);
    num = num_faces(m);//num = 2
  }

См. CGAL 5.5.2 — Поверхностные сетки: Руководство  пользователя

Проверить на самопересечение

 Во многих алгоритмах требуется, чтобы входная сетка была несамопересекающейся моделью. Теперь давайте проверим, является ли приведенная выше модель самопересекающейся, следующим образом.

  Mesh m;

  // Add the points as vertices
  vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
  vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor w = m.add_vertex(K::Point_3(1,1,0));
  vertex_descriptor x = m.add_vertex(K::Point_3(1,0,0));

  m.add_face(u,v,w);
  int num = num_faces(m);
  face_descriptor f = m.add_face(u,v,x);
  num = num_faces(m);
  if(f == Mesh::null_face())
  {
    std::cerr<<"The face could not be added because of an orientation error."<<std::endl;
    f = m.add_face(u,x,v);
    num = num_faces(m);

    //结果intersect = true; 即当前模型为自相交模型
    bool intersect = CGAL::Polygon_mesh_processing::does_self_intersect(m);
    assert(f != Mesh::null_face());
  }

Замените u,x,v на v,x,w и снова посмотрите на результат самопересечения.

  Mesh m;

  // Add the points as vertices
  vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
  vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor w = m.add_vertex(K::Point_3(1,1,0));
  vertex_descriptor x = m.add_vertex(K::Point_3(1,0,0));

  m.add_face(u,v,w);
  int num = num_faces(m);
  face_descriptor f = m.add_face(u,v,x);
  num = num_faces(m);
  if(f == Mesh::null_face())
  {
    std::cerr<<"The face could not be added because of an orientation error."<<std::endl;
    f = m.add_face(v, x, w);
    num = num_faces(m);    

    bool intersect = CGAL::Polygon_mesh_processing::does_self_intersect(m);
    //结果 intersect = false;
    assert(f != Mesh::null_face());
  }

диапазоны и итераторы

Получить все точки Surface_Mesh 

#include <vector>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>

typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
  Mesh m;

  // u            x
  // +------------+
  // |            |
  // |            |
  // |      f     |
  // |            |
  // |            |
  // +------------+
  // v            w

  // Add the points as vertices
  vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
  vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor w = m.add_vertex(K::Point_3(1,0,0));
  vertex_descriptor x = m.add_vertex(K::Point_3(1,1,0));

  /* face_descriptor f = */ m.add_face(u,v,w,x);

  {
    std::cout << "all vertices " << std::endl;

    // The vertex iterator type is a nested type of the Vertex_range
    Mesh::Vertex_range::iterator  vb, ve;

    Mesh::Vertex_range r = m.vertices();
    // The iterators can be accessed through the C++ range API
    vb = r.begin();
    ve = r.end();
    // or the boost Range API
    vb = boost::begin(r);
    ve = boost::end(r);

    // or with boost::tie, as the CGAL range derives from std::pair
    for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb){
            std::cout << *vb << std::endl;
    }

    // Instead of the classical for loop one can use
    // the boost macro for a range
    for(vertex_descriptor vd : m.vertices()){
      std::cout << vd << std::endl;
    }

    // or the C++11 for loop. Note that there is a ':' and not a ',' as in BOOST_FOREACH
    for(vertex_descriptor vd : m.vertices()){
      std::cout << vd << std::endl;
    }

  }

  return 0;
}

Получите связанные точки точек, ребер и граней Surface_Mesh

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>

#include <vector>

typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;

int main()
{
  Mesh m;

  // u            x
  // +------------+
  // |            |
  // |            |
  // |      f     |
  // |            |
  // |            |
  // +------------+
  // v            w

  // Add the points as vertices
  vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
  vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor w = m.add_vertex(K::Point_3(1,0,0));
  vertex_descriptor x = m.add_vertex(K::Point_3(1,1,0));

  face_descriptor f = m.add_face(u,v,w,x);

  {
    std::cout << "vertices around vertex " << v << std::endl;
    CGAL::Vertex_around_target_circulator<Mesh> vbegin(m.halfedge(v),m), done(vbegin);

    do {
      std::cout << *vbegin++ << std::endl;
    } while(vbegin != done);
  }

  {
    std::cout << "vertices around face " << f << std::endl;
    CGAL::Vertex_around_face_iterator<Mesh> vbegin, vend;
    for(boost::tie(vbegin, vend) = vertices_around_face(m.halfedge(f), m);
        vbegin != vend;
        ++vbegin){
      std::cout << *vbegin << std::endl;
    }
  }

  // or the same again, but directly with a range based loop
  for(vertex_descriptor vd : vertices_around_face(m.halfedge(f), m)){
    std::cout << vd << std::endl;
  }


  return 0;
}

Кроме того: vertices_around_target получает связанные точки, такие как линии и точки.

halfedges_round_target и halfedges_around_face

Faces_round_target и Faces_round_face

Атрибуты

Получить информацию о точке и координаты

#include <string>

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>

typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;

int main()
{
  Mesh m;
  vertex_descriptor v0 = m.add_vertex(K::Point_3(0,2,0));
  vertex_descriptor v1 = m.add_vertex(K::Point_3(2,2,0));
  vertex_descriptor v2 = m.add_vertex(K::Point_3(0,0,0));
  vertex_descriptor v3 = m.add_vertex(K::Point_3(2,0,0));
  vertex_descriptor v4 = m.add_vertex(K::Point_3(1,1,0));
  m.add_face(v3, v1, v4);
  m.add_face(v0, v4, v1);
  m.add_face(v0, v2, v4);
  m.add_face(v2, v3, v4);


  // give each vertex a name, the default is empty
  Mesh::Property_map<vertex_descriptor,std::string> name;
  bool created;
  boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
  assert(created);
  // add some names to the vertices
  name[v0] = "hello";
  name[v2] = "world";

  {
    // You get an existing property, and created will be false
    Mesh::Property_map<vertex_descriptor,std::string> name;
    bool created;
    boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name", "");
    assert(! created);
  }

  //  You can't get a property that does not exist
  Mesh::Property_map<face_descriptor,std::string> gnus;
  bool found;
  boost::tie(gnus, found) = m.property_map<face_descriptor,std::string>("v:gnus");
  assert(! found);

  // retrieve the point property for which exists a convenience function
  Mesh::Property_map<vertex_descriptor, K::Point_3> location = m.points();
  for(vertex_descriptor vd : m.vertices()) {
    std::cout << name[vd] << " @ " << location[vd] << std::endl;
  }

  std::vector<std::string> props = m.properties<vertex_descriptor>();
  for(std::string p : props){
    std::cout << p << std::endl;
  }

  // delete the string property again
  m.remove_property_map(name);

  return 0;
}

 Другой метод обхода

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>

#include <CGAL/Polygon_mesh_processing/bbox.h>

#include <iostream>

typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point_3;

namespace My {

  struct Mesh: public CGAL::Surface_mesh<Point_3> {
    typedef CGAL::Surface_mesh<Point_3> Base;
    std::string name;
  };

} // namespace My


#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My::Mesh
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME CGAL::Surface_mesh<::Point_3>
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>

int main()
{
  My::Mesh mesh;
  CGAL::make_triangle(Point_3(0,0,0), Point_3(1,0,0), Point_3(1,1,1), mesh);
  typedef boost::graph_traits<My::Mesh>::vertex_descriptor vertex_descriptor;

  typedef boost::property_map<My::Mesh,CGAL::vertex_point_t>::type Point_property_map;
  Point_property_map ppm = get(CGAL::vertex_point, mesh);

  for(vertex_descriptor vd : vertices(mesh)){
    if (vd != boost::graph_traits<My::Mesh>::null_vertex()){
      std::cout << vd << " at " << get(ppm, vd) << std::endl;
    }
  }
  std::cout << CGAL::Polygon_mesh_processing::bbox(mesh) << std::endl;

  return 0;
}

Спасибо за ваши лайки + внимание, Сяойи будет продолжать делиться и вместе добиваться прогресса!

 

Supongo que te gusta

Origin blog.csdn.net/qq_40041064/article/details/131589994
Recomendado
Clasificación