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 数学理论基础
网格生成的定义
三维网格生成是将连续的三维域 离散化为有限个简单几何元素(通常是四面体)的集合,满足:
- 覆盖性:所有元素的并集等于目标域
- 无重叠:元素之间仅在边界处相交
- 形状质量:元素形状满足特定质量标准
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支持:
- 常数尺寸场:
- 梯度限制尺寸场:
- 自定义尺寸场:用户提供的任意函数
尺寸场可视化:
常数尺寸场: 自适应尺寸场:
┌───┬───┬───┐ ┌───┬───┬───┐
├───┼───┼───┤ ├───┼───┼───┤
├───┼───┼───┤ ├───┼───┼───┤
└───┴───┴───┘ └───┴───┴───┘
均匀分布 曲面附近加密(小单元)
内部稀疏(大单元)
保护球理论(Protected Balls)
对于含特征(边、角)的域,Mesh_3使用**保护球(Protected Balls)**技术:
- 在特征边上放置保护球
- 保护球内部不进行细化
- 保护球确保特征边被正确采样
保护球中心构成一维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细化算法保证:
- 终止性:算法在有限步内终止
- 质量界:输出网格满足预设质量标准
- 尺寸界:网格尺寸符合尺寸场要求
- 拓扑正确性:网格与输入域同胚
半径-边比界限
CGAL保证输出四面体的半径-边比不超过用户指定值(默认2.0)。这保证了:
- 无”扁平”四面体
- 最小二面角有下界(约)
表面逼近
通过 facet_distance_bound 参数控制表面逼近精度:
其中 是Hausdorff距离。
参数选择指南
不同应用场景的参数建议:
| 应用 | edge_size | facet_angle | facet_distance | cell_radius_edge | cell_size |
|---|---|---|---|---|---|
| 结构力学 | 0.05-0.1 | 25-30 | 0.001-0.01 | 2.0-3.0 | 0.05-0.1 |
| 流体力学 | 0.01-0.05 | 20-25 | 0.0001-0.001 | 2.0 | 0.01-0.05 |
| 生物医学 | 0.1-0.5 | 25-30 | 0.01-0.05 | 3.0-4.0 | 0.1-0.5 |
| 地质建模 | 0.5-2.0 | 20-25 | 0.1-0.5 | 4.0-5.0 | 0.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提供了:
- 全自动网格生成:从几何描述到高质量网格
- 严格质量保证:半径-边比、二面角等标准
- 自适应细化:根据几何复杂度自动调整
- 拓扑正确性:保证与输入域同胚
- 多域支持:处理材料界面和复杂装配体
Mesh_3是工程计算和科学模拟的关键工具,广泛应用于航空航天、汽车、能源、生物医学等领域。