【CGAL系列】---了解Surface_Mesh

前言:从今天起,小易开始分享关于CGAL相关的知识,主要是因为vtk库不满足需求,如果小伙伴跟我有同样的需求,那么我们一起学起来吧。

主要内容:该文收录在【CGAL系列】专栏中,主要讲解关于CGAL下的Surface_Mesh相关的创建、访问、检查等内容!目的主要是了解了Surface_Mesh的构造原理后,可以与其他数据类型进行相互转换,以及不同库之间的相互转换。

感谢各位小伙伴的点赞+关注,小易会继续分享,一起进步!

目录

CGAL的Kernel

Surface_Mesh

新建Mesh

检查方向(check orientation)

检查自相交

范围和迭代器

获取Surface_Mesh的所有点 

获取Surface_Mesh点、边、面的关联点

属性


CGAL的Kernel

在我们学习CGAL库时,首先要了解Kernel概念,它主要定义了三种精度的Kernel:

typedef CGAL::Simple_cartesian<double> K;

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;

typedef CGAL::Exact_predicates_exact_constructions_kernel K;

关于Kernel的详解,大家可以通过以下链接进行了解:

计算机图形学算法 CGAL计算精度Kernel 图形处理 二三维数据处理_哔哩哔哩_bilibili

 

Surface_Mesh

想要了解Surface_Mesh,首先需要了解CGAL中的BGL(Boost Graph Library)、半边(half edge)等概念,下面给出链接大家可以参考:

计算机图形学算法 CGAL BGL HalfedgeGraph Halfedge Surface_mesh PropertyMaps 图形处理 二三维数据处理_哔哩哔哩_bilibili

 CGAL 5.5.2 - 半边数据结构:用户手册

CGAL 5.5.2 - CGAL 和提升图形库:用户手册 

CGAL 5.5.2 - 表面网格:用户手册 

新建Mesh

数据结构:

#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组成的面构成的Mesh。

检查方向(check orientation)

  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都要求是非自相交的模型。现在来检查以下上述模型是否自相交

  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_around_target & halfedges_around_face

faces_around_target & faces_around_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;
}

感谢这小伙伴的点赞+关注,小易会继续分享,一起进步!

 

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪易

给我来点鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值