文章目录
这篇文章来源于 dev.opencascade.org,使用 腾讯交互翻译 翻译,原文 Open CASCADE Technology - User Guides: Mesh
OCCT 用户指南按 OCCT 模块组织:
- 基础类
- 建模数据
- 建模算法
- 网格
- 形状修复
- 可视化
- VTK 集成服务(VIS)
- IGES 转换器
- STEP 转换器
- 扩展数据交换(XDE)
- Open CASCADE 应用程序框架(OCAF)
- Draw 测试工具
- 检查器
网格呈现 (Mesh presentations)
除了支持 3D 对象的精确几何表示外,Open CASCADE Technology 还提供以网格形式处理对象的细分(tessellated)表示的功能。
Open CASCADE Technology 网格功能提供:
- 存储与形状相关的曲面网格数据的数据结构,以及处理这些数据的一些基本算法
- 从 BRep 对象(形状)构建表面三角形网格的数据结构和算法。
- 通过显示网格以及相关的预处理和后处理数据,扩展 Open CASCADE Technology 的 3D 可视化功能的工具。
Open CASCADE Technology 包括两个网格转换器:
- VRML 转换器将 Open CASCADE 形状转换为 VRML 1.0 文件(虚拟现实建模语言 Virtual Reality Modeling Language)。Open CASCADE 形状可以转换为两种表示:阴影(shaded)或线框(wireframe)。阴影表示将形状表示为由网格算法计算的三角形集,而线框表示将形状表示为曲线集。
- STL 转换器将 Open CASCADE 形状转换为 STL 文件。STL (STtereoLithography) 格式广泛用于快速原型制作。
Open CASCADE SAS 还提供高级网格产品:
此外,我们还可以在曲面和体(volume)网格划分算法、网格优化算法等领域为您提供有效的帮助。如果您需要有关网格算法的合格建议,请不要犹豫,我们的团队在该领域的专业知识将使您受益。
处理数值模拟的项目可以从使用 SALOME 中受益,SALOME 是一个 CAE 的开源框架,具有 CAD 数据接口,通用的有限元前、后处理器和用于集成有限元求解器的 API。
了解更多关于 SALOME 平台的信息,请访问 https://www.salome-platform.org
网格划分算法 (Meshing algorithm)
形状三角剖分算法由 BRepMesh_IncrementalMesh 类的功能提供,该类将形状三角剖分添加到其拓扑数据结构中。这个三角剖分用于在阴影(shaded)模式下可视化形状。
#include <IMeshData_Status.hxx>
#include <IMeshTools_Parameters.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
Standard_Boolean meshing_explicit_parameters()
{
const Standard_Real aRadius = 10.0;
const Standard_Real aHeight = 25.0;
BRepPrimAPI_MakeCylinder aCylinder(aRadius, aHeight);
TopoDS_Shape aShape = aCylinder.Shape();
const Standard_Real aLinearDeflection = 0.01;
const Standard_Real anAngularDeflection = 0.5;
BRepMesh_IncrementalMesh aMesher (aShape, aLinearDeflection, Standard_False, anAngularDeflection, Standard_True);
const Standard_Integer aStatus = aMesher.GetStatusFlags();
return !aStatus;
}
Standard_Boolean meshing_imeshtools_parameters()
{
const Standard_Real aRadius = 10.0;
const Standard_Real aHeight = 25.0;
BRepPrimAPI_MakeCylinder aCylinder(aRadius, aHeight);
TopoDS_Shape aShape = aCylinder.Shape();
IMeshTools_Parameters aMeshParams;
aMeshParams.Deflection = 0.01;
aMeshParams.Angle = 0.5;
aMeshParams.Relative = Standard_False;
aMeshParams.InParallel = Standard_True;
aMeshParams.MinSize = Precision::Confusion();
aMeshParams.InternalVerticesMode = Standard_True;
aMeshParams.ControlSurfaceDeflection = Standard_True;
BRepMesh_IncrementalMesh aMesher (aShape, aMeshParams);
const Standard_Integer aStatus = aMesher.GetStatusFlags();
return !aStatus;
}
默认网格划分算法 BRepMesh_IncrementalMesh 有两个主要选项来定义三角剖分 — 线性(linear)偏转和角度(angular)偏转。
在第一步中,根据指定的参数对面的所有边进行离散化。
在第二步中,将细分(tessellated)面。线性偏转(Linear deflection)限制曲线与其细分之间的距离,而角度偏转(angular deflection)限制折线中后续线段之间的角度。
还有其他选项可用于控制面内部网格划分的行为:DeflectionInterior(偏转内部) 和 AngleInterior(角度内部)。DeflectionInterior(偏转内部)限制三角形与面内部之间的距离。AngleInterior(仅用于 B 样条曲面的细分)限制三角形每个链接的节点中法线(图片中的 N1、N2 和 N3)之间的角度。对于沿面边界边缘的链接有一个例外,在边离散化过程中将对其使用“角度偏转(Angular Deflection)”。
请注意,如果给定的线性偏转值小于形状公差,则算法将跳过此值并将考虑形状公差。
应用程序应提供偏转参数以计算满意的网格。角度偏转相对简单,允许使用默认值(12-20度)。线性偏转具有绝对意义,应用程序应为其模型提供正确的值。赋予较小的值可能会导致网格太大(消耗大量内存,导致计算时间长和渲染速度慢),而较大的值会导致网格难看。
对于在预先已知的尺寸下工作的应用,对所有模型使用绝对线性偏转是合理的。这将根据应用程序中使用的度量和精度提供网格(例如,已知模型将以米为单位存储,对于大多数任务,0.004m 就足够了)。
但是,导入在其他应用程序中创建的模型的应用程序可能不会对所有模型使用相同的偏转。请注意,实际上这是一种异常情况,此应用程序可能只是尺寸变化一个数量级的 CAD 模型的查看器。这个问题可以通过引入具有一定 LOD(细节层次 - level of detail)的相对线性偏转的概念来解决。细节水平是绝对偏转的比例因子,应用于模型尺寸。
网格化覆盖具有三角形网格的形状。除了隐藏线去除之外,还可以使用网格化将形状传递到另一个工具:制造工具、着色算法、有限元算法或碰撞算法。
您可以通过首先浏览形状来获取有关形状的信息。要在以后访问形状中的面的三角剖分,请使用 BRepTool::Triangulation
。若要访问多边形(它是面边的近似值),请使用 BRepTool::PolygonOnTriangulation
。
BRepMesh 架构 (BRepMesh Architecture)
目标
所选架构的主要目标是:
- 消除数据结构、辅助工具和算法之间的紧密联系,创建可扩展的解决方案,易于维护和改进;
- 为了简化调试和可读性,将代码划分为负责特定操作的几个功能单元;
- 引入新的数据结构,使操纵特定实体(边、线、面)的离散模型成为可能,以便在局部执行计算,而不是处理整个模型;
- 实现一个新的三角剖分算法,以替换包含需要移到上层的过于复杂的解决方案的现有功能。此外,提供了根据曲面类型更改算法的可能性(最初是为了加快平面的网格划分)。
一般工作流程
一般来说,组件的工作流程可以分为六个部分:
- 模型数据结构的创建:对传递给算法的源 TopoDS_Shape 进行分析并分解为面和边。在数据模型中创建与每个拓扑实体相对应的反射。请注意,底层算法使用数据模型作为输入,并通过公共接口访问它,该接口允许创建具有特定实体之间的必要依赖关系的自定义数据模型(参见“数据模型接口”段落);
- 离散化边 3D 和 2D曲线:3D曲线以及每个模型边的一组相关的2D曲线被离散化,以创建一个连贯的骨架,用作面(face)网格划分过程的基础。如果源形状的边已经包含符合指定参数的多边形数据,则会从形状中提取该数据并按原样存储在模型中。每条边单独处理,不考虑相邻性;
- 修复(Heal)离散模型:源 TopoDS_Shape 可能包含在设计、交换或修改模型期间引入的问题,例如开线(open wires)或自相交(self-intersections)。此外,一些问题,如自相交(self-intersections),可以由粗略离散的边引入。这一阶段负责分析离散模型,以便发现和修复问题,或在问题无法解决的情况下拒绝进一步处理模型部件;
- 预处理离散模型:定义在面(faces)网格划分之前要执行的特定于已实现方法的操作。默认情况下,此操作会遍历模型面,检查现有三角剖分的一致性,并在不一致的情况下从多边形数据中清除拓扑面和相邻边,或者标记离散模型的面为不需要计算;
- 离散化面:表示基于 2D 离散数据对特定面执行网格生成的核心部分。该操作将数据模型中与面边相关的多边形数据缓存以供进一步处理,并将生成的网格存储到 TopoDS_Face;
- 后处理离散模型:定义在面网格划分后要执行的特定于已实现方法的操作。默认情况下,此操作将在前一阶段获得的多边形数据存储到源模型的 TopoDS_Edge 对象。
公共接口
组件结构包含两个单元:IMeshData(参见数据模型接口)和 IMeshTools,分别定义了数据模型和算法工具的公共接口。类 IMeshTools_Context 表示这些单元之间的连接器。上下文类缓存数据模型以及与上述工作流的六个阶段中的每个阶段对应的工具,并提供安全调用相应工具的方法(类似于 IntTools_Context 的设计,以便保持与 OCCT 核心工具的一致性)。除第一个阶段外,所有阶段都使用数据模型作为输入,并对整个结构执行特定的操作。因此,定义了 API 类 IMeshTools_ModelAlgo,以便统一操作数据模型的工具的接口。每个处理数据模型的工具都应该继承这个接口,以便能够在上下文中缓存它。与其他接口不同的是,模型构建器接口是由另一个类 IMeshTools_ModelBuilder 定义的,这是由于阶段的含义不同。启动整个工作流的入口点由 IMeshTools_MeshBuilder 表示。
IMeshTools_Context 的默认实现在 BRepMesh_Context 类中给出,通过默认算法工具的实例初始化上下文。
工厂接口 IMeshTools_MeshAlgoFactory 提供了更改特定曲面的三角剖分算法的可能性。工厂通过 IMeshTools_MeshAlgo 接口返回三角剖分算法的实例,具体取决于作为参数传递的曲面类型。它应该用于面(face)离散化阶段。
AlgoFactory 的默认实现在 BRepMesh_MeshAlgoFactory 中给出,返回根据传递的曲面类型选择的不同复杂度的算法。反过来,它被用作 BRepMesh_FaceDiscret 算法的初始化器,表示面离散化阶段的启动器。
其余接口描述了辅助工具:
- IMeshTools_CurveTessellator:为负责在 3D 和 2D 曲线上创建离散多边形的算法以及用于从 TopoDS_Edge 提取现有多边形的工具提供通用接口,从而允许在不考虑实现细节的情况下获得曲线上的离散点和相应参数(请参见 BRepMesh_EdgeDiscret 中派生类 BRepMesh_CurveTessellator、BRepMesh_EdgeTessellationExtractor 的使用示例);
- IMeshTools_ShapeExplorer:最后两个接口表示访问者设计模式,旨在将拓扑形状元素(边和面)的迭代与对特定元素执行的操作分开;
- IMeshTools_ShapeVisitor:为目标拓扑形状的边和面上的操作提供通用接口。它可以与 IMeshTools_ShapeExplorer 结合使用。BRepMesh_ShapeVisitor 中提供的默认实现执行数据模型的初始化。这种方法的优点是 IMeshTools_ShapeVisitor 的实现可以根据特定的数据模型进行更改,而形状浏览器(shape explorer)的实现保持不变。
创建模型数据结构
在网格划分过程的第一阶段创建用于保持底层算法所需的离散和临时数据的数据结构。通常,模型表示适合目标任务的源拓扑形状实体之间的依赖关系。
数据模型接口
IMeshData 单元提供通用接口,用于指定在整个工作流的不同阶段使用的数据模型 API。所设计接口的依赖关系和参考如下图所示。具体的接口实现取决于目标应用程序,它允许开发人员实现不同的模型并使用自定义的低级数据结构,例如不同的集合,NCollection 或 STL
。IMeshData_Shape 用作所有数据结构和工具的基类,保持拓扑形状,以避免可能的复制粘贴。
接口的默认实现在 BRepMeshData 单元中给出。默认数据模型的主要目的是提供以并行模式执行边缘离散化的特征。因此,curve、pcurve 和其他类是基于 STL 容器和智能指针的,因为 NCollection 在某些情况下不提供线程安全性(例如 NCollection_Sequence)。此外,它紧密地反映了源形状的拓扑结构,即数据模型中的边的数量等于源模型中的边的数量;每条边包含与其相邻面相关联的一组 pcurves,这允许在单独的线程中为所有 pcurves 或特定边的 3D 曲线创建离散多边形。
优点:在必要的情况下,数据模型(可能带有处理算法)可以很容易地被支持元素之间另一种依赖关系的另一个实现所取代。
不同数据模型的另一个例子是,不需要创建在相邻面之间同步的离散多边形的网格,即在必要的情况下,加速创建仅用于可视化或快速计算的粗略逐面细分(tessellation)(XDEDRAW_Props 中使用的方法)。
采集数据模型
在这个阶段,数据模型由根据源形状的拓扑结构的实体填充。数据模型的默认实现在 BRepMeshData 单元中给出,并将模型表示为两个集合:一个边集合和一个面集合。每个面由一条或多条线组成,其中第一条线始终代表外部线,而其他线则是内部线。反过来,每条线描绘定向边的有序序列。每条边的特征是一条 3D 曲线和零条(在自由边的情况下)或多条与该边相邻的面相关联的 2D 曲线。3D 和 2D 曲线分别表示在参考面的 3D 和 2D 空间中定义的一组点参数对(a set of pairs point-parameter)。曲线(curve)和 pcurve 之间的另一个区别是,后者具有对其定义的面的引用。
模型填充算法由 BRepMesh_ShapeVisitor 类表示,在 BRepMesh_ShapeExplorer 的帮助下,在目标形状的边和面上执行迭代,将模型创建为拓扑形状的反射。注意,该算法在数据模型的公共接口上操作,并在不了解实现细节和底层数据结构的情况下创建一个结构。采集功能的入口点是 BRepMesh_ModelBuilder 类。
离散化 3D 和 2D 曲线边
在这个阶段,只考虑数据模型的边缘。每个边都是单独处理的(可以在多个线程中运行处理)。检查边是否存在多边形数据。如果至少存在一个表示并适合网格化参数,则将恢复该表示并将其用作整组 pcurves 以及指定给边的 3D 曲线的细分的参考数据(请参见 BRepMesh_EdgeTessellationExtractor)。否则,将创建一个新的细分算法并用于生成初始多边形(请参见 BRepMesh_CurveTessellator),并将边标记为过时。此外,模型边缘通过偏转(deflection)以及重新计算相同范围,相同参数和简并(degeneracy)参数进行更新。有关实现细节,请参见 BRepMesh_EdgeDiscret。
IMeshData 单元定义接口 IMeshData_ParametersListArrayAdaptor,用于将任意数据结构适配到 NCollection_Array1 容器 API。该解决方案使用 NCollection_Array1 和 IMeshData_Curve 作为 BRepMesh_EdgeParameterProvider 工具的源,旨在生成考虑相同参数属性的一致参数化。
修复(Heal)离散模型
一般来说,这个阶段表示对整个离散模型执行的一组操作,以解决由于设计、转换或粗略离散化引起的问题而导致的不一致。根据目标三角剖分算法,可以执行不同的操作序列,例如,有不同的方法来处理自相交 – 通过降低目标精度来放大边缘离散化,或者在交点处分割链接。在这个阶段,整个边缘集被整体考虑,并考虑它们的相邻性。BRepMesh_ModelHealer 中给出了模型修复程序的默认实现,它执行以下操作:
- 迭代模型面(faces)并检查其线(wires)的一致性,即线(wires)是否闭合且不包含自交(self-intersections)。数据结构设计为无冲突,因此可以以并行模式运行处理;
- 强制连接参数空间中相邻边的端点,从而闭合可能断开的部分之间的间隙。该操作的目的是创建相对于目标面的参数空间定义的正确离散模型,仅考虑 3D 空间的连通性和公差。这意味着没有进行特定的计算来确定 U 和 V 公差;
- 在形成面形状的边上注册相交点。为了解决自相交问题,有两种可能的解决方案:
- 减少特定边的偏转(deflection)并更新其离散模型。之后,工作流程 “交叉检查 – 放大 (intersection check – amplification)” 重复最多5次。因此,目标边包含更精细的细分,网格划分继续进行,或者面被标记为 IMeshData_SelfIntersectingWire 状态,并拒绝进一步处理;
- 通过交点分割目标边,并将更新后的多边形与曲线以及与每条边关联的其余 pcurves 同步。与放大过程相比,该操作提供了更健壮的解决方案,并保证了结果,但是从同步功能的角度来看,其更难以实现。
预处理离散模型
这个阶段实现了在面的网格划分之前要执行的操作。根据目标的不同,它可以被改变或省略。默认情况下,BRepMesh_ModelPreProcessor 实现了检查拓扑面以确保现有三角剖分一致性的功能,即:与目标偏转参数的一致性;三角形引用的节点索引不超过三角剖分中存储的节点数。如果该面未通过某些检查,则会从三角剖分中清除该面,并从现有多边形中清除其相邻边。这不会影响离散模型,也不需要任何重新计算,因为模型会为整个边的集合保持细分(tessellations),尽管它们的多边形是一致的。
离散化面
面的离散化是网格划分算法的一般部分。在此阶段,在先前步骤中获得和处理的边缘细分(tessellation)数据用于形成目标面的轮廓,并作为输入传递到三角剖分(triangulation)算法。默认实现由 BRepMesh_FaceDiscret 类提供,该类表示三角剖分算法的启动器。它迭代数据模型中可用的面,根据与每个面相关联的表面类型通过 IMeshTools_MeshAlgoFactory 创建三角剖分算法的实例并执行它。每个面都被单独处理,因此可以以并行模式处理面。面离散化的类图如下图所示。
通常,面网格划分算法具有以下结构:
- BRepMesh_BaseMeshAlgo 实现 IMeshTools_MeshAlgo 接口和继承算法的基本功能。这个类的主要目标是初始化 BRepMesh_DataStructureOfDelaun 的实例以及适用于嵌套算法的辅助数据结构,这些算法使用作为输入参数传递的面模型数据。尽管实现了三角剖分算法,这种结构目前被认为是 OCCT 的常见结构。然而,用户可以自由地实现自定义算法和支持数据结构,这些数据结构可通过 IMeshTools_MeshAlgo 接口访问,例如,连接一个不支持 TopoDS_Shape 的第三方网格化工具。为此,这种结构提供了以插件的形式将连接器分发到各种算法的可能性;
- BRepMesh_DelaunayBaseMeshAlgo 和
BRepMesh_SweepLineMeshAlgo
类实现直接在 BRepMesh_DataStructureOfDelaun 实例上操作的核心网格划分功能。这些算法表示网格生成工具,将新的点从数据结构添加到最终的网格; - BRepMesh_NodeInsertionMeshAlgo 类表示一个包装器,用于扩展从 BRepMesh_BaseMeshAlgo 继承的算法,以启用生成曲面节点并将其插入到结构中的功能。在这个级别上,将创建分类工具的实例,并可用于接受-拒绝内部节点。此外,还将执行相对于为相应方向指定的范围缩放点的 UV 坐标所需的计算。只要这两种三角剖分算法都在结构提供的静态数据上工作,就会在初始化阶段添加新节点。曲面节点由称为范围分割器的辅助工具生成,并作为模板参数传递(参见范围分割器(Range splitter));
- 类 BRepMesh_DelaunayNodeInsertionMeshAlgo 和
BRepMesh_SweepLineNodeInsertionMeshAlgo
实现与添加内部节点相关的算法特定功能,补充由 BRepMesh_NodeInsertionMeshAlgo 提供的功能; - BRepMesh_DelaunayDeflectionControlMeshAlgo 扩展了 BRepMesh_DelaunayNodeInsertionMeshAlgo 的功能,通过附加的过程控制生成三角形的偏转。
BRepMesh 为用户提供了一种将默认三角剖分算法切换为自定义算法的方法,该算法可以由用户实现,也可以在全球范围内使用。目前有三个基类可用于集成第三方算法:
- BRepMesh_ConstrainedBaseMeshAlgo 基类,用于提供不需要 BRepMesh 共同处理的具有约束的三角剖分的生成的工具;
- BRepMesh_CustomBaseMeshAlgo 为不支持约束的通用算法提供了入口点,并且仅用于生成基础网格。约束边使用组件本身提供的标准功能在第三方求解器生成的背景网格上进行处理;
- BRepMesh_CustomDelaunayBaseMeshAlgo 包含 BRepMesh 使用第三方算法结果进行检查或优化的工具的初始化部分。
可以通过使用相关接口实现 IMeshTools_MeshAlgoFactory 并将其传递给 BRepMesh_Context::SetFaceDiscret()
来提供网格划分算法。OCCT 带有两种基本的 2D 网格划分算法:BRepMesh_MeshAlgoFactory(默认使用)和 BRepMesh_DelabellaMeshAlgoFactory。
下面的示例演示了如何在 Draw 环境中完成此操作:
psphere s 10
### Default Algo ###
incmesh s 0.0001 -algo default
### Delabella Algo ###
incmesh s 0.0001 -algo delabella
下面的代码片段展示了如何将自定义网格工厂传递给 BRepMesh_IncrementalMesh:
IMeshTools_Parameters aMeshParams;
Handle(IMeshTools_Context) aContext = new BRepMesh_Context();
aContext->SetFaceDiscret (new BRepMesh_FaceDiscret (new BRepMesh_DelabellaMeshAlgoFactory()));
BRepMesh_IncrementalMesh aMesher;
aMesher.SetShape (aShape);
aMesher.ChangeParameters() = aMeshParams;
aMesher.Perform (aContext);
范围分割器 (Range splitter)
范围分割器工具提供了生成在使用离散模型数据计算的范围内定义的内部曲面节点的功能。基本功能由 BRepMesh_DefaultRangeSplitter 提供,在平面的情况下无需修改即可使用。默认分割器不生成任何内部节点。
BRepMesh_ConeRangeSplitter、BRepMesh_CylinderRangeSplitter 和 BRepMesh_SphereRangeSplitter 是默认分割器的专用化,用于为相应类型的分析曲面快速生成内部节点。
BRepMesh_UVParamRangeSplitter 实现基本功能,将面边界的离散化点考虑在内以生成节点。它的后继者 BRepMesh_TorusRangeSplitter 和 BRepMesh_NURBSRangeSplitter 相应地扩展了环形曲面和 NURBS 曲面的基本功能。
后处理离散模型
这个阶段实现了面网格划分后要执行的操作。根据目标的不同,它可以被改变或省略。默认情况下,BRepMesh_ModelPostProcessor 将存储在数据模型中的多边形数据提交给 TopoDS_Edge。