【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** 一键生成。
相关推荐
小龙报1 天前
【数据结构与算法】单链表核心精讲:从概念到实战,吃透指针与动态内存操作
c语言·开发语言·数据结构·c++·人工智能·算法·链表
野犬寒鸦1 天前
从零起步学习并发编程 || 第二章:多线程与死锁在项目中的应用示例
java·开发语言·数据库·后端·学习
long3161 天前
合并排序 merge sort
java·数据结构·spring boot·算法·排序算法
定偶1 天前
事务、触发器、存储过程与视图全解析
数据库·oracle
格林威1 天前
Baumer相机碳纤维布纹方向识别:用于复合材料铺层校验的 5 个核心技巧,附 OpenCV+Halcon 实战代码!
人工智能·数码相机·opencv·算法·计算机视觉·视觉检测
范纹杉想快点毕业1 天前
STM32单片机与ZYNQ PS端 中断+状态机+FIFO 综合应用实战文档(初学者版)
linux·数据结构·数据库·算法·mongodb
拓云者也1 天前
常用的生物信息学数据库以及处理工具
数据库·python·oracle·r语言·bash
Henry Zhu1231 天前
数据库(二):数据模型
数据库
曹牧1 天前
Java:将字符串转换为整数
java·数据库
hcnaisd21 天前
机器学习模型部署:将模型转化为Web API
jvm·数据库·python