CGAL 5.6 - Surface Mesh: User Manual
目录
Surface_mesh 类是半边数据结构的实现,可用来表示多面体表面。它是半边数据结构(Halfedge Data Structures)和三维多面体表面(3D Polyhedral Surface)这两个 CGAL 软件包的替代品。其主要区别在于它是基于索引的,而不是基于指针的。此外,向顶点、半边、边和面添加信息的机制要简单得多,而且是在运行时而不是编译时完成的。
由于数据结构使用整数索引作为顶点、半边、边和面的描述符,因此它的内存占用比基于指针的 64 位版本更少。由于索引是连续的,因此可用作存储属性的向量索引。
当元素被移除时,它们只会被标记为已移除,必须调用垃圾回收函数才能真正移除它们。
Surface_mesh 提供了四个嵌套类,分别代表半边数据结构的基本元素:
Surface_mesh::Vertex_index曲面网格::顶点索引
Surface_mesh::Halfedge_index曲面网格::半边索引
Surface_mesh::Face_index曲面网格::面索引
Surface_mesh::Edge_index曲面网格::边索引
1、新建Surface_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; //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));
m.add_face(u, v, w);
int num = num_faces(m); //结果num = 1
return 0;
}
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; //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
face_descriptor f = m.add_face(u, v, x);
if (f == Mesh::null_face())
{
std::cerr << "The face could not be added because of an orientation error." << std::endl;
//结果intersect = true; 即当前模型为自相交模型
bool intersect = CGAL::Polygon_mesh_processing::does_self_intersect(m);
std::cout << "intersect:"<< intersect << std::endl;
assert(f != Mesh::null_face());
f = m.add_face(u, x, v);
num = num_faces(m);
//结果intersect = true; 即当前模型为自相交模型
intersect = CGAL::Polygon_mesh_processing::does_self_intersect(m);
std::cout << "intersect:" << intersect << std::endl;
assert(f != Mesh::null_face());
}
std::cout << num << std::endl;
return 0;
}
3、获取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 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;
}
}
return 0;
}
4、获取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;
}
}
std::cout << "=====" << 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;
}
5、自定义点的名称
#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";
// 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;
}
注意一下boost::tie
`boost::tie`是Boost库中的一个实用函数,它用于将多个变量绑定到一个tuple(元组)的各个元素上。这使得你可以一次性从一个tuple中分别获取多个值,而不需要逐一访问每个元素。`boost::tie`在处理那些返回多个值的函数时特别有用,尤其是当这些值被打包成一个tuple或pair时。
让我们来详细解释一下`boost::tie`的作用和如何使用它:
### 基本概念
- **Tuple**:一个tuple是一个可以存储不同类型值的固定大小的容器。例如,一个`std::pair`可以被视为一个两元素的tuple。
- **绑定(Tie)**:绑定的概念是指将多个变量关联到一个复合对象(如tuple或pair)的不同部分。
### 使用`boost::tie`
在不使用`boost::tie`的情况下,如果你想从一个返回tuple或pair的函数中获取多个值,你通常需要创建一个tuple或pair变量,然后分别访问它的元素。例如:
```cpp
std::pair<int, bool> result = some_function();
int value = result.first;
bool flag = result.second;
```
使用`boost::tie`可以使这个过程更简洁:
```cpp
int value;
bool flag;
boost::tie(value, flag) = some_function();
```
在这个示例中,`some_function`返回一个包含两个元素的pair(或tuple)。使用`boost::tie`,你可以直接将这两个元素分别绑定到`value`和`flag`变量上。
### 在CGAL中的应用
在CGAL中,`boost::tie`常用于处理那些返回pair或tuple的函数。例如,`add_property_map`函数返回一个pair,包含创建的属性映射和一个布尔值,指示映射是否是新创建的。通过`boost::tie`,你可以直接将这两个值分别绑定到两个变量上:
```cpp
Mesh::Property_map<vertex_descriptor, std::string> name;
bool created;
boost::tie(name, created) = m.add_property_map<vertex_descriptor, std::string>("v:name", "");
```
这里,`name`被绑定到属性映射上,而`created`被绑定到布尔标志上,表明映射是否新创建。
总之,`boost::tie`是一种在C++中同时处理多个返回值的便捷方式,特别是当这些值被打包在一个tuple或pair中时。