在计算机辅助制造 (CAM) 软件开发中,无论是叶片精加工的路径计算,还是模具设计的刀具半径补偿,底层的几何网格质量直接决定了算法的鲁棒性。
本文基于 CGAL 5.10.2 的 Mesh_2 软件包,深入探讨"符合三角剖分 (Conforming Triangulations)"的核心机制,解析 Delaunay 与 Gabriel 性质的区别,并结合 C++ 代码展示如何在工程中应用这些算法来优化加工边界。
1. 为什么普通的三角剖分不够用?
当我们导入一个零件轮廓(PSLG,平面直线图)并进行三角剖分时,最常见的问题是**"边界不稳定"**。
在普通的约束三角剖分 (CDT) 中,虽然约束边(轮廓线)被保留了,但它们可能非常细长,或者与邻近点的几何关系很差。这会导致以下后果:
- 刀轨计算误差:在计算偏置(Offset)时,细长的三角形会导致法向量计算剧烈抖动。
- 数值不稳定:在进行有限元分析或物理仿真时,劣质网格会导致计算不收敛。
解决这个问题的方案,就是引入**"符合化 (Conforming)"** 算法。
2. 核心概念解析
要理解 CGAL 是如何修复网格的,我们需要搞懂三个关键术语:
2.1 Delaunay 性质(空圆性质)
这是网格质量的基石。对于网格中的任意三角形,其外接圆内部不包含网格中的任何其他顶点。
- 作用:最大化了三角形的最小角,避免了极瘦的三角形。
2.2 Gabriel 性质(更严苛的标准)
Gabriel 性质比 Delaunay 更严格。它要求:以任意一条约束边为直径的圆(Diametrical Circle),其内部不能包含任何其他顶点。
- Delaunay vs Gabriel:Delaunay 看的是"外接圆",Gabriel 看的是"直径圆"。
- CAM 中的意义:如果边界符合 Gabriel 性质,那么在边界附近的几何拓扑是非常"干净"的,这对接触检测和刀具路径生成的稳定性至关重要。
2.3 Steiner 顶点 (Steiner Points)
当输入的轮廓线不满足上述性质时(例如线段太长,或者旁边有个点离线太近),算法会在这些线段上自动插入额外的点 。
这些不是用户输入,而是为了满足几何规则而由算法生成的点,被称为 Steiner 顶点。
3. 算法原理:如何"修剪"网格?
CGAL 使用 Delaunay Refinement (细化) 算法来处理这一过程:
- 检查约束边:算法遍历所有约束边。
- 判定冲突:
- 如果是 Delaunay 模式:检查外接圆是否为空。
- 如果是 Gabriel 模式:检查以边为直径的圆是否为空。
- 插入 Steiner 点 :如果圆内有点(冲突),算法就在该约束边的中点插入一个 Steiner 点,将长边切成两段短边。
- 递归:重复上述过程,直到所有边都"合规"。
注意:Gabriel 模式通常会比 Delaunay 模式插入更多的点,因为它对空圆的要求更苛刻(直径圆通常比外接圆小,更容易"撞"到别的点)。
4. 实战代码演示
以下代码基于 CGAL 5.10.2,演示了如何将一个普通的约束三角剖分逐步优化为符合 Delaunay 和 Gabriel 标准的网格。
cpp
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_conformer_2.h> // 核心头文件:包含符合化算法
#include <iostream>
// 使用 EPICK 内核:CAM 开发的首选,兼顾判断精度与计算速度
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;
// 1. 构建基础几何:插入顶点
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.));
// 2. 插入约束边:定义加工边界
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 << "初始顶点数: " << cdt.number_of_vertices() << std::endl;
// 3. 符合 Delaunay 处理
// 算法会在约束边上插点,确保满足空外接圆性质
CGAL::make_conforming_Delaunay_2(cdt);
std::cout << "Delaunay 符合化后的顶点数: " << cdt.number_of_vertices() << std::endl;
// 4. 符合 Gabriel 处理 (更严格)
// 算法确保所有约束边为直径的圆都是空的,通常会插入更多点
CGAL::make_conforming_Gabriel_2(cdt);
std::cout << "Gabriel 符合化后的顶点数: " << cdt.number_of_vertices() << std::endl;
return 0;
}
5. 进阶优化:Lloyd 算法
生成符合标准的网格后,为了进一步提升"美观度"(即让三角形更接近等边三角形),通常会通过 Lloyd 优化 进行后处理。
cpp
// 移动顶点到 Voronoi 单元质心,迭代优化 10 次
CGAL::lloyd_optimize_mesh_2(cdt, CGAL::parameters::max_iteration_number = 10);
这一步能显著改善网格的角度分布,使其在 CAM 计算中更加稳定。
总结
对于 CAM 软件开发,网格不仅仅是一堆三角形,它是所有几何算法的"路基"。
- 使用
make_conforming_Delaunay_2保证基本的三角形质量。 - 使用
make_conforming_Gabriel_2确保边界的绝对稳健性。 - 理解 Steiner 点的生成机制,有助于我们在精度(点多)和性能(点少)之间找到平衡。