作者
劳伦特·里诺(Laurent Rineau)
简介
这个包实现了Shewchuk的算法[1]来构造合规的三角剖分和二维网格。合规的三角剖分将在“合规的三角剖分”部分中描述,而二维网格将在“网格”部分中描述。
Shewchuk的算法:
Shewchuk的算法[1]指的是由乔纳森·谢伍德(Jonathan R. Shewchuk)提出的一系列算法,特别是关于二维和三维的Delaunay三角剖分和约束Delaunay三角剖分。谢伍德在这些领域做出了杰出的贡献,他的算法被广泛用于计算几何库和软件中,包括CGAL(Computational Geometry Algorithms Library)和Triangle等。
在二维空间中,Shewchuk的算法主要用于生成高质量的三角网格,这些网格满足Delaunay性质,即没有任何点位于其相邻三角形的外接圆内部。这种性质保证了生成的网格在几何上是“好”的,因为它避免了狭窄的三角形,这些三角形在数值计算中可能导致问题。
对于约束Delaunay三角剖分,算法允许用户指定一些必须包含在最终网格中的边,或者固定某些顶点的位置。这些约束条件在生成三角剖分时会被考虑,以生成满足所有约束条件的合规三角剖分。
在CGAL中,这些算法的实现使得用户能够轻松地生成高质量的二维三角网格,并且可以根据需要添加约束条件来满足特定的应用需求。通过调整参数和约束条件,用户可以控制生成的网格的精度和质量,以满足不同领域的计算需求。
需要注意的是,Shewchuk的算法是一个复杂的计算几何算法,其实现涉及大量的数学和几何知识。因此,对于不熟悉计算几何的用户来说,直接使用CGAL等库中的实现可能是更好的选择,因为这些库已经提供了经过优化和测试的算法实现,可以方便地集成到各种应用程序中。
1 Conforming Triangulations(合规三角剖分)
1.1 Definitions
A triangulation is a Delaunay triangulation if the circumscribing circle of any facet of the triangulation contains no vertex in its interior. A constrained Delaunay triangulation is a constrained triangulation which is as much Delaunay as possible. The circumscribing circle of any facet of a constrained Delaunay triangulation contains in its interior no data point visible from the facet.
An edge is said to be a Delaunay edge if it is inscribed in an empty circle (containing no data point in its interior). This edge is said to be a Gabriel edge if its diametrical circle is empty.
A constrained Delaunay triangulation is said to be a conforming Delaunay triangulation if every constrained edge is a Delaunay edge. Because any edge in a constrained Delaunay triangulation is either a Delaunay edge or a constrained edge, a conforming Delaunay triangulation is in fact a Delaunay triangulation. The only difference is that some of the edges are marked as constrained edges.
A constrained Delaunay triangulation is said to be a conforming Gabriel triangulation if every constrained edge is a Gabriel edge. The Gabriel property is stronger than the Delaunay property and each Gabriel edge is a Delaunay edge. Conforming Gabriel triangulations are thus also conforming Delaunay triangulations.
Any constrained Delaunay triangulation can be refined into a conforming Delaunay triangulation or into a conforming Gabriel triangulation by adding vertices, called Steiner vertices, on constrained edges until they are decomposed into subconstraints small enough to be Delaunay or Gabriel edges.
1.1 定义
如果三角剖分中任何面的外接圆内部不包含任何顶点,则该三角剖分是Delaunay三角剖分。约束Delaunay三角剖分是尽可能保持Delaunay性质的约束三角剖分。约束Delaunay三角剖分中任何面的外接圆内部不包含从该面可见的任何数据点。
如果一条边被包含在一个空圆内(即该圆的内部不包含任何数据点),则称该边为Delaunay边。如果一条边的直径圆是空的,则称该边为Gabriel边。
如果约束Delaunay三角剖分中的每条约束边都是Delaunay边,则该三角剖分称为合规的Delaunay三角剖分。由于约束Delaunay三角剖分中的任何边要么是Delaunay边,要么是约束边,因此合规的Delaunay三角剖分实际上是Delaunay三角剖分。唯一的区别是,一些边被标记为约束边。
如果约束Delaunay三角剖分中的每条约束边都是Gabriel边,则该三角剖分称为合规的Gabriel三角剖分。Gabriel属性比Delaunay属性更强,并且每条Gabriel边都是Delaunay边。因此,合规的Gabriel三角剖分也是合规的Delaunay三角剖分。
可以通过在约束边上添加顶点(称为Steiner顶点)来将任何约束Delaunay三角剖分细化为合规的Delaunay三角剖分或合规的Gabriel三角剖分,直到它们被分解为足够小的子约束,以成为Delaunay边或Gabriel边。
1.2 Building Conforming Triangulations(构建合规三角剖分)
Constrained Delaunay triangulations can be refined into conforming triangulations by the two following global functions:
In both cases, the template parameter CDT
must be instantiated by a constrained Delaunay triangulation class (see Chapter 2D Triangulations).
The geometric traits of the constrained Delaunay triangulation used to instantiate the parameter CDT
has to be a model of the concept ConformingDelaunayTriangulationTraits_2
.
The constrained Delaunay triangulation t
is passed by reference and is refined into a conforming Delaunay triangulation or into a conforming Gabriel triangulation by adding vertices. The user is advised to make a copy of the input triangulation in the case where the original triangulation has to be preserved for other computations
The algorithm used by make_conforming_Delaunay_2()
and make_conforming_Gabriel_2()
builds internal data structures that would be computed twice if the two functions are called consecutively on the same triangulation. In order to avoid these data to be constructed twice, the advanced user can use the class Triangulation_conformer_2<CDT>
to refine a constrained Delaunay triangulation into a conforming Delaunay triangulation and then into a conforming Gabriel triangulation. For additional control of the refinement algorithm, this class also provides separate functions to insert one Steiner point at a time.
约束Delaunay三角剖分可以通过以下两个全局函数进行细化以生成合规三角剖分:
template<class CDT> | |
void make_conforming_Delaunay_2 (CDT& t) | |
template<class CDT> | |
void make_conforming_Gabriel_2 (CDT& t) |
在这两种情况下,模板参数CDT必须由一个约束Delaunay三角剖分类实例化(参见第2章:二维三角剖分)。
用于实例化参数CDT的约束Delaunay三角剖分的几何特性必须是ConformingDelaunayTriangulationTraits_2概念的模型。
约束Delaunay三角剖分t通过引用传递,并通过添加顶点细化为合规的Delaunay三角剖分或合规的Gabriel三角剖分。如果用户需要保留原始三角剖分进行其他计算,建议复制输入三角剖分。
make_conforming_Delaunay_2()和make_conforming_Gabriel_2()算法构建的内部数据结构在连续调用相同三角剖分的两个函数时会被计算两次。为了避免这些数据被构建两次,高级用户可以使用类Triangulation_conformer_2<CDT>来将约束Delaunay三角剖分细化为合规的Delaunay三角剖分,然后细化为合规的Gabriel三角剖分。为了对细化算法进行更多控制,此类还提供了单独插入一个Steiner点的函数。
1.3 Example: Making a Triangulation Conforming Delaunay and Then Conforming Gabriel(制作符合Delaunay和Gabriel的三角剖分)
This example inserts several segments into a constrained Delaunay triangulation, makes it conforming Delaunay, and then conforming Gabriel. At each step, the number of vertices of the triangulation is printed.
1.3 示例:
本示例将几个线段插入到约束Delaunay三角剖分中,先使其符合Delaunay性质,然后符合Gabriel性质。在每个步骤中,都会打印三角剖分的顶点数。
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_conformer_2.h>
#include <iostream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Constrained_Delaunay_triangulation_2<K> CDT;
typedef CDT::Point Point;
typedef CDT::Vertex_handle Vertex_handle;
int main()
{
CDT cdt;
// construct a constrained triangulation
Vertex_handle
va = cdt.insert(Point( 5., 5.)),
vb = cdt.insert(Point(-5., 5.)),
vc = cdt.insert(Point( 4., 3.)),
vd = cdt.insert(Point( 5.,-5.)),
ve = cdt.insert(Point( 6., 6.)),
vf = cdt.insert(Point(-6., 6.)),
vg = cdt.insert(Point(-6.,-6.)),
vh = cdt.insert(Point( 6.,-6.));
cdt.insert_constraint(va,vb);
cdt.insert_constraint(vb,vc);
cdt.insert_constraint(vc,vd);
cdt.insert_constraint(vd,va);
cdt.insert_constraint(ve,vf);
cdt.insert_constraint(vf,vg);
cdt.insert_constraint(vg,vh);
cdt.insert_constraint(vh,ve);
std::cout << "Number of vertices before: "
<< cdt.number_of_vertices() << std::endl;
// make it conforming Delaunay
CGAL::make_conforming_Delaunay_2(cdt);
std::cout << "Number of vertices after make_conforming_Delaunay_2: "
<< cdt.number_of_vertices() << std::endl;
// then make it conforming Gabriel
CGAL::make_conforming_Gabriel_2(cdt);
std::cout << "Number of vertices after make_conforming_Gabriel_2: "
<< cdt.number_of_vertices() << std::endl;
}