第5章 三维网格控制:尺寸场、体孔洞与网格算法
5.1 学习目标
- 理解网格特征长度(Characteristic Length,
lc)的分级控制策略:不同几何点设置不同lc值,实现局部网格加密 - 掌握
Mesh.MeshSizeFactor全局缩放因子的用法,理解其与命令行参数-clscale的等价关系 - 学会通过
addSurfaceLoop+addVolume构建含孔洞的三维实体(Volume with Holes) - 了解三维网格算法选择机制:全局选项
Mesh.Algorithm与逐面设置mesh::setAlgorithm() - 掌握高阶网格(High-Order Mesh)与选择性可见性网格划分(MeshOnlyVisible)的配置方法
5.2 核心概念说明
5.2.1 分级网格尺寸控制
在前几章中,所有几何点通常使用同一个 lc 值。在实际 CAE 前处理中,我们经常需要对不同区域设置不同的网格密度——例如应力集中区使用细网格,远场区域使用粗网格。Gmsh 通过在定义点时指定不同的 lc 参数实现这一目标:
// 点 1:密集网格(lc 小)
gmsh::model::geo::addPoint(0.5, 0.5, 0.5, lcar2 /*=0.0005*/, 1);
// 点 2:稀疏网格(lc 大)
gmsh::model::geo::addPoint(0.5, 0.5, 0, lcar1 /*=0.1*/, 2);
lc 值表示该点附近的期望网格边长。值越小,网格越密集。Gmsh 的网格生成器会在各点之间平滑过渡网格尺寸。
5.2.2 MeshSizeFactor 全局缩放
当需要整体调整网格密度(例如做收敛性研究)而不修改每个点的 lc 值时,可以使用全局缩放因子:
gmsh::option::setNumber("Mesh.MeshSizeFactor", 0.1);
这会将所有点的 lc 乘以 0.1 后送入网格生成器。等效的命令行参数为:
./t5.exe -clscale 0.2
缩放因子 clscale 取值为 1 时保持原始尺寸,取值越小网格越密。例如 t5 教程中:
- clscale=1:约 3000 节点、14000 四面体
- clscale=0.2:约 231000 节点、1360000 四面体
5.2.3 从 SurfaceLoop 到 Volume
在三维建模中,Gmsh 使用层级结构构建实体:
- 曲面(Surface):由曲线环(Curve Loop)定义,可以是平面(
addPlaneSurface)或非平面(addSurfaceFilling) - 曲面环(Surface Loop):一组闭合的曲面集合,形成"壳"(Shell)
- 体(Volume):由曲面环定义的三维实体
构建含孔洞的体的关键规则:
- addVolume 的参数是一个曲面环标签列表
- 第一个曲面环定义体的外边界(exterior boundary)
- 后续曲面环定义体内的孔洞(holes)
// shells[0] 是外边界,shells[1..5] 是 5 个球面孔洞
int ve = gmsh::model::geo::addVolume(shells);
5.2.4 非平曲面与球面孔洞
对于球面等非平曲面,Gmsh 内置几何内核提供 addSurfaceFilling 函数。当边界曲线是以同一点为圆心的圆弧(Circle Arc)时,该函数自动生成球面片(spherical patch);否则使用超限插值(transfinite interpolation)。
每个球面孔洞由 8 个球面三角形片(对应球面八面体剖分)构成,通过 8 个曲面环和 12 条圆弧定义。
5.2.5 三维网格算法概览
Gmsh 支持多种三维网格生成算法,通过 Mesh.Algorithm 选项全局设置:
| 值 | 算法名称 | 适用维度 | 特点 |
|---|---|---|---|
| 1 | MeshAdapt | 2D | 自适应网格,稳定性好 |
| 5 | Delaunay | 2D | 经典 Delaunay 三角剖分 |
| 6 | Frontal-Delaunay | 2D | 前沿推进 + Delaunay,质量更优 |
| 7 | BAMG | 2D | 各向异性,需要额外安装 |
| 8 | Delaunay for Quads | 2D | 四边形 Delaunay |
| 9 | Packing of Parallelograms | 2D | 平行四边形填充 |
此外,可以对特定面单独设置算法:
// 对 dim=2, tag=33 的面使用 MeshAdapt(算法1)
gmsh::model::mesh::setAlgorithm(2, 33, 1);
5.2.6 高阶网格
为生成曲线网格(curvilinear mesh)以更好地贴合几何曲率,可以启用高阶单元:
gmsh::option::setNumber("Mesh.ElementOrder", 2); // 二阶单元
gmsh::option::setNumber("Mesh.HighOrderOptimize", 2); // 高阶优化(保证有效性)
HighOrderOptimize 使用基于 Johnen 等人(2013)和 Toulorge 等人(2013)的方法,对曲线单元进行几何有效性优化和去纠缠(untangling)。
5.2.7 选择性可见性网格划分
有时我们只希望对模型的某一部分进行网格划分。Gmsh 支持隐藏实体并仅对可见部分生成网格:
// 隐藏所有实体
std::vector<std::pair<int, int>> entities;
gmsh::model::getEntities(entities);
gmsh::model::setVisibility(entities, false);
// 仅显示体 tag=5
gmsh::model::setVisibility({{3, 5}}, true, true);
// 仅对可见部分生成网格
gmsh::option::setNumber("Mesh.MeshOnlyVisible", 1);
5.3 C++ 代码逐段讲解
5.3.1 球面孔洞辅助函数 cheeseHole
这是本章最核心的函数,它创建一个球面孔洞并返回其曲面环和体标签。我们将逐步拆解其实现。
void cheeseHole(double x, double y, double z, double r, double lc,
std::vector<int> &shells, std::vector<int> &volumes)
{
参数说明:
- (x, y, z):球心坐标
- r:球半径
- lc:该孔洞周边的网格特征长度
- shells:输出参数,添加该孔洞的曲面环标签
- volumes:输出参数,添加该孔洞的体标签
步骤一:定义球面上的 7 个关键点
int p1 = gmsh::model::geo::addPoint(x, y, z, lc); // 球心
int p2 = gmsh::model::geo::addPoint(x + r, y, z, lc); // +x 方向
int p3 = gmsh::model::geo::addPoint(x, y + r, z, lc); // +y 方向
int p4 = gmsh::model::geo::addPoint(x, y, z + r, lc); // +z 方向
int p5 = gmsh::model::geo::addPoint(x - r, y, z, lc); // -x 方向
int p6 = gmsh::model::geo::addPoint(x, y - r, z, lc); // -y 方向
int p7 = gmsh::model::geo::addPoint(x, y, z - r, lc); // -z 方向
这 7 个点构成球面的八面体近似框架:p1 是球心(用作所有圆弧的中心),p2 到 p7 是球面上的 6 个顶点(分别位于 6 个坐标轴方向上)。
步骤二:创建球面上的 12 条大圆弧
每条圆弧的圆心都是 p1(球心),使得这些圆弧位于球面上:
int c1 = gmsh::model::geo::addCircleArc(p2, p1, p7);
int c2 = gmsh::model::geo::addCircleArc(p7, p1, p5);
int c3 = gmsh::model::geo::addCircleArc(p5, p1, p4);
int c4 = gmsh::model::geo::addCircleArc(p4, p1, p2);
int c5 = gmsh::model::geo::addCircleArc(p2, p1, p3);
int c6 = gmsh::model::geo::addCircleArc(p3, p1, p5);
int c7 = gmsh::model::geo::addCircleArc(p5, p1, p6);
int c8 = gmsh::model::geo::addCircleArc(p6, p1, p2);
int c9 = gmsh::model::geo::addCircleArc(p7, p1, p3);
int c10 = gmsh::model::geo::addCircleArc(p3, p1, p4);
int c11 = gmsh::model::geo::addCircleArc(p4, p1, p6);
int c12 = gmsh::model::geo::addCircleArc(p6, p1, p7);
这 12 条大圆弧将球面划分为 8 个球面三角形区域(上下左右前后各四分之一)。每段圆弧角度为 90 度,符合 addCircleArc 的 Pi 限制。
步骤三:构建 8 个曲线环与球面片
int l1 = gmsh::model::geo::addCurveLoop({c5, c10, c4});
int l2 = gmsh::model::geo::addCurveLoop({c9, -c5, c1});
int l3 = gmsh::model::geo::addCurveLoop({c12, -c8, -c1});
int l4 = gmsh::model::geo::addCurveLoop({c8, -c4, c11});
int l5 = gmsh::model::geo::addCurveLoop({-c10, c6, c3});
int l6 = gmsh::model::geo::addCurveLoop({-c11, -c3, c7});
int l7 = gmsh::model::geo::addCurveLoop({-c2, -c7, -c12});
int l8 = gmsh::model::geo::addCurveLoop({-c6, -c9, c2});
每个曲线环由 3 条圆弧构成(球面三角形边界)。负号用于调整方向,确保每个环的法向量一致。
int s1 = gmsh::model::geo::addSurfaceFilling({l1});
int s2 = gmsh::model::geo::addSurfaceFilling({l2});
int s3 = gmsh::model::geo::addSurfaceFilling({l3});
int s4 = gmsh::model::geo::addSurfaceFilling({l4});
int s5 = gmsh::model::geo::addSurfaceFilling({l5});
int s6 = gmsh::model::geo::addSurfaceFilling({l6});
int s7 = gmsh::model::geo::addSurfaceFilling({l7});
int s8 = gmsh::model::geo::addSurfaceFilling({l8});
由于所有边界圆弧共享同一个圆心 p1,addSurfaceFilling 自动识别并生成球面片,而非平面超限插值。
步骤四:组合曲面环与体,输出结果
int sl = gmsh::model::geo::addSurfaceLoop({s1, s2, s3, s4, s5, s6, s7, s8});
int v = gmsh::model::geo::addVolume({sl});
shells.push_back(sl);
volumes.push_back(v);
}
8 个球面片构成一个封闭壳体(曲面环),再由它定义孔洞体。调用者通过 shells 和 volumes 获取生成的标签。
5.3.2 构建截断立方体主体
截断立方体(truncated cube)是一个将角切掉的立方体,共 14 个顶点、21 条边、9 个平面面:
// 截断立方体的 14 个顶点
gmsh::model::geo::addPoint(0.5, 0.5, 0.5, lcar2, 1); // 切角点(密集)
gmsh::model::geo::addPoint(0.5, 0.5, 0, lcar1, 2);
gmsh::model::geo::addPoint(0, 0.5, 0.5, lcar1, 3);
// ... 其余点省略,使用 lcar1
注意点 1 使用了较小的 lcar2(=0.0005),使其周边网格显著加密,而其余点使用较大的 lcar1(=0.1)。这种不均匀的尺寸分布在生成的网格中表现为:从点 1 向外逐渐过渡,尺寸从极小增加到正常。
外边界曲面环由 9 个平面面构成:
int sl = gmsh::model::geo::addSurfaceLoop(
{35, 31, 29, 37, 33, 23, 39, 25, 27});
shells.push_back(sl);
5.3.3 在体内创建 5 个球面孔洞
使用循环在截断立方体内部依次放置 5 个球面孔洞:
double x = 0, y = 0.75, z = 0, r = 0.09;
for (int t = 1; t <= 5; t++) {
x += 0.166;
z += 0.166;
cheeseHole(x, y, z, r, lcar3, shells, volumes);
gmsh::model::geo::addPhysicalGroup(3, {volumes.back()}, t);
std::printf("Hole %d (center = {%g,%g,%g}, radius = %g) has number %d!\n",
t, x, y, z, r, volumes.back());
}
每个孔洞创建后,立即将其体标签加入物理组(dim=3),物理组标签 t 用于在求解器中区分不同的孔洞。
5.3.4 定义含孔洞的最终实体
int ve = gmsh::model::geo::addVolume(shells);
gmsh::model::geo::synchronize();
gmsh::model::addPhysicalGroup(3, {ve}, 10);
shells 向量中,第一个元素是截断立方体的外表面曲面环,后续 5 个元素是球面孔洞的曲面环。addVolume 将第一个作为外边界,其余作为内孔洞,生成"瑞士奶酪"状的实体。
物理组标签 10 用于标识去除孔洞后的立方体区域(dim=3)。
5.3.5 配置网格生成选项
全局算法设置:
gmsh::option::setNumber("Mesh.Algorithm", 6); // Frontal-Delaunay
逐面设置:对面 tag=33 单独使用 MeshAdapt 算法:
gmsh::model::mesh::setAlgorithm(2, 33, 1);
高阶网格(可选,注释掉的代码):
// gmsh::option::setNumber("Mesh.ElementOrder", 2);
// gmsh::option::setNumber("Mesh.HighOrderOptimize", 2);
选择性可见性网格划分(可选,注释掉的代码):
// std::vector<std::pair<int, int>> ent;
// gmsh::model::getEntities(ent);
// gmsh::model::setVisibility(ent, false);
// gmsh::model::setVisibility({{3, 5}}, true, true);
// gmsh::option::setNumber("Mesh.MeshOnlyVisible", 1);
5.3.6 网格生成与输出
gmsh::model::mesh::generate(3);
gmsh::write("t5.msh");
std::set<std::string> args(argv, argv + argc);
if (!args.count("-nopopup")) gmsh::fltk::run();
gmsh::finalize();
return 0;
5.4 完整可运行代码
// ch05_full.cpp — 截断立方体 + 5 个球面孔洞完整示例
#include <set>
#include <cstdio>
#include <gmsh.h>
// 创建球面孔洞辅助函数
void cheeseHole(double x, double y, double z, double r, double lc,
std::vector<int> &shells, std::vector<int> &volumes)
{
namespace factory = gmsh::model::geo;
// 球面上 7 个关键点(球心 + 6 个极点)
int p1 = factory::addPoint(x, y, z, lc);
int p2 = factory::addPoint(x + r, y, z, lc);
int p3 = factory::addPoint(x, y + r, z, lc);
int p4 = factory::addPoint(x, y, z + r, lc);
int p5 = factory::addPoint(x - r, y, z, lc);
int p6 = factory::addPoint(x, y - r, z, lc);
int p7 = factory::addPoint(x, y, z - r, lc);
// 12 条大圆弧(圆心均为 p1)
int c1 = factory::addCircleArc(p2, p1, p7);
int c2 = factory::addCircleArc(p7, p1, p5);
int c3 = factory::addCircleArc(p5, p1, p4);
int c4 = factory::addCircleArc(p4, p1, p2);
int c5 = factory::addCircleArc(p2, p1, p3);
int c6 = factory::addCircleArc(p3, p1, p5);
int c7 = factory::addCircleArc(p5, p1, p6);
int c8 = factory::addCircleArc(p6, p1, p2);
int c9 = factory::addCircleArc(p7, p1, p3);
int c10 = factory::addCircleArc(p3, p1, p4);
int c11 = factory::addCircleArc(p4, p1, p6);
int c12 = factory::addCircleArc(p6, p1, p7);
// 8 个曲线环 + 8 个球面片
int l1 = factory::addCurveLoop({c5, c10, c4});
int l2 = factory::addCurveLoop({c9, -c5, c1});
int l3 = factory::addCurveLoop({c12, -c8, -c1});
int l4 = factory::addCurveLoop({c8, -c4, c11});
int l5 = factory::addCurveLoop({-c10, c6, c3});
int l6 = factory::addCurveLoop({-c11, -c3, c7});
int l7 = factory::addCurveLoop({-c2, -c7, -c12});
int l8 = factory::addCurveLoop({-c6, -c9, c2});
int s1 = factory::addSurfaceFilling({l1});
int s2 = factory::addSurfaceFilling({l2});
int s3 = factory::addSurfaceFilling({l3});
int s4 = factory::addSurfaceFilling({l4});
int s5 = factory::addSurfaceFilling({l5});
int s6 = factory::addSurfaceFilling({l6});
int s7 = factory::addSurfaceFilling({l7});
int s8 = factory::addSurfaceFilling({l8});
int sl = factory::addSurfaceLoop({s1, s2, s3, s4, s5, s6, s7, s8});
int v = factory::addVolume({sl});
shells.push_back(sl);
volumes.push_back(v);
}
int main(int argc, char **argv)
{
gmsh::initialize(argc, argv);
gmsh::model::add("ch05_truncated_cube_with_holes");
namespace factory = gmsh::model::geo;
double lcar1 = 0.1; // 稀疏区域 lc
double lcar2 = 0.0005; // 点 1 附近密集 lc
double lcar3 = 0.055; // 孔洞周边 lc
// ---- 如果想全局缩放,取消此注释 ----
// gmsh::option::setNumber("Mesh.MeshSizeFactor", 0.1);
// ---- 截断立方体的 14 个顶点 ----
factory::addPoint(0.5, 0.5, 0.5, lcar2, 1);
factory::addPoint(0.5, 0.5, 0, lcar1, 2);
factory::addPoint(0, 0.5, 0.5, lcar1, 3);
factory::addPoint(0, 0, 0.5, lcar1, 4);
factory::addPoint(0.5, 0, 0.5, lcar1, 5);
factory::addPoint(0.5, 0, 0, lcar1, 6);
factory::addPoint(0, 0.5, 0, lcar1, 7);
factory::addPoint(0, 1, 0, lcar1, 8);
factory::addPoint(1, 1, 0, lcar1, 9);
factory::addPoint(0, 0, 1, lcar1, 10);
factory::addPoint(0, 1, 1, lcar1, 11);
factory::addPoint(1, 1, 1, lcar1, 12);
factory::addPoint(1, 0, 1, lcar1, 13);
factory::addPoint(1, 0, 0, lcar1, 14);
// ---- 21 条直线边 ----
factory::addLine(8, 9, 1); factory::addLine(9, 12, 2);
factory::addLine(12, 11, 3); factory::addLine(11, 8, 4);
factory::addLine(9, 14, 5); factory::addLine(14, 13, 6);
factory::addLine(13, 12, 7); factory::addLine(11, 10, 8);
factory::addLine(10, 13, 9); factory::addLine(10, 4, 10);
factory::addLine(4, 5, 11); factory::addLine(5, 6, 12);
factory::addLine(6, 2, 13); factory::addLine(2, 1, 14);
factory::addLine(1, 3, 15); factory::addLine(3, 7, 16);
factory::addLine(7, 2, 17); factory::addLine(3, 4, 18);
factory::addLine(5, 1, 19); factory::addLine(7, 8, 20);
factory::addLine(6, 14, 21);
// ---- 9 个曲线环 + 9 个平面面 ----
factory::addCurveLoop({-11, -19, -15, -18}, 22);
factory::addPlaneSurface({22}, 23);
factory::addCurveLoop({16, 17, 14, 15}, 24);
factory::addPlaneSurface({24}, 25);
factory::addCurveLoop({-17, 20, 1, 5, -21, 13}, 26);
factory::addPlaneSurface({26}, 27);
factory::addCurveLoop({-4, -1, -2, -3}, 28);
factory::addPlaneSurface({28}, 29);
factory::addCurveLoop({-7, 2, -5, -6}, 30);
factory::addPlaneSurface({30}, 31);
factory::addCurveLoop({6, -9, 10, 11, 12, 21}, 32);
factory::addPlaneSurface({32}, 33);
factory::addCurveLoop({7, 3, 8, 9}, 34);
factory::addPlaneSurface({34}, 35);
factory::addCurveLoop({-10, 18, -16, -20, 4, -8}, 36);
factory::addPlaneSurface({36}, 37);
factory::addCurveLoop({-14, -13, -12, 19}, 38);
factory::addPlaneSurface({38}, 39);
std::vector<int> shells, volumes;
// 外边界曲面环
int sl = factory::addSurfaceLoop(
{35, 31, 29, 37, 33, 23, 39, 25, 27});
shells.push_back(sl);
// ---- 创建 5 个球面孔洞 ----
double x = 0, y = 0.75, z = 0, r = 0.09;
for (int t = 1; t <= 5; t++) {
x += 0.166;
z += 0.166;
cheeseHole(x, y, z, r, lcar3, shells, volumes);
factory::addPhysicalGroup(3, {volumes.back()}, t);
std::printf("Hole %d (center = {%g,%g,%g}, radius = %g) has number %d!\n",
t, x, y, z, r, volumes.back());
}
// 含孔洞的体:第一个曲面环是外边界,后续的是孔洞
int ve = factory::addVolume(shells);
factory::synchronize();
// 物理组:体 ve 标识去除孔洞后的立方体区域
gmsh::model::addPhysicalGroup(3, {ve}, 10);
// ---- 网格算法配置 ----
gmsh::option::setNumber("Mesh.Algorithm", 6); // Frontal-Delaunay (2D)
gmsh::model::mesh::setAlgorithm(2, 33, 1); // 面 33 单独使用 MeshAdapt
// ---- 高阶网格(可选,取消注释启用) ----
// gmsh::option::setNumber("Mesh.ElementOrder", 2);
// gmsh::option::setNumber("Mesh.HighOrderOptimize", 2);
// ---- 选择性可见性网格划分(可选,取消注释启用) ----
// std::vector<std::pair<int, int>> ent;
// gmsh::model::getEntities(ent);
// gmsh::model::setVisibility(ent, false);
// gmsh::model::setVisibility({{3, 5}}, true, true);
// gmsh::option::setNumber("Mesh.MeshOnlyVisible", 1);
// ---- 生成三维网格 ----
gmsh::model::mesh::generate(3);
gmsh::write("ch05_result.msh");
// 启动 GUI(除非传入了 -nopopup)
std::set<std::string> args(argv, argv + argc);
if (!args.count("-nopopup")) gmsh::fltk::run();
gmsh::finalize();
return 0;
}
5.5 关键 API 速查表
尺寸控制
| 函数 / 选项 | 说明 |
|---|---|
factory::addPoint(x, y, z, lc, tag) |
定义点及其局部网格特征长度 |
gmsh::option::setNumber("Mesh.MeshSizeFactor", factor) |
全局尺寸缩放因子 |
命令行 -clscale <factor> |
等效于 Mesh.MeshSizeFactor |
曲面与体构建
| 函数 | 说明 |
|---|---|
factory::addCircleArc(start, center, end, tag) |
三点圆弧(弧度 < Pi) |
factory::addCurveLoop({curveTags}, tag) |
由曲线列表构成闭合环 |
factory::addPlaneSurface({loopTags}, tag) |
平面面:第一个环=外边界,其余=孔洞 |
factory::addSurfaceFilling({loopTag}, tag) |
非平曲面填充:圆弧共中心则生成球面片 |
factory::addSurfaceLoop({surfaceTags}, tag) |
由一组曲面构成封闭壳体 |
factory::addVolume({surfaceLoopTags}, tag) |
定义体:第一个环=外边界,其余=内孔洞 |
网格算法
| 函数 / 选项 | 说明 |
|---|---|
gmsh::option::setNumber("Mesh.Algorithm", algo) |
全局设置网格算法(1/5/6/7/8/9) |
gmsh::model::mesh::setAlgorithm(dim, tag, algo) |
对指定实体单独设置算法 |
gmsh::option::setNumber("Mesh.ElementOrder", N) |
设置单元阶次(1=线性, 2=二阶) |
gmsh::option::setNumber("Mesh.HighOrderOptimize", opt) |
高阶曲线单元优化策略 |
gmsh::model::mesh::generate(3) |
生成三维网格 |
实体可见性与物理组
| 函数 | 说明 |
|---|---|
gmsh::model::getEntities(entities) |
获取所有实体列表 {dim, tag} |
gmsh::model::setVisibility(entities, visible) |
设置实体可见性 |
gmsh::model::setVisibility(entities, visible, recursive) |
递归设置可见性 |
gmsh::option::setNumber("Mesh.MeshOnlyVisible", 1) |
仅对可见实体生成网格 |
gmsh::model::addPhysicalGroup(dim, {tags}, tag) |
将实体分组为物理组(dim=3 为体组) |
注意事项
lc分级策略:在不同关键点设置不同的lc值,Gmsh 会在各点之间平滑过渡网格尺寸。网格尺寸从lc最小的点向外逐渐增大。- 全局缩放:
Mesh.MeshSizeFactor是在所有lc值计算完毕后应用的乘法因子。用于收敛性研究的网格加密而不需要重新定义几何。 - 圆弧角度限制:内置几何内核中,
addCircleArc的弧度必须小于 Pi。完整圆至少需要 3 段圆弧。本章球面孔洞使用 12 段,每段 90 度。 - 曲面填充的选择:
addSurfaceFilling适用于 3 或 4 条边界的曲面;当所有边界圆弧共享同一圆心时自动生成球面片。如有更多边界曲线,可使用 OpenCASCADE 内核的gmsh::model::occ::addSurfaceFilling。 - 体的孔洞规则:
addVolume的参数列表中,第一个曲面环定义外边界,后续曲面环定义内部孔洞。孔洞不能与外部边界相交或超出外部边界。 - 物理组用于区域标识:在本章中,dim=3 的物理组用于区分立方体材料区域(tag=10)和各个球面孔洞(tag=1..5),方便在求解器中施加不同属性。
- 选择性网格划分:设置
Mesh.MeshOnlyVisible = 1后,generate()仅处理当前可见的实体,这在调试或分步划分大型模型时非常有用。 - 编译命令(链接 Gmsh 库):
g++ -o ch05_full ch05_full.cpp -lgmsh -std=c++11使用时可通过./ch05_full -clscale 0.5控制全局网格密度。