CGAL的2D三角剖分

CGAL的2D三角剖分_第1张图片

         本章介绍了CGAL的二维三角剖分。定义部分回顾了关于三角剖分的主要定义。表示部分讨论了二维三角剖分在CGAL中的表示方式。软件设计部分介绍了二维三角剖分包的总体软件设计。接下来的部分介绍了CGAL中可用的不同二维三角剖分类:基本三角剖分(基本三角剖分部分)、Delaunay三角剖分(Delaunay三角剖分部分)、规则三角剖分(规则三角剖分部分)、约束三角剖分(约束三角剖分部分)和约束Delaunay三角剖分(约束Delaunay三角剖分部分)。上述需要认真了解的只用Delaunay三角剖分,其他三角剖分算法,目前可找到的文献较少。

        具有约束和子约束之间双向映射的约束三角剖分部分描述了一个类,该类实现了一个约束或约束Delaunay三角剖分,并使用一个额外的数据结构来描述约束是如何被三角剖分的边细化的。三角剖分层次一节描述了用于快速点位置查询的分层数据结构。最后,灵活性一节解释了用户如何使用定制的面和顶点类从CGAL图形库的灵活性中受益。

1、定义

        单形和复形是拓扑几何中的概念,其中单形是一种由仿射无关的顶点组构成的几何图形,而复形则是由单形构建的更复杂的几何图形。

        具体来说,单形是由仿射无关的顶点组构成的几何图形,其中包括点、线段、三角形等。单形的边界算子决定了定向和奇偶性,即通过去掉一个定点,得到的顶点组依旧是仿射无关的,并且可以构成一个更低维度的单形。

        而复形是由单形构建的更复杂的几何图形,通过将多个单形组合在一起,形成一个整体的几何形状。复形的构建可以不受度量的限制,只考虑形状的拓扑性质。例如,一个复形可以表示一个物体的表面,而单形则是构成该表面的小块几何图形。

        在三角剖分中,奇点指的是在三角形的外接圆内,除了三角形顶点以外的其他点。这些点破坏了三角形的空圆性质,即一个三角形(或边)的外接圆范围内(边界除外),不包含点集P中的任何顶点。

        二维三角剖分可以大致描述为三角面片的集合T,使得:两个面要么不相交,要么共享一个较低维度的面(边或顶点)。T中的一组面按邻接关系连接。作为T中面交集的域UT没有奇点。

        更确切地说,三角剖分可以被描述为单形复形。让我们先记录一些定义。单形复形是单形的集合T,使得T中任何单形面都是T中的单形、T中的两个单形要么不相交,要么共享一个共同的子面(边)。

        单形复体的维数d是其单形的最大维数。单纯复形T是纯的,如果T的任何单形都包含在具有最大维数的T的单形中。

        如果两个最大维数为d的T中的单形共享一个d-1维子面,则它们被称为相邻。如果邻接关系定义了最大维数T的单形集合上的连通图,则单形复形是连通的。

        三角形的连通性是指三角形中任意两点之间是否存在一条路径,使得这两点之间的路径上没有任何其他点。如果存在这样的路径,则称三角形是连通的。

        在三角剖分中,连通性是指任何两个三角形顶点之间是否存在一条边连接它们。如果存在这样的边,则称这两个三角形是连通的。

        T中所有单形的并UT称为T的域。如果T的域中的点p在UT中的周围既不是拓扑球也不是拓扑圆盘,则称其为奇点。然后,二维三角剖分可以被描述为纯的、连通的、没有奇点的二维单纯复形。

        在三角剖分中,奇点指的是在三角形的外接圆内,除了三角形顶点以外的其他点。这些点破坏了三角形的空圆性质,即一个三角形(或边)的外接圆范围内(边界除外),不包含点集P中的任何顶点。

        三角剖分的每个面都可以给出一个方向,这反过来又诱导了与该面相交的边的方向。如果两个相邻面的方向在它们共同的相交边上是相反的,则这两个相邻面的方向是一致的。如果三角剖分的每个面的方向都可以这样选择,即所有成对的相交面都有一致的方向,则该三角剖分是可定向的。

        CGAL中的Triangulation类可以用于处理二维和三维的三角剖分。CGAL中的Triangulation类允许用户表示任何可定向二维三角剖分的组合,而不需要边界。在这个数据结构之上,二维三角剖分类负责三角剖分的几何嵌入,并被设计用于处理平面三角剖分。三角剖分的平面可以嵌入到更高维的空间中。

       CGAL 的三角剖分是完整的三角剖分,这意味着它们的域是它们的顶点的凸包。由于任何平面三角剖分都可以完成,这不是一个真正的限制。例如,多边形区域的三角剖分可以构造并表示为约束三角剖分的一个子集,其中区域边界边被输入为约束边(参见“约束三角剖分”,“约束Delaunay三角剖分”和“约束三角剖分,约束与子约束之间双向映射”)。

        严格来说,术语面应该用于设计任何尺寸的面,三角形剖分的二维面应该被正确地称为小平面。但是,根据常见的用法,我们以后经常将面称为二维三角剖分的面。

2、表示

2.1、面集合

       CGAL的2D三角剖分可以被视为一个平面分区,其有界面是三角形,覆盖了顶点集的凸包。这个分区的单个无界面是凸包的补集。在许多应用中,如Kirkpatrick的层次结构或增量Delaunay构造,只处理三角形面很方便。因此,一个名为无限顶点的虚拟顶点被添加到三角剖分中,以及与之相关的无限边和无限面。每个无限边都与无限顶点和凸包的一个顶点相交。每个无限面都与无限顶点和凸包的一个边相交。

        因此,三角剖分的每个边都恰好与两个面相交,三角剖分的面集在拓扑上等价于二维球面。

        请注意,无穷顶点没有重要的坐标,并且不能对它或无穷面应用几何谓词。

CGAL的2D三角剖分_第2张图片

        这延伸到退化情况下或当三角剖分具有少于三个顶点时出现的低维三角剖分。包括无限面,一维三角剖分是一个边缘和顶点环,拓扑上等价于一个1-球体。零维三角剖分,其域被简化为一个点,由两个顶点表示,拓扑上等价于一个0-球体。下图是具有零个、一个和两个有限顶点的三角形。

CGAL的2D三角剖分_第3张图片

2.2、基于面和顶点的表示

        由于三角剖分是一组具有恒定复杂度的三角形面,因此三角剖分不是作为平面地图之上的一个层来实现的。Cgal使用基于面和顶点而不是边的三角剖分的适当内部表示。这种表示节省了存储空间,并导致了更快的算法。

        表示的基本元素是顶点和面。每个三角形面都可以访问它的三个入射顶点和它的三个相邻面。每个顶点都可以访问它的一个入射面,并通过该面访问它的入射面的循环列表。

        面的三个顶点索引按逆时针顺序用0、1和2。面的邻居索引也用0、1、2,这样由i索引的邻居与具有相同索引的顶点相对。参见下图,该图所示的函数ccw(i)和cw(i)分别计算i+1和i-1模3。

        边缘不是显式表示的,它们只是通过两个面的邻接关系隐式表示的。每条边都有两个隐式表示:与索引为i的顶点相对的面f的边,可以表示为f的邻居(i)的边。

CGAL的2D三角剖分_第4张图片

3、软件设计

      CGAL的三角剖分类提供了高级几何功能,例如三角剖分中点的位置、插入、删除或位移。它们被构建为称为三角剖分数据结构的数据结构之上的层。三角剖分数据结构可以被视为三角剖分面和顶点的容器。这个数据结构还负责三角剖分的所有组合方面。

        几何方面和组合部分之间的这种分离在软件设计中反映为三角剖分类具有两个模板参数的事实:

        第一个参数代表一个几何特征类,提供三角剖分的几何基元(点、线段和三角形)以及对这些对象的基本操作(谓词或构造)。

        第二个参数代表三角剖分数据结构类。三角剖分数据结构的概念在《二维三角剖分数据结构》一章的概念部分进行了描述。三角剖分数据结构定义了用于表示三角剖分面和顶点的类型,以及用于访问和访问面和顶点的其他类型(句柄、迭代器和循环器)。

        CGAL提供了类 Triangulation_data_structure_2 作为三角剖分数据结构的默认模型。类 Triangulation_data_structure_2有两个模板参数,分别代表一个顶点类和一个面类。CGAL为这些模板参数定义了概念,并为这些概念提供了默认模型。顶点和基类由几何特征类模板化,使其能够获得三角剖分的几何基元的一些知识。这些默认的顶点和面基类可以由用户自定义的基类替换,例如,为了处理附加到三角剖分的顶点或面的附加属性。有关如何利用这种灵活性的更多详细信息,请参阅“灵活性”一节。

        总结了三角剖分包的设计,展示了构成该包的三层(基类、三角剖分据结构和三角剖分)。

CGAL的2D三角剖分_第5张图片

        负责三角剖分的几何嵌入的顶层三角剖分级别根据不同类型的三角剖分而有所不同:基本三角剖分、Delaunay三角剖分、规则三角剖分、约束三角剖分或约束Delaunay三角剖分。每种三角剖分对应于不同的类。下图总结了CGAL2D三角剖分类的派生依赖关系。任何2D三角剖分类都由几何特征类和三角剖分数据结构参数化。虽然唯一的概念TriangulationDataStructure_2描述了任何三角剖分类的三角剖分数据结构要求,但几何特征类的要求实际上取决于三角剖分类。一般来说,顶点和面基类要求由基本概念TriangulationVertexBase_2和TriangulationFaceBase_2描述。然而,一些三角剖分类要求基类实现基本概念的细化。 

CGAL的2D三角剖分_第6张图片

4、基础三角剖分

4.1、描述

        类Triangulation_2是其他二维三角剖分类的基类,实现了三角剖分的用户接口。

        三角剖分的顶点和面通过句柄、迭代器和循环器访问。句柄是Handle概念的一个模型,它基本上提供了两个解引用运算符*和->。循环器是一种专门用于访问循环序列的类型。当访问的元素不属于序列时,使用句柄。迭代器和循环器用于访问三角剖分的全部或部分。

        迭代器和循环器都是双向的,不可变的。循环器和迭代器可以转换为具有相同值类型的句柄,因此当调用成员函数时,任何句柄类型参数都可以替换为具有相同值类型的迭代器或循环器。

        三角类提供了一个函数,可以按顺时针或逆时针顺序访问面的顶点和邻居。

        循环器可以访问给定顶点或其相邻顶点所附着的边缘或面。另一种循环器类型可以访问给定线所经过的所有面。循环器既可以遍历无限特征,也可以遍历有限特征。

        三角剖分类提供了一些迭代器来访问所有的面、边或顶点,以及有选择地访问有限的面、边或顶点的迭代器。

        三角剖分类提供了测试任何特征的无限特征的方法,以及在给定其顶点的情况下测试特定特征(边或面)在三角剖分中的存在的方法。

        三角剖分类提供了一种方法来定位给定点相对于三角形的位置。 特别是,该方法报告该点是否与三角形的顶点重合,是否位于边缘、面内或凸包外。 在退化的低维三角化的情况下,查询点也可能位于三角化仿射包络外。

        三角剖分类还提供了相对于三角剖分的给定有限面或其外接圆定位点的方法。三角剖分的面及其外接圆具有逆时针方向。

        三角剖分可以通过几个函数进行修改:插入点、删除顶点、移动顶点、翻转边。当两个入射面的并集形成一个凸四边形时,可以翻转边。

CGAL的2D三角剖分_第7张图片

4.2、实施

        定位是通过随机游走实现的。游走开始于三角剖分的一个顶点,该顶点作为可选参数给出,如果没有给出可选参数,则开始于三角剖分的任意顶点。对于Delaunay三角剖分,在最坏情况下需要O(n)的时间,但如果顶点随机均匀分布,则平均只需要O(n-√)。在三角剖分层次一节中描述的类Triangulation_hierarchy_2实现了一种数据结构,旨在提供一种更高效的点定位算法。

        插入点是通过定位包含该点的面,并将该面分割成三个新面来完成的。如果该点落在凸包外,则通过翻转来恢复三角剖分。除了定位外,插入需要的时间为O(1)。这个界限只是对位于凸包外的点的平均时间界限。

        删除一个顶点是通过删除所有相邻的三角形,并对孔进行重新三角化来实现的。删除所花费的时间最多与d2成正比,其中d是被删除顶点的度数,对于随机顶点,d为O(1)。

        顶点的位移是通过以下方式完成的:首先,验证三角剖分嵌入在位移后是否保持平面;如果是,则将顶点直接放置在新位置;否则,在新位置插入一个点,并删除过时位置的顶点。

        有限特征上的面、边和顶点迭代器是从它们访问所有(有限和无限)特征的对应迭代器中导出的,而这些迭代器本身又是由三角剖分数据结构的相应迭代器导出的。

4.3、几何特征

        三角剖分的几何特征类需要提供构建三角剖分的几何对象(点、线段和三角形)以及这些对象的几何谓词。所需的谓词是:比较两个点的x或y坐标。方向测试,计算三个给定点顺序类型。

        Triangulation_Traits_2概念描述了三角剖分的几何特征类的要求。CGAL内核类是该概念的模型。CGAL库还使用内核几何对象和谓词提供了Triangulation_Traits_2的专用模型。这些类本身由CGAL内核模板化,并从内核中提取所需的类型和谓词。Projection_traits_xy_3类是构建地形三角剖分的几何特征类。这样的三角剖分是嵌入在三维空间中的二维三角剖分。数据点是三维点。三角剖分是根据这些点在xy平面上的投影构建的,然后提升到原始的三维数据点。这对于处理GIS地形特别有用。特征类提供了忽略点 z 坐标的几何谓词,而不是真正投影三维点并保持每个点与其投影之间的映射(这会占用空间并容易出错)。请参阅 Delaunay Triangulations 部分以获取示例。      

        CGAL 库还提供了几何特征类 Projection_traits_yz_3 和 Projection_traits_xz_3,分别用于处理 yz 平面和 xz 平面上的投影,以及几何特征类 Projection_traits_3,用于处理由其正交向量定义的任意平面上的投影。//除了这些几何特征类,其他的很少见。

4.4、绘制2D的三角剖分

        通过调用的CGAL::draw()函数,可以可视化2D三角剖分。此函数打开一个新窗口,显示给定的2D三角剖分。调用此函数是阻塞的,即一旦用户关闭窗口,程序就会继续。

CGAL的2D三角剖分_第8张图片

5、Delaunay三角剖分(重要)

        Delaunay三角剖分是一种根据一组点生成三角剖分的方法。它的基本原则是保证所有三角形的外接圆内部不包含其他点。这样可以保证生成的三角剖分是最优的,即每个三角形都是尽可能小的。

        在Delaunay三角剖分中,由于它的定义和特性,可能会增加顶点的数量。这是因为在生成三角剖分的过程中,为了确保满足Delaunay三角剖分的条件,可能会插入一些新的顶点。具体来说,当一组点进行Delaunay三角剖分时,可能会出现以下情况:如果某两个点之间的距离非常接近,那么在它们之间插入一个新的顶点可能会更有利于生成一个尽可能小的三角形。如果某两个三角形共享一条边,且这条边上的顶点不是两个三角形的顶点,那么将这个顶点从其中一个三角形移除,并在另一条边上插入一个新的顶点可能会生成更小的三角形。

        因此,Delaunay三角剖分可能会增加顶点的数量,但这是为了确保生成的三角剖分是最优的。

5.1、描述

        类 Delaunay_triangulation_2< Traits, Tds > 旨在表示平面上一组数据点的 Delaunay 三角剖分。 Delaunay 三角剖分满足以下空圆性质(也称为 Delaunay 性质):三角剖分任何面的外接圆在其内部不包含数据点。对于没有四个共圆点的子集的点集,Delaunay 三角剖分是唯一的,它是点集的 Voronoi 图的对偶。

        类 Delaunay_triangulation_2< Traits,Tds> 派生自类 Triangulation_2< Traits,Tds>。

        类 Delaunay_triangulation_2 继承了基本类 Triangulation_2 定义的类型。由 traits 类提供的其他类型被定义为表示对偶沃罗诺伊图。

        类 Delaunay_triangulation_2< Traits,Tds> 重写了在三角剖分中插入、移动或删除点的成员函数,以保持 Delaunay 属性。它还有一个成员函数(Vertex_handleDelaunay_triangulation_2::nearest_vertex(const Point& p))来回答最近邻查询,以及构造对偶沃罗诺伊图的元素(顶点和边)的成员函数。

5.2、几何特征

        几何特征类必须是概念DelaunayTriangulationTraits_2的模型,该概念细化了概念TriangulationTraits_2。特别是,该概念提供了side_of_oriented_circle谓词,该谓词给定四个点p、q、r、s,确定了点s相对于通过p、q和r的圆的位置。side_of_oriented_circle谓词实际上定义了Delaunay三角剖分。改变该谓词允许用户为不同的度量构建Delaunay三角剖分的变体,例如L1或L∞度量或由凸物体定义的任何度量。但是,奇异度量的用户必须注意,所构造的三角剖分必须是凸壳的三角剖分,这意味着凸壳边缘必须是Delaunay边缘。这适用于任何平滑凸度量(如L2),并且可以通过在点集上添加精心选择的哨兵点来确保其他度量(如L∞)。

        CGAL 核心类是欧几里得度量的 DelaunayTriangulation_Traits_2 概念的模型。 地形的 traits 类,Projection_traits_xy_3、Projection_traits_yz_3 和 Projection_traits_xz_3,也是 DelaunayTriangulation Traits_2 的模型,除了它们不满足对偶函数和最近顶点查询的要求。

5.3、实施

        在Delaunay三角网中插入新点时,首先使用基本三角网的插入成员函数,然后执行一系列翻转以恢复Delaunay属性。如果新顶点在更新的Delaunay三角网中的度数为d,则必须执行的翻转次数为O(d)。对于随机均匀分布的点,一旦点位于三角网中,每次插入平均需要O(1)的时间。

        移除操作会调用三角剖分中的移除操作,然后对由此产生的孔进行重新三角剖分,以满足Delaunay标准。移除度数为d的顶点需要O(d2)的时间。对于三角剖分中的随机顶点,度数为O(1)。当移除的顶点度数较小(≤7)时,会使用一种特殊程序,使随机点的全局移除时间减少2倍。

        将点p处的顶点v移位到新位置p',首先检查三角剖分嵌入在将v移动到p'后是否保持平面。如果是,则将v移动到p'并简单地执行一系列翻转以恢复Delaunay属性,其中d是位移后的顶点度。否则,通过在新位置插入一个顶点并删除过时的顶点来完成位移。在最坏的情况下,复杂度为O(n),但对于单位方块中均匀分布的顶点,只有O(1+δn−−√),其中δ是新旧位置之间的欧几里德距离。

        执行点定位后,在最坏情况下,点的最近邻居可以在O(n)时间内找到,但对于随机均匀分布的顶点和任何查询点,可以在O(1)时间内找到。

6、规则三角剖分

        正则三角剖分是一种特殊的三角剖分,它对于给定的点集,通过特定的规则构建出满足一定条件的三维凸包。具体来说,正则三角剖分是将一个有限点集V映射到一个凸多胞形,该多胞形的每个面都是一个三角形,且所有三角形的合集是散点集V的凸包。

6.1、描述

        令 PW = {(pi,wi)|i=1,…,n} 为一组加权点,其中每个 pi 都是一个点,每个 wi 都是一个标量,称为点 pi 的权重。或者,每个加权点 (pi,wi) 可以被视为一个球体(或圆,取决于 pi 的维度),其中心为 pi,半径为 ri=根号wi。

        集合PW的幂图是一个空间划分,其中每个单元对应于PW中的一个球体(pi,wi),并且是点p的轨迹,点p相对于(pi,wi)的幂小于它相对于PW中任何其他球体的幂。在二维空间中,该图的对偶是一个三角剖分,其域覆盖中心点集合P={pi|i=1,…,n}的凸包,其顶点构成P的一个子集。这样的三角剖分称为正则三角剖分。如果平面上的三个点pi、pj和pk在PW的正则三角剖分中形成三角形,则存在一个点p,其相对于(pi,wi)、(pj,wj)和(pk,wk)的幂相等,并且该幂小于p相对于PW中任何其他球体的幂。

        类Regular_triangulation_2旨在维护一组二维加权点的正三角形。它从类Triangulation_2派生而来。函数insert和remove被重写以处理加权点并保持正三角形属性。函数move()没有被重写,因此不保留正三角形属性。一组加权点PW的正三角形的顶点仅对应于PW的子集。一些输入加权点在双幂图中没有单元,因此不对应于正三角形的顶点。这样的点称为隐藏点。因为隐藏点在以后某个点被删除时可能作为顶点重新出现,所以它们必须存储在某个地方。正三角形将这些点存储在称为隐藏顶点的特殊顶点中。只有当隐藏它的二维面从三角剖分中删除时,隐藏点才会重新出现为三角剖分的顶点。为了处理这个特性,规则三角剖分的每个面都存储一个隐藏顶点列表。当面被删除时,这些顶点中的点会重新插入三角剖分中。

        常规三角剖分具有构造对偶功率图的顶点和边的成员函数。

6.2、几何特征

        正三角剖分的几何特征类必须提供加权点类型和对这些加权点的幂测试。概念RegularTriangulationTraits_2是对概念TriangulationTraits_2的改进。所有CGAL内核都是特征概念RegularTriangulationTraits_2的模型。

6.3、正则三角剖分的顶点类型和面类型

        正则三角剖分的基顶点类型包含一个布尔数据成员来标记顶点的隐藏状态。因此,CGAL定义了RegularTriangulationVertexBase_2的概念,该概念对TriangulationVertexBase_2的概念进行了细化,并为该概念提供了一个默认模型。

        正则三角剖分面基类型需要提供隐藏顶点列表,用于存储被面隐藏的点。它必须是概念 RegularTriangulationFaceBase_2 的模型。 CGAL几何提供模板类 Regular_triangulation_face_base_2< Traits > 作为正三角剖分面的默认基类。

7、约束三角剖分

CGAL的2D三角剖分_第9张图片

        约束三角剖分是指一组点的三角剖分,其边中必须包含一组连接这些点的给定折线。这些折线称为约束。相应的边称为约束边。

        受约束边的端点当然是三角剖分的顶点。但是,三角剖分也可能包括其他顶点。受约束三角剖分有三个版本。

        在这些版本中,输入约束可能由相交、重叠或部分重叠的线段组成。三角剖分在每个点处引入了额外的顶点,这些点是两个约束的适当交点。单个约束与其他约束相交,将在三角剖分中显示为多个受约束的边。有两种方法可以处理相交约束。
        当谓词被精确计算时,第一个是鲁棒的,但构造(即交集计算)是近似的。
第二个应该使用精确算法(这意味着对谓词的精确评估和对交集的精确计算)。

 7.1、几何特征

        约束三角剖分的几何特征类必须是概念TriangulationTraits_2的模型。当支持输入约束的交集时,几何特征类必须是概念ConstrainedTriangulationTraits_2的模型,该模型对概念TriangulationTraits_2进行了细化,提供了额外的函数对象类型来计算两个线段的交集。

7.2、约束三角剖分的面基类 

        关于约束边的信息存储在三角剖分中。约束三角剖分的面基必须是概念ConstrainedTriangulationFaceBase_2的模型,该概念对概念TriangulationFaceBase_2进行了细化。概念ConstrainedTriangulationFaceBase_2需要成员函数来获取和设置边的约束状态。

        CGAL为约束三角剖分提供了一个默认的面基类。这个名为Constrained_triangulation_face_base_2的类从Triangulation_face_base_2类派生而来,并添加了三个布尔数据成员来存储其边的状态。

CGAL的2D三角剖分_第10张图片

8、约束Delaunay三角剖分

        约束Delaunay三角剖分和Delaunay三角剖分的主要区别在于约束的存在与否。

        Delaunay三角剖分是一种离散分布的点集P的三角剖分,它使得点集P中没有任意一个点严格处于任意一个三角形的外接圆的内部。这种三角剖分构建的三角网可以尽量避免狭长三角形的出现,有效提高逼近精度,使得网格整体质量保持最优。

        约束Delaunay三角剖分则是在Delaunay三角剖分的基础上引入了约束条件。这些约束条件可以包括点集的边界或其他特定要求,如特定的三角形形状或大小等。这种类型的三角剖分不是任意的,而是受到特定约束的限制。

        另外,约束Delaunay三角剖分的构建过程可能比Delaunay三角剖分更为复杂,因为它需要在满足约束条件的前提下,尽可能地优化三角形的形状和质量。因此,在实际应用中,需要根据具体需求和数据特点来选择是否采用约束Delaunay三角剖分。

        受约束的Delaunay三角剖分是一种具有约束边的三角剖分,这些约束边尽可能地接近Delaunay三角剖分。由于约束边不一定是Delaunay边,因此受约束的Delaunay三角剖分的三角形不一定满足空圆性质,但它们满足较弱的约束空圆性质。然后,三角剖分是受约束的Delaunay三角剖分,只要任何面的外接圆不包含从该面内部可见的顶点。与受约束的三角剖分的情况一样,提供了三种不同版本的Delaunay受约束三角剖分。第一个版本处理一组约束,这些约束除了端点外不相互交叉。另外两个版本处理相交的输入约束。其中一个版本的设计是,当与提供精确谓词和近似构造的几何特征类(如Filtered_kernel或任何提供过滤精确谓词的核)结合使用时,它具有鲁棒性。第三个版本的设计是,与精确算术数字类型一起使用。

       CGAL类 Constrained_Delaunay_triangulation_2 旨在表示受约束的 Delaunay 三角剖分。

        与约束三角剖分的情况一样,第三个参数 Itag 是交点标记,用于选择如何处理相交约束。 它可以用以下类之一实例化:No_constraint_intersection_tag、No_constraint_intersection_requiring_constructions_tag、Exact_predicates_tag 或 Exact_intersections_tag(见“约束三角剖分”一节)。

        受约束的 Delaunay 三角剖分不是 Delaunay 三角剖分,但它是一种受约束的三角剖分。 因此,Constrained_Delaunay_triangulation_2 类从 Constrained_triangulation_2 类派生而来。

        受约束的Delaunay三角剖分具有成员函数,可以覆盖点或约束的插入和删除。每个成员函数都负责恢复受约束的空圆属性。

8.1、几何特征类

        受约束的Delaunay三角剖分的几何特征类需要提供side_of_oriented_circle谓词作为Delaunay三角剖分的几何特征类,并且必须是概念DelaunayTriangulationTraits_2的模型。当支持输入约束相交时,进一步要求几何特征类提供函数对象来计算约束相交。然后,几何特征类必须同时是概念ConstrainedTriangulation Traits_2的模型。

8.2、Face基类

        有关三角剖分边状态(受约束或不受约束)的信息必须存储在面类中,受约束的Delaunay三角剖分的面基类必须是ConstrainedTriangulationFaceBase_2的模型。

9、约束和次约束之间双向映射的约束三角剖分

        本节对约束的管理

        Constrained_triangulation_plus_2 类提供了一个具有附加数据结构的约束三角剖分,该数据结构跟踪输入约束及其在三角剖分中的细化。 Constrained_triangulation_plus_2 类继承自其模板参数 Tr,该参数必须由约束或约束的 Delaunay 三角剖分实例化。 根据其交点标记,基类将支持或不支持相交输入约束。 当支持输入约束的相交时,基类将构造约束排列的三角剖分,在每个适当的交点处引入新的顶点。

        三角剖分将为每个输入约束保留此约束上的顶点序列。这些顶点或者是输入约束的顶点,或者是交点。

        输入约束的两个连续顶点形成一个子约束。三角剖分使得可以检索三角剖分的子约束集(不是沿着约束排序的)。

        它进一步允许检索出诱导子约束的输入约束集。由于从受约束的边e中直接获得子约束是很容易的,因此可以很容易地获得诱导e的输入约束。

9.1、边、受约束的边、约束和子约束

        所有三角剖分类都将类型 Edge 定义为 typedef std::pair Edge。对于一个 pair (fh,i),它是面 *fh 的边,与第 i 个顶点相对。

        受约束的边 e 是受约束三角剖分 ct 的边,对于该边,ct.is_constrained(e) 返回 true。

        约束是作为输入给出的折线(在最简单的情况下只是一个线段),在三角剖分中它被分割成受约束的边。

        Subconstraint类型被定义为typedef std::pair Subconstraint。这两个顶点句柄必须是受约束边的顶点。

        Constraint_id类型标识约束。

        所有受约束的CGAL类都提供了插入约束的功能,具有受约束边的概念,并提供Constrained_edges_iterator。

        Constrained_triangulation_plus_2 类还额外提供了以下方法

        使用类型为Constraint_iterator的迭代器遍历三角剖分的所有约束,其值类型为Constraint_id,获取所有导致约束边或子约束的约束,使用 Vertices_in_constraint_iterator 类型的迭代器遍历约束的顶点序列,其值类型为 Vertex_handle

        使用 Subconstraint_iterator 类型的迭代器遍历三角剖分中的子约束,其值类型为 Subconstraint。

        请注意,Constrained_edges_iterator 和 Subconstraint_iterator 非常相似。Constrained_edges_iterator 遍历所有边并跳过不受约束的边,这意味着遍历时间将与总边数呈线性关系。而 Subconstraint_iterator 遍历三角剖分中存储的一组子约束。

        另一方面,由于子约束只是一对顶点控制柄,确定相应的边需要两个顶点中较小的一个度数,而从子约束中获取边是一个常数时间操作。

9.2、交叉点标记

        当基础约束三角剖分类处理约束的交集并使用精确数字类型时,即当其交集标签为 Exact_intersections_tag 时,Constrained_triangulation_plus_2 类特别有用。在这种情况下,Constrained_triangulation_plus_2 避免了交集点计算中的级联。

CGAL的2D三角剖分_第11张图片

        插入约束时,例如三角剖分中的线段 s,该线段可能与约束边 e 相交,其顶点为 p 和 q。算法可以计算 s 与线段 [p,q] 的交点 i。由于这些点可能是先前构造的交点,如上图中的 q,最好使用诱导边的输入约束 c。如果 c 是线段,则算法将 s 与 c 相交。如果 c 是折线,则算法从输入约束中找出两个顶点,定义一个诱导边 e 的输入线段。 

10、三角剖分层次

        类Triangulation_hierarchy_2实现了一个添加了数据结构的三角剖分,以有效地回答点位置查询。该数据结构是一个三角剖分的层次结构。最低级别的三角剖分是原始三角剖分,其中要执行操作和点位置。然后在每个后续级别,数据结构存储了前一级别三角剖分中顶点的小随机样本的三角剖分。点位置是通过自上而下的最近邻查询完成的。最近邻查询首先在顶层三角剖分中朴素地执行。然后,在每个后续级别,通过从前一级别中找到的最近邻进行线性步行,找到该级别的最近邻。由于每个三角剖分中的顶点数量只是前一个三角剖分中顶点数量的一小部分,因此数据结构保持较小,并在真实数据上实现了快速点位置查询。当为Delaunay三角剖分构建时,这种结构具有最佳行为。但是,它也可以用于其他三角剖分,Triangulation_hierarchy_2类由一个参数模板化,该参数由一个CGAL的三角剖分类实例化。

        类 Triangulation_hierarchy_2 继承了作为模板参数 Tr 传递的三角剖分类型。插入、移动和删除成员函数被重写,以在每次操作时更新数据结构。定位查询也被重写,以利用数据结构进行快速处理。

10.1、三角剖分层次的顶点

        三角剖分层次的基础顶点类必须是概念TriangulationHierarchyVertexBase_2的模型,该模型扩展了概念TriangulationVertexBase_2。这一扩展为两个指针添加了访问和设置成员函数,这两个指针指向下一级和上一级三角剖分中相应的顶点。

        CGAL 提供了 Triangulation_hierarchy_vertex_base_2 类,它是 TriangulationHierarchyVertexBase_2 概念的模型。该类由参数 Vb 模板化,该参数由 TriangulationVertexBase_2 概念的模型实例化。 Triangulation_hierarchy_vertex_base_2 类继承了其模板参数 Vb。这种设计允许使用默认的顶点类或用户自定义的顶点类,并为 Vb 提供额外的功能。

11、灵活性

        本质是对三角剖分数据结构的顶点结构进行修改。

11.1、自定义的顶点和面

        为了能够适应各种需求,我们为二维三角剖分选择了一种高度灵活的设计。我们已经看到,三角剖分类有两个参数:一个几何特征类和一个三角剖分数据结构类,用户可以使用自己的自定义类对其进行实例化。

        然而,最实用的灵活性来自三角剖分数据结构本身有两个模板参数,需要用三角剖分的顶点和面的类来实例化。使用他自己的自定义类来实例化这些参数,用户可以轻松地构建一个包含顶点和面中附加信息或功能的三角剖分。

11.2、循环依赖

        为了确保灵活性,三角剖分数据结构由顶点和面基类模板化。此外,由于关联关系和邻接关系存储在顶点和面中,基类必须知道三角剖分数据结构提供的顶点和面上的句柄类型。因此,顶点和面基类本身必须通过三角测量数据结构进行参数化,并且存在对模板参数的循环依赖。

CGAL的2D三角剖分_第12张图片

        以前,这种循环依赖是通过在基类的接口中只使用void指针来避免的。这些void在三角剖分数据结构级别上转换为适当的类型。这种解决方案有一些缺点:主要是用户无法在三角剖分的顶点或面上添加与三角剖分数据结构定义的类型相关的功能,例如一个顶点的句柄,他不得不使用void*指针。解决模板依赖性的新解决方案基于类似于标准分配器类std:: allocator中使用的机制的重新绑定机制。重新绑定机制在第二章《三角剖分数据结构》的“默认三角剖分数据结构”一节中进行了描述。现在,我们只注意到设计要求在顶点和面基类中存在一个嵌套的模板类Rebind_TDS,它定义了重新绑定机制使用的类型Other。 

11.3、增加颜色

        可以使用预定义的类Triangulation_vertex_base_with_info_2或Triangulation_face_base_with_info_2。这些类有一个模板参数Info,专门用于处理附加信息。

11.4、增加句柄

        需要基于Triangulation_vertex_base_2类。

template < class Gt, class Vb = CGAL::Triangulation_vertex_base_2 >
class My_vertex_base
  : public  Vb

11.5、插入点范围时设置信息

        在Delaunay(或规则)三角网中插入(加权)点最有效的方法是将(加权)点的迭代器范围提供给插入函数。但是,(加权)点的迭代器范围不允许用户为每个顶点设置不同的信息。为了解决这个问题,在三角网的顶点类型是TriangulationVertexBaseWithInfo_2(如Triangulation_vertex_base_with_info_2)模型的情况下,我们提供了三个示例来执行相同的操作:将无符号整数设置为每个顶点的信息。这个无符号整数的值是范围中给定的对应点的初始顺序。

11.6、在pair上使用迭代器

typedef CGAL::Triangulation_vertex_base_with_info_2    Vb;
typedef CGAL::Triangulation_data_structure_2                    Tds;
typedef CGAL::Delaunay_triangulation_2                      Delaunay;

11.7、使用Boost压缩迭代器

        boost::make_zip_iterator是Boost库中的一个函数,它用于创建zip迭代器。Zip迭代器是一种可以同时遍历多个范围的迭代器。这些范围可以是同类型的,也可以是不同类型的。

  Delaunay T;
  T.insert( boost::make_zip_iterator(boost::make_tuple( points.begin(),indices.begin() )),
            boost::make_zip_iterator(boost::make_tuple( points.end(),indices.end() ) )  );

11.8、使用Boost变换迭代器

        boost::make_transform_iterator是一个用于创建转换迭代器的函数,它属于Boost库的范围。转换迭代器是一种特殊类型的迭代器,可以将容器中的元素转换为另一种形式。

        boost::make_transform_iterator函数需要两个参数:一个输入迭代器和一个可调用对象(函数或函数对象),该对象定义了如何将输入迭代器指向的元素转换为另一种形式。

你可能感兴趣的:(CGAL,算法,几何学)