【CGAL实战】深入理解二维受约束 Delaunay 网格生成

在计算几何、有限元分析(FEA)以及地形建模中,网格生成(Mesh Generation) 是一个至关重要的步骤。如何将一个任意形状的多边形区域离散化为高质量的三角形网格?

本文将以 CGAL (Computational Geometry Algorithms Library) 为例,通过一段标准代码,深入剖析如何生成受约束 Delaunay 三角网格 (Constrained Delaunay Triangulation, CDT),并重点解读控制网格质量的核心参数。

1. 什么是受约束 Delaunay 三角剖分 (CDT)?

普通的 Delaunay 三角剖分虽然能保证三角形尽可能"圆润"(避免极细长的三角形),但它无法强制保留我们指定的边界线段

CDT (Constrained Delaunay Triangulation) 解决了这个问题:它允许我们定义"约束边(Constraints)"。这些边必须出现在最终的网格中,哪怕它们破坏了 Delaunay 性质。在此基础上,CGAL 的网格生成算法(Mesher)会通过插入额外的点(Steiner Points)来优化网格,使其既满足边界约束,又满足形状和大小的要求。

2. 核心代码实现

下面是一个完整的 C++ 示例,展示了如何定义一个"风筝形"区域并对其进行网格细化。

cpp 复制代码
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Delaunay_mesher_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>
#include <CGAL/Delaunay_mesh_size_criteria_2.h>
#include <iostream>

// --- 1. 类型定义与内核配置 ---
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Triangulation_vertex_base_2<K> Vb;

// 关键点:必须使用 Delaunay_mesh_face_base_2 以支持细化算法
typedef CGAL::Delaunay_mesh_face_base_2<K> Fb; 
typedef CGAL::Triangulation_data_structure_2<Vb, Fb> Tds;
typedef CGAL::Constrained_Delaunay_triangulation_2<K, Tds> CDT;
typedef CGAL::Delaunay_mesh_size_criteria_2<CDT> Criteria;

typedef CDT::Vertex_handle Vertex_handle;
typedef CDT::Point Point;

int main()
{
    CDT cdt;

    // --- 2. 定义几何边界 ---
    // 定义一个菱形/风筝形
    Vertex_handle va = cdt.insert(Point(-4,0));
    Vertex_handle vb = cdt.insert(Point(0,-1));
    Vertex_handle vc = cdt.insert(Point(4,0));
    Vertex_handle vd = cdt.insert(Point(0,1));
    
    // 插入一个内部点
    cdt.insert(Point(2, 0.6));

    // --- 3. 插入约束边 ---
    cdt.insert_constraint(va, vb);
    cdt.insert_constraint(vb, vc);
    cdt.insert_constraint(vc, vd);
    cdt.insert_constraint(vd, va);

    std::cout << "初始顶点数: " << cdt.number_of_vertices() << std::endl;

    // --- 4. 执行网格细化 ---
    std::cout << "正在生成网格..." << std::endl;
    
    // 核心函数:设置细化标准
    CGAL::refine_Delaunay_mesh_2(cdt, CGAL::parameters::criteria(Criteria(0.125, 0.5)));

    std::cout << "细化后顶点数: " << cdt.number_of_vertices() << std::endl;
    
    return 0;
}

3. 避坑指南:类型定义

很多初学者在使用 CGAL 网格生成时会遇到编译错误或运行时崩溃,原因通常出在 Face_base 的选择上。

请注意这行代码:

cpp 复制代码
typedef CGAL::Delaunay_mesh_face_base_2<K> Fb;

普通的三角剖分使用 Triangulation_face_base_2 即可,但如果你要使用 refine_Delaunay_mesh_2 算法,必须 使用 Delaunay_mesh_face_base_2。因为细化算法需要在每个三角形对象中存储额外的状态信息(如三角形是否在约束区域内、是否满足尺寸要求等)。

4. 深度解析:Criteria 参数的魔法

代码中最关键的一行是:

cpp 复制代码
CGAL::refine_Delaunay_mesh_2(cdt, CGAL::parameters::criteria(Criteria(0.125, 0.5)));

这里的 Criteria(0.125, 0.5) 控制着最终网格的质量和密度。很多开发者不知道如何调整这两个数字。

参数一:Shape Bound (形状标准) = 0.125

这个参数控制三角形的形状质量 ,具体来说是限制三角形的最小角

  • 含义:它定义了一个常数 ,使得 。
  • 为何是 0.125? 这是 CGAL 的推荐值。当 时,算法保证生成的网格中所有三角形的最小角 。
  • 建议保持 0.125 不变。这是该算法能保证数学上收敛(终止)的最严格限制。如果设得更小(试图追求接近 60° 的完美三角形),算法可能会陷入死循环。如果你不关心形状只关心大小,可以设为 0。

参数二:Size Bound (尺寸标准) = 0.5

这个参数控制三角形的最大大小(网格密度)。

  • 含义:网格中任意三角形的任意边长都不能超过这个值。

  • 影响

  • 值越小:网格越密,顶点越多,计算量越大。

  • 值越大:网格越稀疏。

  • 设为 0:不限制大小,只为了满足形状要求或边界约束而加点。

  • 示例:在上面的代码中,几何体跨度为 8 (-4 到 4),我们将尺寸限制为 0.5。这意味着原来的大三角形会被切碎,算法会自动插入大量的 Steiner Points 直到所有边长都小于 0.5。

5. 进阶技巧:非均匀网格

如果你希望在某些区域网格密(如应力集中区),某些区域网格稀,Criteria 的第二个参数其实可以接受一个函数对象 (Functor) 而不仅仅是 double

你可以编写一个类,根据坐标 返回不同的尺寸限制值,从而实现自适应网格生成。

cpp 复制代码
// 伪代码思路
struct Variable_sizing {
    double operator()(const Point& p) const {
        if (is_important_region(p)) return 0.1; // 核心区域加密
        return 1.0; // 边缘区域稀疏
    }
};

6. 总结

使用 CGAL 生成二维网格的流程可以概括为:

  1. 配置 Kernel 和 Traits (别忘了 Delaunay_mesh_face_base_2)。
  2. 构建 CDT,插入点和约束边。
  3. 设置 Criteria :记住 0.125 是形状的黄金标准,调节第二个参数来控制网格密度。
  4. **调用 refine_Delaunay_mesh_2** 一键生成。
相关推荐
产幻少年2 小时前
redis位图
数据库·redis·缓存
漫随流水2 小时前
leetcode算法(104.二叉树的最大深度)
数据结构·算法·leetcode·二叉树
机器学习之心HML2 小时前
鲸鱼算法(WOA)优化Kriging模型
算法
短剑重铸之日2 小时前
《7天学会Redis》Day 4 - 高可用架构设计与实践
数据库·redis·缓存
DYS_房东的猫3 小时前
《 C++ 零基础入门教程》第6章:模板与 STL 算法 —— 写一次,用万次
开发语言·c++·算法
Tim_103 小时前
【算法专题训练】37、前缀树&二叉树
算法
NineData3 小时前
第三届数据库编程大赛-八强决赛成绩揭晓
数据库·算法·代码规范
難釋懷3 小时前
认识Redis
数据库·redis·缓存
超级种码3 小时前
Redis:Redis脚本
数据库·redis·缓存
雍凉明月夜3 小时前
深度学习之目标检测yolo算法Ⅱ(v4)
深度学习·算法·yolo·目标检测