【CGAL Series】---Understand Surface_Mesh

Foreword: Starting today, Xiaoyi began to share knowledge about CGAL, mainly because the vtk library does not meet the needs. If my friends have the same needs as me, then let's learn together.

Main content: This article is included in the [CGAL Series] column, mainly explaining the creation, access, inspection and other content related to Surface_Mesh under CGAL! The main purpose is that after understanding the construction principle of Surface_Mesh, it can be converted with other data types and converted between different libraries.

Thank you for your likes + attention, Xiaoyi will continue to share and make progress together!

Table of contents

Kernel of CGAL

Surface_Mesh

New Mesh

check orientation

Check for self-intersection

ranges and iterators

Get all points of Surface_Mesh 

Get the associated points of Surface_Mesh points, edges, and faces

Attributes


Kernel of CGAL

When we study the CGAL library, we must first understand the Kernel concept, which mainly defines three kinds of precision Kernel:

typedef CGAL::Simple_cartesian<double> K;

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;

typedef CGAL::Exact_predicates_exact_constructions_kernel K;

For the detailed explanation of Kernel, you can use the following link to learn about it:

Computer graphics algorithm CGAL calculation accuracy Kernel graphics processing 2D and 3D data processing_哔哩哔哩_bilibili

 

Surface_Mesh

To understand Surface_Mesh, you first need to understand concepts such as BGL (Boost Graph Library) and half edge (half edge) in CGAL. ​​The links below are for your reference:

Computer Graphics Algorithm CGAL BGL HalfedgeGraph Halfedge Surface_mesh PropertyMaps Graphics Processing 2D and 3D Data Processing_哔哩哔哩_bilibili

 CGAL 5.5.2 - Halfedge Data Structure: User's Manual

CGAL 5.5.2 - CGAL and Boost Graphics Library: User's Manual 

CGAL 5.5.2 - Surface Meshes: User's Manual 

New Mesh

data structure:

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

At this time, a new Mesh composed of surfaces composed of u, v, and w is created.

check orientation

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

  Question: Two faces are added, why only one face is obtained?

  Reason: Wrong orientation.

  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
  }

Refer to CGAL 5.5.2 - Surface Meshes: User Manual  Connectivity

Check for self-intersection

 In many algorithms, the input Mesh is required to be a non-self-intersecting model. Now let's check if the above model is self-intersecting as follows

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

Replace u,x,v with v,x,w and see the self-intersection result again.

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

ranges and iterators

Get all points of 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;
}

Get the associated points of Surface_Mesh points, edges, and faces

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

In addition: vertices_around_target gets associated points such as lines and points.

halfedges_around_target & halfedges_around_face

faces_around_target & faces_around_face

Attributes

Get point information and coordinates

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

 Another traversal method

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

Thank you for your likes + attention, Xiaoyi will continue to share and make progress together!

 

Guess you like

Origin blog.csdn.net/qq_40041064/article/details/131589994