第11章 STL重网格:无CAD模型的表面重构
11.1 学习目标
- 理解CAE前处理中"只有STL网格、无CAD几何"场景的处理流程
- 掌握
classifySurfaces()进行拓扑识别和createGeometry()生成参数化几何 - 学会对离散表面重新划分网格(改变密度/单元类型)
- 了解ONELAB参数化接口的基本使用
11.2 核心概念说明
11.2.1 为什么需要STL重网格
在CAE前处理中,模型的来源多种多样:
- 逆向工程:3D扫描 → STL点云 → 三角面片
- 医学影像:CT/MRI → 分割 → STL表面网格
- 外部数据:第三方软件导出的STL(可能不含CAD信息)
这些场景的共同特点是:只有离散的三角面片,没有参数化CAD几何。直接使用原始STL做有限元分析通常会遇到网格质量差、单元数量不可控、无法局部细化等问题。
Gmsh提供了从STL重建参数化几何、然后重新划分网格的能力。
11.2.2 处理流程
STL文件 ──merge()──> 离散三角网格
└── classifySurfaces() ──> 识别尖锐特征,创建离散实体(面/线/点)
└── createGeometry() ──> 为每个离散面计算参数化(u,v)
└── addSurfaceLoop + Volume ──> 构建体
└── mesh::generate() ──> 在参数化几何上重新划分网格
如果有STEP等CAD格式可用(参见第18章),优先使用CAD模型而非STL重网格。CAD几何的精度更高、参数化更光滑,网格质量也更好。
11.2.3 ONELAB参数接口
Gmsh提供了ONELAB参数系统,允许在GUI中动态调整参数并触发热更新。本章示例通过 gmsh::onelab::set() 定义三个参数(分类角度、强制参数化、趣味尺寸场),在GUI中修改后自动重新构建几何和网格。
11.3 C++代码逐段讲解
11.3.1 导入STL文件
#include <gmsh.h>
gmsh::initialize();
gmsh::model::add("t13");
try {
gmsh::merge("../t13_data.stl"); // 加载STL三角面片
} catch(...) {
gmsh::logger::write("Could not load STL mesh: bye!");
return;
}
merge() 可以加载STL、MSH、POS等多种格式。try/catch保护是为了在文件缺失时优雅退出。
11.3.2 表面分类(拓扑识别)
double angle = 40; // 尖锐边判定角度(度)
bool includeBoundary = true;
bool forceParametrizablePatches = false;
double curveAngle = 180; // 强制分割曲线的角度
gmsh::model::mesh::classifySurfaces(
angle * M_PI / 180., // 弧度=角度*pi/180
includeBoundary, // 包含边界边
forceParametrizablePatches,// 强制生成可参数化的patch
curveAngle * M_PI / 180. // 曲线分割角度
);
classifySurfaces() 做四件事:
1. 检测相邻三角面片间的二面角,大于 angle 的边标记为尖锐边
2. 沿尖锐边将原始表面分割为多个离散面(discrete surface)
3. 创建离散曲线(discrete curve,标签从1开始)和离散点
4. 建立面-线-点的拓扑关系
参数说明:
- angle:越小越敏感,识别出更多尖锐特征(更多分割)
- includeBoundary:开表面是否将边界纳入分类
- forceParametrizablePatches:对复杂patch强制分割为可参数化的小patch
- curveAngle:大于此角度的曲线节点会被分割
11.3.3 生成参数化几何
gmsh::model::mesh::createGeometry();
createGeometry() 为每个离散面计算 $R^2 \rightarrow R^3$ 的参数映射(u, v坐标),使得后续可以在参数空间上重新划分网格。这一步是STL重网格的关键。
11.3.4 构建体并设置网格尺寸
// 获取所有离散面,构建SurfaceLoop和Volume
std::vector<std::pair<int, int>> s;
gmsh::model::getEntities(s, 2); // 获取所有2D实体
std::vector<int> sl;
for(auto surf : s) sl.push_back(surf.second);
int l = gmsh::model::geo::addSurfaceLoop(sl);
gmsh::model::geo::addVolume({l});
gmsh::model::geo::synchronize();
// 用MathEval尺寸场控制重网格密度
int f = gmsh::model::mesh::field::add("MathEval");
gmsh::model::mesh::field::setString(f, "F", "4"); // 全场均匀尺寸=4
gmsh::model::mesh::field::setAsBackgroundMesh(f);
gmsh::model::mesh::generate(3);
尺寸场设为常数 "F"="4" 得到全场均匀网格。你可以用更复杂的表达式来实现局部细化。
11.4 完整可运行代码
// ch11_stl_remesh.cpp — STL重网格示例
#include <set>
#include <cmath>
#include <gmsh.h>
int main(int argc, char **argv)
{
gmsh::initialize();
gmsh::model::add("ch11");
// 1. 导入STL文件
try {
gmsh::merge("path/to/your_model.stl");
} catch(...) {
gmsh::logger::write("STL file not found!");
gmsh::finalize();
return 1;
}
// 2. 表面分类(角度=40度,含边界)
double angle = 40;
gmsh::model::mesh::classifySurfaces(
angle * M_PI / 180., true, false, M_PI);
// 3. 创建参数化几何
gmsh::model::mesh::createGeometry();
// 4. 构建体(如果STL是闭合的)
std::vector<std::pair<int, int>> s;
gmsh::model::getEntities(s, 2);
std::vector<int> sl;
for(auto &e : s) sl.push_back(e.second);
int l = gmsh::model::geo::addSurfaceLoop(sl);
gmsh::model::geo::addVolume({l});
gmsh::model::geo::synchronize();
// 5. 设置网格尺寸并生成
int f = gmsh::model::mesh::field::add("MathEval");
gmsh::model::mesh::field::setString(f, "F", "4");
gmsh::model::mesh::field::setAsBackgroundMesh(f);
gmsh::model::mesh::generate(3);
gmsh::write("remeshed.msh");
std::set<std::string> args(argv, argv + argc);
if(!args.count("-nopopup")) gmsh::fltk::run();
gmsh::finalize();
return 0;
}
11.5 关键API速查表
| API | 说明 |
|---|---|
merge(filename) |
加载STL/MSH/POS等文件 |
mesh::classifySurfaces(angle, boundary, forceParam, curveAngle) |
识别尖锐特征,创建离散实体和拓扑 |
mesh::createGeometry() |
为离散面生成参数化(u,v)映射 |
geo::addSurfaceLoop({surfaceTags}) |
由面列表构建面环 |
geo::addVolume({surfaceLoopTags}) |
由面环列表构建体 |
11.6 注意事项
- 优先使用CAD格式:如果有STEP/IGES可用,使用第18章的OpenCASCADE导入方法,几何精度远高于STL重建
- 分类角度调节:
angle太小会产生过多碎面(难以参数化),太大则丢失几何特征。40°是经验出发点 - 闭合性要求:STL必须是水密的(watertight)才能构建Volume;开表面只能做2D重网格
- 参数化质量:极细长的patch可能导致参数化失败,可尝试
forceParametrizablePatches=true - 大模型性能:STL面片数超过数十万时,
classifySurfaces()和createGeometry()可能耗时较长