9.1 Mesh_3三维网格生成概述

上一节: 8.2 三维Delaunay三角剖分 下一节: 9.2 曲面网格生成

0. 直观理解:乐高积木与精密工程

0.1 生活类比:乐高积木搭建

想象你正在用乐高积木搭建一个复杂的模型。每个乐高积木就像是一个四面体单元,而整个模型就是我们要生成的三维网格

Mesh_3的工作方式

  • 输入:你要搭建的目标形状(比如一艘飞船)
  • 过程:根据复杂度选择合适的积木大小
  • 输出:由许多小积木组成的完整模型
简单区域 = 大积木(少顶点)          复杂区域 = 小积木(多顶点)

┌─────────┐                         ┌───┬───┬───┐
│         │                         ├───┼───┼───┤
│         │        vs               ├───┼───┼───┤
│         │                         ├───┼───┼───┤
└─────────┘                         └───┴───┴───┘

在曲面附近加密                    在平坦区域稀疏

0.2 为什么需要三维网格?

场景1:汽车碰撞测试(有限元分析)

  • 需要精确模拟汽车外壳的变形
  • 网格质量直接影响计算精度
  • 太粗的网格 → 结果不准确
  • 太细的网格 → 计算时间过长

场景2:心脏血流模拟(计算流体力学)

  • 模拟血液在心脏中的流动
  • 需要捕捉血管的几何细节
  • 网格必须适应血流速度变化

场景3:油田储量估算(地质建模)

  • 模拟石油在多孔岩石中的流动
  • 网格需要反映地层结构
  • 不同岩层需要不同密度

0.3 Delaunay细化过程动画描述

Mesh_3的核心算法是Delaunay细化,让我们用动画的方式理解它:

第1帧:初始状态
        
        目标域(球体)
           •
          / \
         /   \
        /     \
       •-------•
        \     /
         \   /
          \ /
           •

只有边界上的几个点

第2帧:识别"坏"单元
        
           •
          /|\
         / | \
        /  |  \
       •---|---•
        \  |  /
         \ | /
          \|/
           •
           
红色三角形 = 太扁平(质量差)
蓝色区域 = 太大(尺寸超标)

第3帧:插入Steiner点
        
           •
          /|\
         / | \
        /  +  \      <-- 新点(Steiner点)
       •---|---•
        \  |  /
         \ | /
          \|/
           •

在坏单元的中心插入新点

第4帧:更新Delaunay三角剖分
        
           •
          /|\
         / | \
        / /|\ \
       •---|---•
        \ \|/ /
         \ | /
          \|/
           •

重新三角化,保持Delaunay性质

第5帧:重复直到满足标准
        
           •
          /|\
         / | \
        /  |  \
       •---+---+•
        \  |  /
         \ | /
          \|/
           •

所有单元都满足质量标准!

9.1.1 数学理论基础

网格生成的定义

三维网格生成是将连续的三维域 离散化为有限个简单几何元素(通常是四面体)的集合,满足:

  1. 覆盖性:所有元素的并集等于目标域
  2. 无重叠:元素之间仅在边界处相交
  3. 形状质量:元素形状满足特定质量标准

Delaunay细化理论

Mesh_3基于**Delaunay细化(Delaunay Refinement)**算法,核心思想是:

通过不断插入Steiner点(网格顶点),直到所有四面体满足质量和尺寸标准。

质量度量可视化

半径-边比(Radius-Edge Ratio)

优质四面体:              劣质四面体:
    
    A                      A
   /|\                    /|
  / | \                  / |
 /  |  \                /  |
B---|---C              B---|---C
 \  |  /                \  |  /
  \ | /                  \ | /
   \|/                    \|/
    D                      D
    
R/L_min ≈ 0.9            R/L_min >> 1
(接近正四面体)          (扁平/细长)

纵横比(Aspect Ratio)

其中 是内切球半径。

二面角(Dihedral Angle)

四面体两个面之间的夹角,范围 。过小的二面角会导致数值不稳定。

二面角示意:

面ABC和面ABD之间的二面角:

       C
      /
     /
    / 二面角θ
   A--------B
    \       /
     \     /
      \   /
       \ /
        D
        
优质四面体:最小二面角 > 15°
劣质四面体:最小二面角 < 1°(接近0的"刀片"四面体)

尺寸场(Sizing Field)

尺寸场 定义了在位置 处期望的网格边长。Mesh_3支持:

  1. 常数尺寸场
  2. 梯度限制尺寸场
  3. 自定义尺寸场:用户提供的任意函数
尺寸场可视化:

常数尺寸场:              自适应尺寸场:

┌───┬───┬───┐           ┌───┬───┬───┐
├───┼───┼───┤           ├───┼───┼───┤
├───┼───┼───┤           ├───┼───┼───┤
└───┴───┴───┘           └───┴───┴───┘

均匀分布                曲面附近加密(小单元)
                        内部稀疏(大单元)

保护球理论(Protected Balls)

对于含特征(边、角)的域,Mesh_3使用**保护球(Protected Balls)**技术:

  1. 在特征边上放置保护球
  2. 保护球内部不进行细化
  3. 保护球确保特征边被正确采样

保护球中心构成一维Delaunay三角剖分,确保边的正确表示。

保护球可视化:

特征边(红色):

    ●─────●─────●
    /\    /\    /\
   /  \  /  \  /  \
  ●────●────●────●
  
保护球(蓝色虚线):

   (●)──(●)──(●)
   /|\  /|\  /|\
  / | \/ | \/ | \
(●)─●──(●)──●─(●)

保护球覆盖特征边,防止细化算法破坏几何特征

拓扑正确性

Mesh_3保证输出网格与输入域同胚(Homeomorphic),即:

这通过以下机制实现:

  • 特征边/角的显式保护
  • 表面逼近精度控制
  • 拓扑一致性检查

9.1.2 架构分析

整体架构

Mesh_3
├── Domain(域定义)
│   ├── Implicit_domain(隐式函数定义)
│   ├── Polyhedral_domain(多面体域)
│   └── Labeled_image_domain(标量场域)
│
├── Criteria(质量标准)
│   ├── Edge_criteria(边标准)
│   ├── Facet_criteria(面标准)
│   └── Cell_criteria(胞腔标准)
│
├── Mesh_complex(网格复形)
│   ├── In_complex_3_to_triangulation_3
│   └── Mesh_complex_3_in_triangulation_3
│
└── Mesh_generation(生成算法)
    ├── Refine_tets(四面体细化)
    ├── Refine_facets(表面细化)
    └── Refine_edges(边细化)

核心类

1. 域概念(Domain Concept)

域定义了要离散化的几何区域:

class Domain {
    // 必需的类型定义
    typedef ... Point_3;
    typedef ... Subdomain_index;
    typedef ... Surface_patch_index;
    typedef ... Curve_index;
    
    // 必需的操作
    Subdomain_index inside(Point_3 p);  // 判断点属于哪个子域
    
    // 表面查询
    AABB_tree surface_aabb_tree();      // 表面加速结构
    
    // 特征查询
    bool is_in_curve(Point_3 p);        // 点是否在特征曲线上
};

2. 质量标准(Criteria)

// 边质量标准
class Edge_criteria {
    double edge_length_bound;  // 边长上界
};
 
// 面质量标准
class Facet_criteria {
    double facet_angle_bound;      // 面内角下界(度)
    double facet_size_bound;       // 面尺寸上界
    double facet_distance_bound;   // 面到表面的距离上界
};
 
// 胞腔质量标准
class Cell_criteria {
    double cell_radius_edge_bound;  // 半径-边比上界
    double cell_size_bound;         // 胞腔尺寸上界
};

3. 网格复形(Mesh Complex)

// 存储网格的拓扑和几何信息
template <class Tr>
class Mesh_complex_3_in_triangulation_3 {
    // 存储在三角剖分中的网格
    Tr* triangulation;
    
    // 特征信息
    std::set<Edge> edges_in_complex;      // 一维特征
    std::set<Facet> facets_in_complex;    // 二维表面
    std::map<Cell, Subdomain_index> cells_in_complex;  // 三维子域
};

细化算法流程

输入:Domain, Criteria
输出:满足标准的网格

1. 初始化
   - 构建初始Delaunay三角剖分
   - 识别域边界点

2. 边细化(Refine Edges)
   while 存在违反边标准的特征边:
       在边中点插入Steiner点

3. 面细化(Refine Facets)
   while 存在违反面标准的表面面片:
       计算表面中心/Steiner点
       插入点并更新三角剖分

4. 体细化(Refine Cells)
   while 存在违反胞腔标准的四面体:
       计算外接球中心
       插入点并更新三角剖分

5. 输出网格

细化过程可视化

步骤1: 初始网格(粗糙)

    ┌─────────┐
   /         /|
  /         / |
 ┌─────────┐  |
 |         |  |
 |    X    |  |    X = 质量差的单元
 |         | /
 |         |/
 └─────────┘

步骤2: 识别坏单元(红色标记)

    ┌─────────┐
   /         /|
  /    X    / |
 ┌─────────┐  |
 |    X    |  |
 |    X    |  |
 |         | /
 |         |/
 └─────────┘

步骤3: 插入Steiner点并细化

    ┌────┬────┐
   /    /    /|
  /    /X   / |
 ┌────┼────┐  |
 |    |X   |  |
 |    ┼────┼──┤
 |    |    | /
 |    |    |/
 └────┴────┘

步骤4: 最终网格(所有单元满足标准)

    ┌───┬───┬───┐
   /   /   /   /|
  ├───┼───┼───┤ |
  ├───┼───┼───┤ |
  ├───┼───┼───┤ |
  ├───┼───┼───┤/
  └───┴───┴───┘

9.1.3 实现细节

1. 域的实现

隐式域

#include <CGAL/Implicit_mesh_domain_3.h>
 
// 定义隐式函数
typedef K::Point_3 Point;
typedef K::FT FT;
 
FT sphere_function(const Point& p) {
    return p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - 1.0;
}
 
// 创建隐式域(单位球)
typedef CGAL::Implicit_mesh_domain_3<FT, K> Domain;
Domain domain(sphere_function, K::Sphere_3(Point(0,0,0), 2.0));

多面体域

#include <CGAL/Polyhedral_mesh_domain_3.h>
#include <CGAL/Polyhedron_3.h>
 
typedef CGAL::Polyhedron_3<K> Polyhedron;
typedef CGAL::Polyhedral_mesh_domain_3<Polyhedron, K> Mesh_domain;
 
// 从多面体创建域
Polyhedron polyhedron;
// ... 构建多面体 ...
 
Mesh_domain domain(polyhedron);

标量图像域

#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
 
// 从3D图像创建域
typedef CGAL::Labeled_mesh_domain_3<K> Labeled_domain;
typedef CGAL::Mesh_domain_with_polyline_features_3<Labeled_domain> Domain;
 
// 加载图像数据
unsigned char* image_data = load_image("brain.inr");
Labeled_domain labeled_domain(image_data, ...);

2. 质量标准的实现

#include <CGAL/Mesh_criteria_3.h>
 
// 定义质量标准
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
 
// 创建标准
Mesh_criteria criteria(
    CGAL::parameters::edge_size = 0.1,                    // 边长
    CGAL::parameters::facet_angle = 25,                   // 面角(度)
    CGAL::parameters::facet_size = 0.1,                   // 面尺寸
    CGAL::parameters::facet_distance = 0.01,              // 面距离
    CGAL::parameters::cell_radius_edge_ratio = 2.0,       // 半径-边比
    CGAL::parameters::cell_size = 0.1                     // 胞腔尺寸
);

3. 网格生成函数

#include <CGAL/make_mesh_3.h>
 
// 生成网格
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
 
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(
    domain,           // 域
    criteria,         // 质量标准
    CGAL::parameters::no_perturb(),           // 不扰动
    CGAL::parameters::no_exude(),             // 不挤出
    CGAL::parameters::manifold()              // 流形表面
);

4. 后处理

扰动(Perturbation)

移动顶点以改善质量:

CGAL::perturb_mesh_3(c3t3, domain, 
    CGAL::parameters::time_limit = 10);  // 时间限制(秒)

挤出(Exudation)

删除低质量四面体:

CGAL::exude_mesh_3(c3t3,
    CGAL::parameters::time_limit = 10,
    CGAL::parameters::sliver_bound = 10);  // 最小二面角(度)

9.1.4 代码示例

完整示例:球体网格

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Implicit_mesh_domain_3.h>
#include <CGAL/make_mesh_3.h>
#include <CGAL/IO/File_medit.h>
 
// 几何内核
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
typedef K::Point_3 Point;
 
// 隐式函数:单位球
FT sphere_function(const Point& p) {
    return p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - 1.0;
}
 
// 域类型
typedef CGAL::Implicit_mesh_domain_3<FT, K> Domain;
 
// 三角剖分类型
typedef CGAL::Mesh_triangulation_3<Domain>::type Tr;
 
// 网格复形类型
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
 
// 质量标准类型
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
 
int main() {
    // 创建域(单位球,包围盒为[-2,2]^3)
    Domain domain(sphere_function, K::Sphere_3(Point(0,0,0), 4.0));
    
    // 设置质量标准
    Mesh_criteria criteria(
        CGAL::parameters::edge_size = 0.15,
        CGAL::parameters::facet_angle = 25,
        CGAL::parameters::facet_size = 0.15,
        CGAL::parameters::facet_distance = 0.01,
        CGAL::parameters::cell_radius_edge_ratio = 2.0,
        CGAL::parameters::cell_size = 0.15
    );
    
    // 生成网格
    C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria);
    
    // 输出统计信息
    std::cout << "顶点数: " << c3t3.triangulation().number_of_vertices() << std::endl;
    std::cout << "胞腔数: " << c3t3.number_of_cells_in_complex() << std::endl;
    std::cout << "表面面片数: " << c3t3.number_of_facets_in_complex() << std::endl;
    
    // 保存到文件
    std::ofstream medit_file("sphere.mesh");
    CGAL::IO::write_MEDIT(medit_file, c3t3);
    medit_file.close();
    
    return 0;
}

多域网格生成

// 定义多子域的隐式函数
FT multi_domain_function(const Point& p) {
    FT d1 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - 1.0;  // 内球
    FT d2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - 4.0;  // 外球
    
    if (d1 < 0) return 1;   // 内球区域
    if (d2 < 0) return 2;   // 球壳区域
    return 0;                // 外部
}
 
// 创建多域
typedef CGAL::Labeled_mesh_domain_3<K> Domain;
 
Domain domain = Domain::create_labeled_image_mesh_domain(
    multi_domain_function,
    K::Sphere_3(Point(0,0,0), 9.0)
);
 
// 为不同子域设置不同标准
Mesh_criteria criteria(
    CGAL::parameters::edge_size = 0.1,
    CGAL::parameters::facet_angle = 25,
    CGAL::parameters::facet_size = 0.1,
    CGAL::parameters::cell_radius_edge_ratio = 2.0,
    CGAL::parameters::cell_size = Field(0.2, 0.1)  // 外域0.2,内域0.1
);

带特征的网格

#include <CGAL/Mesh_domain_with_polyline_features_3.h>
 
// 创建带特征的域
typedef CGAL::Mesh_domain_with_polyline_features_3<Domain> Domain_with_features;
 
Domain_with_features domain_with_features(domain);
 
// 添加多段线特征
std::vector<Point> polyline;
polyline.push_back(Point(-1, 0, 0));
polyline.push_back(Point(1, 0, 0));
 
domain_with_features.add_feature(polyline);
 
// 检测边界特征
domain_with_features.detect_features();
 
// 生成网格
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(
    domain_with_features,
    criteria,
    CGAL::parameters::domain_with_features()
);

实际应用:CFD网格生成

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Implicit_mesh_domain_3.h>
#include <CGAL/make_mesh_3.h>
 
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
typedef K::Point_3 Point;
 
// 定义飞机机翼周围的流场域
FT wing_flow_domain(const Point& p) {
    FT x = p.x(), y = p.y(), z = p.z();
    
    // 外部边界:长方体
    FT box = std::max({std::abs(x) - 5.0, std::abs(y) - 2.0, std::abs(z) - 2.0});
    
    // 简化机翼形状(椭圆柱)
    FT wing = (x*x)/4.0 + (y*y)/0.04 - 1.0;
    
    // 流场域 = 外部边界内且不在机翼内
    if (box > 0) return 0;  // 外部
    if (wing < 0) return 0;  // 机翼内部(固体)
    return 1;  // 流场区域
}
 
int main() {
    // 创建流场域
    typedef CGAL::Implicit_mesh_domain_3<FT, K> Domain;
    Domain domain(wing_flow_domain, K::Sphere_3(Point(0,0,0), 10.0));
    
    // CFD质量标准:
    // - 边界层需要非常薄(高梯度区域)
    // - 远场可以较粗
    typedef CGAL::Mesh_triangulation_3<Domain>::type Tr;
    typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
    typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
    
    // 自适应尺寸场
    auto size_field = [](const Point& p, const int, const Index&) -> FT {
        FT dist_to_wing = std::sqrt(p.y()*p.y() + p.z()*p.z());
        if (dist_to_wing < 0.5) {
            return 0.02;  // 边界层附近:非常密
        } else if (dist_to_wing < 1.0) {
            return 0.05;  // 近场:较密
        } else {
            return 0.2;   // 远场:较粗
        }
    };
    
    Mesh_criteria criteria(
        CGAL::parameters::edge_size = size_field,
        CGAL::parameters::facet_angle = 25,
        CGAL::parameters::facet_size = size_field,
        CGAL::parameters::facet_distance = 0.01,
        CGAL::parameters::cell_radius_edge_ratio = 2.0,
        CGAL::parameters::cell_size = size_field
    );
    
    // 生成网格
    C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria);
    
    std::cout << "CFD网格生成完成:" << std::endl;
    std::cout << "顶点数: " << c3t3.triangulation().number_of_vertices() << std::endl;
    std::cout << "四面体数: " << c3t3.number_of_cells_in_complex() << std::endl;
    
    // 导出到CFD格式(如OpenFOAM)
    // ...
    
    return 0;
}

9.1.5 复杂度分析

时间复杂度

操作复杂度说明
初始化构建初始Delaunay三角剖分
边细化为特征边数
面细化为表面面片数
体细化为四面体数
总生成时间期望复杂度,n为输出顶点数
扰动每轮迭代
挤出删除低质量单元

空间复杂度

  • Delaunay三角剖分
  • 表面采样(表面复杂度)
  • 特征边采样(曲线复杂度)

总空间复杂度:

输出规模

对于体积为 、表面积为 、特征长度为 的域,在均匀尺寸 下:

  • 顶点数:
  • 四面体数:
  • 表面三角形数:

9.1.6 质量标准与算法保证

理论保证

对于满足特定条件的域,Delaunay细化算法保证:

  1. 终止性:算法在有限步内终止
  2. 质量界:输出网格满足预设质量标准
  3. 尺寸界:网格尺寸符合尺寸场要求
  4. 拓扑正确性:网格与输入域同胚

半径-边比界限

CGAL保证输出四面体的半径-边比不超过用户指定值(默认2.0)。这保证了:

  • 无”扁平”四面体
  • 最小二面角有下界(约

表面逼近

通过 facet_distance_bound 参数控制表面逼近精度:

其中 是Hausdorff距离。

参数选择指南

不同应用场景的参数建议

应用edge_sizefacet_anglefacet_distancecell_radius_edgecell_size
结构力学0.05-0.125-300.001-0.012.0-3.00.05-0.1
流体力学0.01-0.0520-250.0001-0.0012.00.01-0.05
生物医学0.1-0.525-300.01-0.053.0-4.00.1-0.5
地质建模0.5-2.020-250.1-0.54.0-5.00.5-2.0

9.1.7 与其他组件的关系

Mesh_3
├── 依赖
│   ├── Delaunay_triangulation_3(基础三角剖分)
│   ├── AABB_tree(表面查询加速)
│   └── Implicit_surface_3(隐式表面)
│
├── 相关工具
│   ├── CGAL::Polygon_mesh_processing(网格处理)
│   └── CGAL::Tetrahedral_remeshing(四面体重网格化)
│
└── 应用
    ├── 有限元分析(FEM)
    ├── 计算流体力学(CFD)
    └── 生物医学建模

9.1.8 总结

Mesh_3提供了:

  1. 全自动网格生成:从几何描述到高质量网格
  2. 严格质量保证:半径-边比、二面角等标准
  3. 自适应细化:根据几何复杂度自动调整
  4. 拓扑正确性:保证与输入域同胚
  5. 多域支持:处理材料界面和复杂装配体

Mesh_3是工程计算和科学模拟的关键工具,广泛应用于航空航天、汽车、能源、生物医学等领域。