【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** 一键生成。
相关推荐
silvamux_12 小时前
10款模型写种草笔记:可发布性、返工来源与成本数据缺口复盘
java·数据库·笔记
小蒋观天下13 小时前
雷击与浪涌防护:前端SPD选型、接地网误区,接地不当反而引入干扰
深度学习·算法·机器学习
I Am a robert girl13 小时前
从 GameHorizon 拆解多时间尺度游戏评测:数据管线、离线基准与在线回放的三层设计
数据库·游戏·多时间尺度·数据管线·游戏评测·离线基准·在线回放
躺柒14 小时前
读数据安全架构设计与实践17安全架构案例(下)
数据库·安全·零信任·安全架构·防火墙·无边界
SelectDB14 小时前
实时更新排错现场:导入了却查到旧数据,和 FINAL 越加越慢的两条路
大数据·数据库·数据分析
WBluuue14 小时前
数据结构与算法:分块(一):块状数组、块状链表
数据结构·c++·算法·链表
SelectDB14 小时前
拿 Planet 的账单一行行对下来,我总结出三个可自查的校验点
大数据·数据库·数据分析
SelectDB15 小时前
Apache Doris + Vane:让多模态数据进入业务分析
大数据·数据库·数据分析
澳鹏Appen16 小时前
澳鹏重磅发布ExamOCRBench:面向端到端试卷判分的多任务基准
算法·benchmark·基准评测