Skip to content

第20章 后处理插件(Plugin):视图数据运算与变换


20.1 学习目标

  • 理解 Gmsh 插件系统(Plugin)的定位:对后处理视图(View)数据进行运算、变换与可视化增强的模块化工具集
  • 掌握 plugin::setNumber() / plugin::setString() 设置插件参数、plugin::run() 执行插件并生成新视图的标准工作流
  • 熟练使用六种常用内置插件:等值面(Isosurface)、切平面(CutPlane)、二维截面映射(CutMap)、表面提取(Skin)、流线图(StreamLines)与探针采样(Probe)
  • 理解插件运行结果自动产生新 View 的机制,以及多插件串联构建后处理流水线的思路
  • 了解插件在 CAE 中的典型应用场景:截面应力云图、流场流线可视化、参数化分析中的标量场批量提取

20.2 核心概念说明

20.2.1 插件(Plugin)是什么

在 Gmsh 的架构中,前处理(几何建模 + 网格划分)由 model 命名空间负责,而后处理(Post-Processing)则由 View(视图)Plugin(插件) 两部分协作完成。

View(视图):后处理数据的容器,包含标量场(Scalar Field)、矢量场(Vector Field)或张量场(Tensor Field),可以是基于列表的(list-based,独立于网格)或基于模型的(model-based,绑定到特定网格)。

Plugin(插件):对 View 中的数据进行运算或变换的模块。一个插件读取一个或多个源 View,执行特定算法,输出一个新的 View。例如: - 从三维标量场中提取等值面 - 在指定平面上截取截面云图 - 从矢量场中追踪流线

插件的运行流程可以概括为:

源 View (Source) ──→ [Plugin: setNumber/setString 配置参数] ──→ plugin::run() ──→ 新 View (Result)

20.2.2 常用内置插件速览

Gmsh 静态链接了数十个内置插件,以下是 CAE 后处理中最常用的六个:

插件名 功能 适用场景 输入要求 输出
Isosurface 从3D标量场提取等值面 应力/温度等值面可视化 3D 标量 View 2D 曲面 View
CutPlane 用平面截取3D视图 任意角度截面云图 3D View(标量/矢量) 2D 截面 View
CutMap 将3D标量场在截平面上的值展平为2D彩色图 截面应力分布精确判读 3D 标量 View 2D 彩色图 View
Skin 提取3D视图的外表面 仅关心表面场分布时 3D View 2D 表面 View
StreamLines 从矢量场追踪流线/迹线 流场、磁场、热通量方向 3D 矢量 View 1D 线 View
Probe 在指定坐标点采样场值 参数化分析、监控点提取 任意 View 终端输出 + 可选 View

此外还有 ModifyComponents(修改/交换矢量或张量分量)、Annotate(添加文字标注)、Smooth(场值平滑)、Transform(视图几何变换)等辅助插件。

20.2.3 插件参数系统

所有插件都通过统一的参数接口进行配置:

gmsh::plugin::setNumber("PluginName", "ParameterName", value);  // 数值参数
gmsh::plugin::setString("PluginName", "ParameterName", "value"); // 字符串参数
int newViewTag = gmsh::plugin::run("PluginName");               // 执行并返回新View标签

关键点: - 参数名是大小写敏感的("Value" 不等于 "value") - setNumbersetString 设置的是全局状态run() 执行前所有参数必须设置完毕 - run() 返回新生成的 View 标签(整数),可用于后续的 view::option::setNumber() 调整显示属性 - 如果想覆盖已有 View 而非生成新 View,可设置参数 "View" 为负数(表示不生成新视图)

20.2.4 CAE 中的应用场景

  1. 截面应力云图:有限元求解得到3D应力场后,用 CutPlane/CutMap 截取关键截面(如螺栓孔剖面)的应力分布,用于强度校核报告
  2. 流场流线可视化:CFD 求解得到速度场后,用 StreamLines 追踪流体质点轨迹,辅助判断涡流、回流区域
  3. 等值面包络分析:用 Isosurface 提取温度场中某一温度值的包络面,判断热影响区范围
  4. 参数化分析:批量改变求解参数后,用 Probe 在固定监控点自动采样场值,绘制参数-响应曲线

20.3 C++ 代码逐段讲解

20.3.1 头文件与初始化

#include <set>
#include <cmath>
#include <vector>
#include <gmsh.h>

int main(int argc, char **argv)
{
  gmsh::initialize(argc, argv);
  gmsh::model::add("ch20_plugins");

解释<set> 用于命令行参数判断(是否启动 GUI),<cmath> 提供 M_PI 等常量,<vector> 用于容纳节点和单元数据。gmsh::model::add() 为当前模型命名。


20.3.2 加载预置三维标量视图

  // ---- 1. 加载 Gmsh 教程自带的 3D 标量场视图 ----
  try {
    gmsh::merge("../view3.pos");
  } catch(...) {
    gmsh::logger::write("Could not load post-processing views: bye!");
    gmsh::finalize();
    return 0;
  }

  std::vector<int> v;
  gmsh::view::getTags(v);
  if(v.size() != 1) {
    gmsh::logger::write("Wrong number of views!", "error");
    gmsh::finalize();
    return 1;
  }

解释gmsh::merge() 加载后处理数据文件。view3.pos 是 Gmsh 教程提供的三维标量场(一个简单的结构应力模拟数据)。view::getTags() 获取当前模型中的所有 View 标签,此处预期只加载了一个 View。

使用 try-catch 包裹加载操作:.pos 文件可能不存在、格式损坏或路径错误,捕获异常后优雅退出是工程中的良好实践。


20.3.3 创建演示几何体与网格(用于构建矢量视图)

  // ---- 2. 创建演示几何体并生成网格 ----
  // 创建一个立方体作为矢量场的物理域
  gmsh::model::occ::addBox(0, 0, 0, 2, 2, 2, 1);
  gmsh::model::occ::synchronize();
  gmsh::model::mesh::generate(3);

解释:创建一个 2x2x2 的立方体并生成三维四面体网格。这个网格将作为后续基于模型的视图(model-based view)的数据源——我们将从网格节点坐标计算矢量场值,构建一个旋转矢量场 v = (-y, x, 0),用于演示 StreamLines 插件。


20.3.4 从网格数据创建标量视图(Model-Based View)

  // ---- 3. 创建基于模型的标量视图 (Model-Based View) ----
  // 获取所有节点坐标
  std::vector<std::size_t> nodeTags;
  std::vector<double> nodeCoords, nodeParams;
  gmsh::model::mesh::getNodes(nodeTags, nodeCoords, nodeParams, 3);

  // 对每个节点计算标量值: f(x,y,z) = sqrt(x^2 + y^2) —— 到Z轴的距离
  std::vector<double> scalarData;
  for(std::size_t i = 0; i < nodeCoords.size(); i += 3) {
    double d = std::sqrt(nodeCoords[i] * nodeCoords[i] +
                         nodeCoords[i + 1] * nodeCoords[i + 1]);
    scalarData.push_back(d);
  }

  // 创建标量视图并填充 NodeData
  int vScalar = gmsh::view::add("scalar_distance_to_z");
  gmsh::view::addHomogeneousModelData(
      vScalar, 0,                     // viewTag, step
      "ch20_plugins",                 // modelName
      "NodeData",                     // dataType: 节点数据 → 连续场
      nodeTags, scalarData,           // tags + data
      0.0,                            // time
      1);                             // numComponents = 1 (标量)

解释:这里展示了创建基于模型的视图(model-based view)的完整流程。mesh::getNodes() 获取所有三维节点(dim=3)的标签和坐标。对每个节点计算到 Z 轴的距离作为标量值,模拟一个轴对称的温度场或应力幅值场。

view::addHomogeneousModelData() 是该流程的核心 API: - 参数 "NodeData" 表示数据定义在节点上(Gmsh 会用节点形函数进行连续插值) - nodeTags 必须与 scalarData 按顺序一一对应 - numComponents=1 表示标量场;numComponents=3 表示矢量场;numComponents=9 表示张量场


20.3.5 从网格数据创建矢量视图(用于流线演示)

  // ---- 4. 创建基于模型的矢量视图 ----
  // 矢量场 v = (-y, x, 0)  —— 绕 Z 轴的旋转场
  std::vector<double> vectorData;
  for(std::size_t i = 0; i < nodeCoords.size(); i += 3) {
    double x = nodeCoords[i];
    double y = nodeCoords[i + 1];
    vectorData.push_back(-y);    // vx
    vectorData.push_back( x);    // vy
    vectorData.push_back( 0.0);  // vz
  }

  int vVector = gmsh::view::add("vector_rotational");
  gmsh::view::addHomogeneousModelData(
      vVector, 0, "ch20_plugins", "NodeData",
      nodeTags, vectorData,
      0.0,    // time
      3);     // numComponents = 3 (矢量)

解释numComponents=3 将数据标记为矢量场。vectorData 的存储顺序为 vx1, vy1, vz1, vx2, vy2, vz2, ...(分量交错存储)。该旋转矢量场 v = (-y, x, 0) 在 XY 平面形成围绕 Z 轴的逆时针旋转,非常适合演示 StreamLines 插件的流线追踪效果。


20.3.6 Isosurface 等值面提取

  // ---- 5. Isosurface 等值面提取 ----
  // 从 view[0](view3.pos 加载的标量场)中提取 Value=0.67 的等值面
  gmsh::plugin::setNumber("Isosurface", "Value", 0.67);
  gmsh::plugin::setNumber("Isosurface", "View", 0);   // View[0] 为数据源
  int vIso = gmsh::plugin::run("Isosurface");

解释Isosurface 插件在三维标量场中寻找所有等于 Value 的点的集合,并以曲面形式输出。"View" 参数指定源 View 的索引(注意:是索引号而非标签号——View[0] 指 view::getTags() 返回列表中的第一个标签)。

CAE 应用示例:在温度场中提取 T=800 摄氏度的等值面,判断热影响区(HAZ)边界。


20.3.7 CutPlane 截面与 CutMap 截面映射

  // ---- 6. CutPlane 截面 ----
  // 平面方程: A*x + B*y + C*z + D = 0
  // 此处: 0*x + 0.2*y + 1*z + 0 = 0  → z = -0.2*y(倾斜平面)
  gmsh::plugin::setNumber("CutPlane", "A", 0);
  gmsh::plugin::setNumber("CutPlane", "B", 0.2);
  gmsh::plugin::setNumber("CutPlane", "C", 1);
  gmsh::plugin::setNumber("CutPlane", "D", 0);
  gmsh::plugin::setNumber("CutPlane", "View", 0);
  int vCut = gmsh::plugin::run("CutPlane");

  // ---- 7. CutMap 2D 截面映射 ----
  // 将标量场在 XY 平面 (z=0) 上的值展平为彩色二维图
  gmsh::plugin::setNumber("CutMap", "A", 0);
  gmsh::plugin::setNumber("CutMap", "B", 0);
  gmsh::plugin::setNumber("CutMap", "C", 1);
  gmsh::plugin::setNumber("CutMap", "D", -0.5);  // z = 0.5
  gmsh::plugin::setNumber("CutMap", "View", 0);
  int vMap = gmsh::plugin::run("CutMap");

解释

  • CutPlane:用任意位姿的平面 A*x + B*y + C*z + D = 0 截取三维视图。向量 (A, B, C) 为平面法向,D 控制平面沿法向的偏置距离。结果是一个二维截面上的场分布视图。

  • CutMap:与 CutPlane 类似,但将截面上的标量值"平展"为一张彩色的二维矩形图。截面位于 z = -D/C = 0.5。CutMap 比 CutPlane 更直观——它去除了三维透视效应,便于精确判读截面上的数值分布(如截面最大应力值的位置和大小)。

CutPlane vs CutMap 的工程选型: | 特性 | CutPlane | CutMap | |------|----------|--------| | 输出 | 3D 空间中的截面 | 展平的 2D 彩色图 | | 适用场景 | 综合性可视化 | 精确数值判读 | | 多截面叠加 | 可叠加显示 | 独立成图 |


20.3.8 Skin 表面提取

  // ---- 8. Skin 表面提取 ----
  // 从 Isosurface 的结果中提取外表面
  gmsh::plugin::setNumber("Skin", "View", vIso);
  int vSkin = gmsh::plugin::run("Skin");

解释Skin 插件提取三维视图的外表面(outward-facing surface),去除内部结构。当源 View 是封闭等值面时,Skin 结果等于源 View 本身;当源 View 包含内部网格时,Skin 仅保留可见的外部面,可用于生成轻量化的外表面包络。

多插件串联示例原始标量场 → Isosurface → Skin。这种串联是构建后处理流水线的核心模式。


20.3.9 StreamLines 流线追踪

  // ---- 9. StreamLines 流线追踪 ----
  // 从矢量视图中,在多个起点追踪流线
  // 流线起点:在 XY 平面均匀分布 4 个种子点
  for(int i = 0; i < 4; i++) {
    double seedX = 1.0;
    double seedY = 0.5 + i * 0.5;
    double seedZ = 1.0;
    gmsh::plugin::setNumber("StreamLines", "X0", seedX);
    gmsh::plugin::setNumber("StreamLines", "Y0", seedY);
    gmsh::plugin::setNumber("StreamLines", "Z0", seedZ);
    gmsh::plugin::setString("StreamLines", "View", std::to_string(vVector));
    gmsh::plugin::setNumber("StreamLines", "TimeStep", 0.05);
    gmsh::plugin::setNumber("StreamLines", "MaxRecursion", 2000);
    int vSL = gmsh::plugin::run("StreamLines");
  }

解释StreamLines 插件从指定的起始点 (X0, Y0, Z0) 出发,沿矢量场方向(前向和后向)追踪流线。核心参数: - "TimeStep":积分步长,越小精度越高但计算量越大 - "MaxRecursion":最大积分步数,限制流线长度 - "View" 参数接受字符串形式的 View 标签(此处用 std::to_string 转换),而非索引

此处 4 个种子点沿 X=1 线均匀分布,由于矢量场是绕 Z 轴的旋转场,流线将呈现同心圆弧。

CAE 应用:在 CFD 速度场中放置种子点追踪流线,直观显示回流区、涡旋结构;在电磁场中追踪磁力线。


20.3.10 Probe 探针采样

  // ---- 10. Probe 探针采样 ----
  // 在指定坐标采样标量场和矢量场的值
  gmsh::plugin::setNumber("Probe", "X", 1.0);
  gmsh::plugin::setNumber("Probe", "Y", 0.5);
  gmsh::plugin::setNumber("Probe", "Z", 1.0);
  gmsh::plugin::setString("Probe", "View", std::to_string(vVector));
  gmsh::plugin::run("Probe");  // 结果输出到终端控制台

解释Probe 插件在指定空间坐标 (X, Y, Z) 处对源 View 进行采样,将结果(场值及到最近单元的距离)打印到终端控制台。采样使用源 View 的插值方法,因此 "NodeData" 类型的视图在任意点都有插值结果。

CAE 应用:在参数化分析中,在固定监控点(如焊点位置、最大应力预期位置)用 Probe 批量采样,配合脚本绘制参数-响应曲线。


20.3.11 ModifyComponents 分量变换与 Annotate 标注

  // ---- 11. ModifyComponents 修改矢量分量 ----
  // 将矢量场的三个分量交换:(vx, vy, vz) → (vy, vx, vz)
  // 使用表达式映射: 新分量 = f(旧分量)
  gmsh::plugin::setNumber("ModifyComponents", "View", vVector);
  gmsh::plugin::setNumber("ModifyComponents", "NewView", -1);
  gmsh::plugin::setString("ModifyComponents", "Expression0", "v1");
  gmsh::plugin::setString("ModifyComponents", "Expression1", "v0");
  gmsh::plugin::setString("ModifyComponents", "Expression2", "v2");
  int vMod = gmsh::plugin::run("ModifyComponents");

  // ---- 12. Annotate 文本标注 ----
  gmsh::plugin::setString("Annotate", "Text", "Gmsh Plugin Demo");
  gmsh::plugin::setNumber("Annotate", "X", 1.e5);       // >99999 = 窗口居中
  gmsh::plugin::setNumber("Annotate", "Y", 50);
  gmsh::plugin::setString("Annotate", "Font", "Times-BoldItalic");
  gmsh::plugin::setNumber("Annotate", "FontSize", 28);
  gmsh::plugin::setString("Annotate", "Align", "Center");
  gmsh::plugin::setNumber("Annotate", "View", 0);
  gmsh::plugin::run("Annotate");

解释

  • ModifyComponents:通过对原始分量应用数学表达式来生成新的矢量场。v0, v1, v2 是内置变量,代表源场的三个分量。Expression0 = "v1" 表示新场 x 分量取源场 y 分量值,实现了分量交换。NewView = -1 表示不创建新 View(就地覆盖)。支持任意数学表达式,如 "sqrt(v0^2 + v1^2)" 可提取矢量幅值。

  • Annotate:在指定窗口中添加文字标注。坐标 X > 99999 是 Gmsh 的约定——表示窗口水平居中。"Center" 对齐方式使文本以坐标点为中心。"View" 参数指定标注添加到哪个 View 的显示中。


20.3.12 视图可视化选项与 GUI 启动

  // ---- 13. 设置视图可视化选项 ----
  // 对原始标量视图: 开启光照、等值线显示
  gmsh::view::option::setNumber(v[0], "Light", 1);
  gmsh::view::option::setNumber(v[0], "IntervalsType", 1);  // 等值线
  gmsh::view::option::setNumber(v[0], "NbIso", 6);           // 6条等值线
  gmsh::view::option::setNumber(v[0], "SmoothNormals", 1);   // 法向光滑

  // 对等值面和截面视图: 连续色带
  gmsh::view::option::setNumber(vIso, "IntervalsType", 2);   // 连续
  gmsh::view::option::setNumber(vCut, "IntervalsType", 2);

  // 对流线视图: 设置箭头大小
  gmsh::view::option::setNumber(vVector, "ArrowSizeMax", 30);
  gmsh::view::option::setNumber(vVector, "ShowScale", 0);

  // 对 CutMap 视图: 显示标尺
  gmsh::view::option::setNumber(vMap, "ShowScale", 1);

  // ---- 14. 启动 GUI 查看结果 ----
  std::set<std::string> args(argv, argv + argc);
  if(!args.count("-nopopup")) gmsh::fltk::run();

  gmsh::finalize();
  return 0;
}

解释view::option::setNumber(viewTag, optionName, value) 设置单个 View 的显示属性。常用选项:

选项名 含义 典型值
Light 是否开启光照渲染 0=关闭, 1=开启
IntervalsType 色带类型 1=等值线, 2=连续渐变, 3=离散色块
NbIso 等值线条数 正整数
SmoothNormals 法向量光滑(视觉) 0=关闭, 1=开启
ShowScale 是否显示色标尺 0=关闭, 1=开启
ArrowSizeMax 矢量箭头最大尺寸(像素) 正整数
ColormapNumber 色图编号 0-22(共23种内置色图)

通过 -nopopup 命令行参数可以跳过 GUI 直接执行插件(适用于批处理脚本)。


20.4 完整可运行代码

// =============================================================================
//  Chapter 20: Post-Processing Plugins
//
//  功能: 演示 Gmsh 常用后处理插件的使用,包括等值面、切平面、
//        截面映射、表面提取、流线追踪、探针采样、分量变换和文本标注
//
//  编译 (需链接 Gmsh SDK):
//    g++ -o ch20_plugins ch20_plugins.cpp -lgmsh -std=c++11
//
//  运行:
//    ./ch20_plugins              (带 GUI 交互查看)
//    ./ch20_plugins -nopopup     (仅运行插件,不启动 GUI)
//
//  依赖文件:
//    view3.pos   (Gmsh 教程自带的 3D 标量视图数据文件)
// =============================================================================

#include <set>
#include <cmath>
#include <vector>
#include <string>
#include <gmsh.h>

int main(int argc, char **argv)
{
  gmsh::initialize(argc, argv);
  gmsh::model::add("ch20_plugins");

  // ===== 1. 加载预置 3D 标量视图 =====
  try {
    gmsh::merge("../view3.pos");
  } catch(...) {
    gmsh::logger::write("Could not load post-processing views: bye!");
    gmsh::finalize();
    return 0;
  }

  std::vector<int> v;
  gmsh::view::getTags(v);
  if(v.size() != 1) {
    gmsh::logger::write("Wrong number of views!", "error");
    gmsh::finalize();
    return 1;
  }

  // ===== 2. 创建演示几何体与网格(用于构建矢量视图) =====
  gmsh::model::occ::addBox(0, 0, 0, 2, 2, 2, 1);
  gmsh::model::occ::synchronize();
  gmsh::model::mesh::generate(3);

  // ===== 3. 创建基于模型的标量视图 (Model-Based View) =====
  std::vector<std::size_t> nodeTags;
  std::vector<double> nodeCoords, nodeParams;
  gmsh::model::mesh::getNodes(nodeTags, nodeCoords, nodeParams, 3);

  std::vector<double> scalarData;
  for(std::size_t i = 0; i < nodeCoords.size(); i += 3) {
    double d = std::sqrt(nodeCoords[i] * nodeCoords[i] +
                         nodeCoords[i + 1] * nodeCoords[i + 1]);
    scalarData.push_back(d);
  }

  int vScalar = gmsh::view::add("scalar_distance_to_z");
  gmsh::view::addHomogeneousModelData(
      vScalar, 0, "ch20_plugins", "NodeData",
      nodeTags, scalarData, 0.0, 1);

  // ===== 4. 创建基于模型的矢量视图 =====
  std::vector<double> vectorData;
  for(std::size_t i = 0; i < nodeCoords.size(); i += 3) {
    double x = nodeCoords[i], y = nodeCoords[i + 1];
    vectorData.push_back(-y);   // vx
    vectorData.push_back( x);   // vy
    vectorData.push_back( 0.0); // vz
  }

  int vVector = gmsh::view::add("vector_rotational");
  gmsh::view::addHomogeneousModelData(
      vVector, 0, "ch20_plugins", "NodeData",
      nodeTags, vectorData, 0.0, 3);

  // ===== 5. Isosurface 等值面提取 =====
  gmsh::plugin::setNumber("Isosurface", "Value", 0.67);
  gmsh::plugin::setNumber("Isosurface", "View", 0);
  int vIso = gmsh::plugin::run("Isosurface");

  // ===== 6. CutPlane 切平面 =====
  gmsh::plugin::setNumber("CutPlane", "A", 0);
  gmsh::plugin::setNumber("CutPlane", "B", 0.2);
  gmsh::plugin::setNumber("CutPlane", "C", 1);
  gmsh::plugin::setNumber("CutPlane", "D", 0);
  gmsh::plugin::setNumber("CutPlane", "View", 0);
  int vCut = gmsh::plugin::run("CutPlane");

  // ===== 7. CutMap 2D 截面映射 =====
  gmsh::plugin::setNumber("CutMap", "A", 0);
  gmsh::plugin::setNumber("CutMap", "B", 0);
  gmsh::plugin::setNumber("CutMap", "C", 1);
  gmsh::plugin::setNumber("CutMap", "D", -0.5);
  gmsh::plugin::setNumber("CutMap", "View", 0);
  int vMap = gmsh::plugin::run("CutMap");

  // ===== 8. Skin 表面提取 (从等值面结果) =====
  gmsh::plugin::setNumber("Skin", "View", vIso);
  int vSkin = gmsh::plugin::run("Skin");

  // ===== 9. StreamLines 流线追踪 =====
  for(int i = 0; i < 4; i++) {
    gmsh::plugin::setNumber("StreamLines", "X0", 1.0);
    gmsh::plugin::setNumber("StreamLines", "Y0", 0.5 + i * 0.5);
    gmsh::plugin::setNumber("StreamLines", "Z0", 1.0);
    gmsh::plugin::setString("StreamLines", "View", std::to_string(vVector));
    gmsh::plugin::setNumber("StreamLines", "TimeStep", 0.05);
    gmsh::plugin::setNumber("StreamLines", "MaxRecursion", 2000);
    gmsh::plugin::run("StreamLines");
  }

  // ===== 10. Probe 探针采样 =====
  gmsh::plugin::setNumber("Probe", "X", 1.0);
  gmsh::plugin::setNumber("Probe", "Y", 0.5);
  gmsh::plugin::setNumber("Probe", "Z", 1.0);
  gmsh::plugin::setString("Probe", "View", std::to_string(vVector));
  gmsh::plugin::run("Probe");

  // ===== 11. ModifyComponents 分量变换 =====
  gmsh::plugin::setNumber("ModifyComponents", "View", vVector);
  gmsh::plugin::setNumber("ModifyComponents", "NewView", -1);
  gmsh::plugin::setString("ModifyComponents", "Expression0", "v1");
  gmsh::plugin::setString("ModifyComponents", "Expression1", "v0");
  gmsh::plugin::setString("ModifyComponents", "Expression2", "v2");
  int vMod = gmsh::plugin::run("ModifyComponents");

  // ===== 12. Annotate 文本标注 =====
  gmsh::plugin::setString("Annotate", "Text", "Gmsh Plugin Demo");
  gmsh::plugin::setNumber("Annotate", "X", 1.e5);
  gmsh::plugin::setNumber("Annotate", "Y", 50);
  gmsh::plugin::setString("Annotate", "Font", "Times-BoldItalic");
  gmsh::plugin::setNumber("Annotate", "FontSize", 28);
  gmsh::plugin::setString("Annotate", "Align", "Center");
  gmsh::plugin::setNumber("Annotate", "View", 0);
  gmsh::plugin::run("Annotate");

  // ===== 13. 视图可视化选项 =====
  gmsh::view::option::setNumber(v[0], "Light", 1);
  gmsh::view::option::setNumber(v[0], "IntervalsType", 1);
  gmsh::view::option::setNumber(v[0], "NbIso", 6);
  gmsh::view::option::setNumber(v[0], "SmoothNormals", 1);
  gmsh::view::option::setNumber(vIso, "IntervalsType", 2);
  gmsh::view::option::setNumber(vCut, "IntervalsType", 2);
  gmsh::view::option::setNumber(vVector, "ArrowSizeMax", 30);
  gmsh::view::option::setNumber(vVector, "ShowScale", 0);
  gmsh::view::option::setNumber(vMap, "ShowScale", 1);

  // ===== 14. 启动 GUI =====
  std::set<std::string> args(argv, argv + argc);
  if(!args.count("-nopopup")) gmsh::fltk::run();

  gmsh::finalize();
  return 0;
}

20.5 关键 API 速查表

API 函数签名 说明
plugin::setNumber (pluginName, paramName, value) 设置插件的数值型参数(浮点数或整数)
plugin::setString (pluginName, paramName, value) 设置插件的字符串型参数
plugin::run (pluginName)int 执行插件,返回新生成的 View 标签(整数)
view::add (viewName)int 创建一个新 View,返回其标签
view::getTags (tags) 获取当前模型中的所有 View 标签列表
view::addHomogeneousModelData (viewTag, step, modelName, dataType, tags, data, time, numComp) 添加基于模型的数据(均匀类型——所有元素节点数相同)
view::addModelData (viewTag, step, modelName, dataType, tags, data, time, numComp, partition) 添加基于模型的数据(支持混合网格——元素节点数可变化)
view::addListData (viewTag, dataType, numElems, data) 添加基于列表的数据(独立于网格,如 "ST"=标量三角形)
view::option::setNumber (viewTag, optionName, value) 设置单个 View 的可视化选项(如 Light, IntervalsType, NbIso)
view::option::setString (viewTag, optionName, value) 设置单个 View 的字符串选项
view::probe (viewTag, x, y, z, values, distance) 在指定空间点探测 View 的场值(API 方式,不依赖插件)
view::write (viewTag, filename) 将 View 保存到 .pos.msh 文件
model::mesh::getNodes (nodeTags, coord, param, dim, tag, includeBoundary) 获取网格节点标签和坐标(dim=-1 获取所有维度的节点)
gmsh::merge (filename) 合并/加载外部文件(几何、网格或后处理视图)

20.6 内置插件参数速查

Isosurface(等值面)

参数 类型 说明
Value number 等值面的标量值
View number 源 View 的索引号(非标签号),View[-1] 为当前 View
ExtractVolume number 是否提取体积(0=否, >0=是)

CutPlane / CutMap(截面)

参数 类型 说明
A, B, C, D number 平面方程系数: A*x + B*y + C*z + D = 0。(A,B,C) 为法向量
View number 源 View 索引
RecurLevel number 递归次数(用于自适应细分)

StreamLines(流线)

参数 类型 说明
View string 源 View 标签的字符串形式(如 "0"
X0, Y0, Z0 number 流线起始点坐标
TimeStep number 积分步长
MaxRecursion number 最大积分步数
Direction string 追踪方向:"Forward", "Backward", "Both"

Skin(表面提取)

参数 类型 说明
View number 源 View 标签/索引
VisibleOnly number 是否仅提取可见面(0=全部表面, 1=仅可见)

Probe(探针)

参数 类型 说明
X, Y, Z number 采样点坐标
View string 源 View 标签的字符串形式
Interpolation number 插值方法(0=默认)

ModifyComponents(分量修改)

参数 类型 说明
View number 源 View 标签
Expression0 ~ Expression9 string 各分量的数学表达式。内置变量 v0~v8 代表源场分量
NewView number -1=覆盖源View, 0=创建新View

Annotate(文本标注)

参数 类型 说明
Text string 文本内容
X, Y (2D), X, Y, Z (3D) number 坐标位置(X>99999=窗口居中)
Font string 字体名(如 "Times-BoldItalic", "Helvetica")
FontSize number 字号
Align string 对齐方式:"Left", "Center", "Right"
View number 目标 View 索引

20.7 本章小结

  • View(视图) 是 Gmsh 后处理数据的容器,支持标量/矢量/张量场,分为 list-based(独立于网格)和 model-based(绑定到网格)两种。
  • Plugin(插件) 对 View 进行运算或变换,通过 setNumber()/setString() 配置参数,run() 执行并生成新 View。
  • 六大常用插件:Isosurface(等值面)、CutPlane(3D 截面)、CutMap(2D 截面图)、Skin(提取表面)、StreamLines(流线追踪)、Probe(探针采样)。
  • 插件可以串联使用(如 标量场 → Isosurface → Skin),构建自动化后处理流水线。
  • view::addHomogeneousModelData()view::addListData() 分别是创建 model-based 和 list-based 视图的两种方式;前者绑定到网格,后者独立存在。
  • view::option::setNumber() 控制单个 View 的显示属性(光照、色带类型、等值线条数等),是生成出版级后处理图的关键。

20.8 注意事项

  1. View 索引 vs 标签IsosurfaceCutPlaneAnnotate 等插件的 "View" 参数使用索引号(从 0 开始),而 StreamLinesProbe"View" 参数使用标签号的字符串形式。这是 Gmsh 插件接口的历史遗留不一致,使用时务必查阅对应插件的文档。

  2. 插件参数残留plugin::setNumber()plugin::setString() 设置的是全局状态。同一个插件的参数在前一次 run() 后仍保留。如果第二次调用同一插件但不重新设置全部参数,前次的参数值可能仍生效。建议每次 run() 前显式设置所有关键参数。

  3. IntervalsType 含义:1=等值线(iso-lines, 连续曲线),2=连续色带(continuous, 渐变色填充),3=离散色块(discrete, 按区间分段着色)。选择不当可能导致视图在 GUI 中完全不可见。

  4. StreamLines 的 View 参数:该插件的 "View" 参数类型为 string(字符串),而非 number。如果用 setNumber() 设置将不会生效。必须使用 setString() 并传入标签的字符串形式。

  5. Probe 的输出Probe 插件将结果打印到 Gmsh 日志/终端,如果需要编程方式获取采样值,应使用 view::probe() API 而非 Probe 插件。详见 x3.cpp 中的 gmsh::view::probe() 用法。

  6. model-based view 对网格变化的响应:model-based view 依赖网格拓扑。如果后续对几何做 fragmentremoveEntities 等改变网格的操作,之前创建的 model-based view 数据可能失效(节点/单元标签不再对应)。应在网格最终确定后再创建 model-based views。

  7. 插件结果的 View 标签管理plugin::run() 每次调用都生成新 View(标签递增)。在批量运行时如不管理,会累积大量 View。可通过设置 "View" 为负数使插件覆盖指定 View,或定期调用 view::remove() 清理不需要的 View。