1 Introduction
半边数据结构(缩写为 HalfedgeDS,模板参数缩写为 HDS)是一种以边为中心的数据结构,能够维护顶点、边和面的入射信息,例如平面地图、多面体或其他嵌入任意维度的可定向二维曲面。每条边被分解成两个方向相反的半边。每个半边存储一个入射面和一个入射顶点。每个面和每个顶点都会存储一条入射半边。半边数据结构的简化变体可以省略其中一些信息,例如面中的半边指针或面的存储。
半边数据结构是一种组合数据结构,几何解释是由建立在半边数据结构之上的类添加的。这些类可能比直接使用半边数据结构更方便,因为半边数据结构只是一个实现层。请参见 "多面体表面 "一章中的 Polyhedron_3 类。
这里提供的数据结构也被称为 FE 结构 [9]、半边 [6]、[2] 或双连边列表 (DCEL) [3],尽管 DCEL [7] 的原始参考文献描述的是另一种数据结构。半边数据结构也可视为四边数据结构 [4] 的变种之一。一般来说,四边数据可以表示不可定向的 2-manifold,但这里的变体仅限于可定向的 2-manifold。关于这些不同数据结构的概述和比较,以及此处实现的设计的详尽描述,请参阅 [5]。
2 Software Design
图 26.1 以顶层的多面体_3 为例,说明了软件设计中三层的职责。项为实际存储的信息提供空间,即分别在顶点(Vertex)、半边(Halfedge)和面(Face)中使用成员变量和访问成员函数。半边需要提供对下一个半边和相对半边的引用。也可选择提供对上一个半边、入射顶点和入射面的引用。顶点和面可以是空的。也可以提供对入射半边的引用。半边数据结构和多面体都支持上述选项,例如,如果存在欧拉运算,欧拉运算会更新可选引用。此外,还可以用任意属性和成员函数扩展项类,这些属性和成员函数将通过继承的方式推广到多面体实际使用的类中。
顶点、半边和面作为 Items 类的局部类型传递给半边数据结构和多面体。为顶点、半边和面提供的实现满足要求中的强制部分。用户可将它们用作扩展的基类。此外,还提供了更丰富的实现作为默认设置;对于多面体,它们提供了所有可选的事件、顶点类型中的三维点和面型中的平面方程。
半边数据结构概念 HalfedgeDS 负责项目的存储组织。目前,我们提供了内部使用双向列表或向量的实现方式。HalfedgeDS 定义了属于项的句柄和迭代器。这些类型被推广到项目本身的声明中,并用于提供对事件项目的引用。类型的推广是通过项目类型的模板参数 Refs 来完成的。半边数据结构提供了插入和删除项、遍历所有项的成员函数,并提供了对项的访问权限。
HalfedgeDS 概念有两种不同的模型:HalfedgeDS_list 和 HalfedgeDS_vector,可能还会有更多。因此,我们将它们的接口保持在较小的范围内,并将常用功能分解成独立的辅助类 HalfedgeDS_decorator、HalfedgeDS_const_decorator 和 HalfedgeDS_items_decorator,图 26.1 中没有显示这些辅助类,但它们会被放在 HalfedgeDS 的边上,因为它们拓宽了接口,但并没有隐藏接口。这些辅助类包含的操作有助于实现下一层的操作,例如多面体。例如,它们添加了欧拉运算和部分运算,通过这些运算可以建立更多的欧拉运算,如在顶点的边环中插入一条边。此外,辅助类还包含自适应功能。例如,如果半边边没有提供 HalfedgeDSHalfedge::prev() 成员函数,那么辅助类的 HalfedgeDS_items_decorator::find_prev() 成员函数就会沿面的正方向搜索前一条半边边。但如果提供了 HalfedgeDSHalfedge::prev() 成员函数,HalfedgeDS_items_decorator::find_prev() 成员函数就会简单地调用它。这种区别在编译时通过一种叫做编译时标签的技术来解决,类似于 [8] 中的迭代器标签。
Polyhedron_3 是第三层示例,它通过添加几何解释、提供易于使用的高级函数界面并统一对下面的访问灵活性,使得使用更加方便。在这个示例中,面被重新命名为 "面"(facet),这在三维曲面中更为常见。该界面的设计旨在保护内部表示的完整性,用户不能直接写入存储在项中的句柄。Polyhedron_3 还添加了方便高效的循环器,用于访问顶点或面周围的循环边序列。为此,Polyhedron_3 从原有的项中派生出了新的顶点、半边和面。这些新项是 HalfedgeDS 中实际使用的项,从而保持了设计的类型结构的连贯性,特别是与之前的设计相比较。
3 Example Programs
3.1 The Default Halfedge Data Structure
下面的示例程序使用了默认的半边数据结构和装饰器类。默认的半边数据结构使用基于列表的表示法。定义了项的所有发生率和顶点的点类型。trivial traits 类提供了点的类型。程序将创建一个由两条半边、一个顶点和两个面组成的循环,并检查其有效性。
#include <CGAL/HalfedgeDS_default.h>
#include <CGAL/HalfedgeDS_decorator.h>
#include <cassert>
struct Traits { typedef int Point_2; };
typedef CGAL::HalfedgeDS_default<Traits> HDS;
typedef CGAL::HalfedgeDS_decorator<HDS> Decorator;
int main() {
HDS hds;
Decorator decorator(hds);
decorator.create_loop();
assert( decorator.is_valid());
return 0;
}
3.2 A Minimal Halfedge Data Structure
#include <CGAL/HalfedgeDS_min_items.h>
#include <CGAL/HalfedgeDS_default.h>
#include <CGAL/HalfedgeDS_decorator.h>
#include <cassert>
typedef CGAL::HalfedgeDS_default<int, CGAL::HalfedgeDS_min_items> HDS;
typedef CGAL::HalfedgeDS_decorator<HDS> Decorator;
int main() {
HDS hds;
Decorator decorator(hds);
decorator.create_loop();
assert(decorator.is_valid());
return 0;
}
3.3 The Default with a Vector Instead of a List
默认的半边数据结构内部使用一个列表和最大基类。这里我们将列表改为向量表示。同样,一个微不足道的特质类提供了用于点的类型。需要注意的是,对于矢量存储,半边数据结构的大小应事先预留,可以使用示例中的构造函数,也可以使用 reserve() 成员函数。以后可以通过进一步调用 reserve() 成员函数来调整数据结构的大小,但前提是数据结构处于一致状态,即有效状态。
#include <CGAL/HalfedgeDS_items_2.h>
#include <CGAL/HalfedgeDS_vector.h>
#include <CGAL/HalfedgeDS_decorator.h>
#include <cassert>
struct Traits {
typedef int Point_2;
};
typedef CGAL::HalfedgeDS_vector< Traits, CGAL::HalfedgeDS_items_2> HDS;
typedef CGAL::HalfedgeDS_decorator<HDS> Decorator;
int main() {
HDS hds(1, 2, 2);
Decorator decorator(hds);
decorator.create_loop();
assert(decorator.is_valid());
return 0;
}
CGAL 5.6 - Halfedge Data Structures: User Manual