ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

occt的boolean工具

occt的boolean工具 1. 前言occt中最常用的布尔工具是BRepAlgoAPI_Fuse、BRepAlgoAPI_Cut和BRepAlgoAPI_Common即所谓的并集、差集、交集它们都属于标准的正则化布尔操作。所有的布尔操作都属于General Fuse Algorithm体系也就是BRepAlgoAPI_BuilderAlgo表示通用构建器子类BRepAlgoAPI_BooleanOperation代表标准布尔由它派生的即是上述三个工具以及BRepAlgoAPI_Section交线提取器其它的子类还有BRepAlgoAPI_Splitter表示通用分割器。在GFA体系中cell是一个绕不开的概念所有输入形状经过求交分割后产生的每一个最小不可再分的拓扑单元就是一个 Cell3D Cell 最小实体块Solid2D Cell 最小面片Face1D Cell 最小线段Edge0D Cell 顶点VertexBRepAlgoAPI_Splitter就是Cell的生产工具BRepAlgoAPI_BuilderAlgo及其子类就是融合Cell的工具。2. 底层BOPAlgo算法工具GFA 的真正引擎所有 API 类最终都委托到这里执行。本文内容暂时不直接涉及这些底层对象。工具类职责关键特性BOPAlgo_PaveFiller求交计算器计算所有输入形状之间的交点、交线、交面构建 Pave 数据结构是整个 GFA 最耗时的步骤BOPAlgo_Builder通用构建器基于 PaveFiller 结果按规则分类 Cells 并合并支持正则化与非正则化模式BOPAlgo_BOP标准布尔操作算法Builder 的特化版内置 Fuse/Cut/Common 的固定选择逻辑BOPAlgo_CellsBuilder自定义重组引擎跳过自动选择允许用户按包含/排除规则任意选取 Cells 并组装BOPAlgo_Section纯截面算法仅提取低维交集边/点不执行构建流程BOPAlgo_RemoveFaces小面清理器消除布尔运算产生的退化小面/窄条面BOPAlgo_MakerVolume实体生成器从一组面/壳自动缝合成封闭实体常用于修复导入模型BOPAlgo_ArgumentAnalyzer输入预检器在运算前检查输入的合法性自交、间隙、退化等可自动修复部分问题3. 布尔基础概念TODO4. occt的标准布尔的高级工具occt中标准布尔可以分为BRepAlgoAPI_Fuse、BRepAlgoAPI_Cut、BRepAlgoAPI_Common和BRepAlgoAPI_Section四种前三个主要针对的都是同维度的流形体。它们都是BRepAlgoAPI_BuilderAlgo的子类所以它们也具备设置BuilderAlgo所支持的一些参数。本小结主要关注它们自身的能力和使用要点。4.1 BRepAlgoAPI_Fuse工具布尔并集支持“多-多”组合SetArguments和SetTools要求模型是同维度的流形体voidSafeFuse(constTopoDS_ShapeshapeA,constTopoDS_ShapeshapeB,TopoDS_ShapeoutResult){BRepAlgoAPI_Fuse fuseOp;// ✅ 使用 SetArguments/SetTools 而非构造函数传参TopTools_ListOfShape args,tools;args.Append(shapeA);tools.Append(shapeB);fuseOp.SetArguments(args);fuseOp.SetTools(tools);// ✅ 关键参数配置fuseOp.SetRunParallel(Standard_True);// 多线程加速fuseOp.SetFuzzyValue(1.0e-4);// 模糊容差修复微小间隙fuseOp.SetGlue(BOPAlgo_GlueShift);// 装配体贴合面优化fuseOp.SetToFillHistory(Standard_True);// 启用历史追溯// 执行运算fuseOp.Build();// ✅ 结构化错误检查替代旧版 ErrorStatus 枚举if(!fuseOp.IsDone()||fuseOp.HasErrors()){constHandle(BOPAlgo_Report)reportfuseOp.GetReport();std::cerrFuse failed with report-GetAlerts(Message_Error).Extent() errors:std::endl;report-Dump(std::cerr);return;}// 警告信息非致命但值得关注if(fuseOp.HasWarnings()){constHandle(BOPAlgo_Report)reportfuseOp.GetReport();std::coutFuse completed with warnings:std::endl;report-Dump(std::cout);}outResultfuseOp.Shape();}4.2 BRepAlgoAPI_Cut工具布尔差集支持“多-多”组合SetArguments和SetTools要求模型是同纬度的流形体4.3 BRepAlgoAPI_Common工具布尔交集支持“多-多”组合SetArguments和SetTools要求模型是同纬度的流形体4.4 BRepAlgoAPI_Section工具仅提取两个输入对象相交的部分其结果是一个由交线TopoDS_Edge和交点TopoDS_Vertex组成的复合体TopoDS_Compound。除了两个Shape之间的操作它还支持两个Geom_Surface之间的求交BRepAlgoAPI_Section(constocc::handleGeom_SurfaceSf1,constocc::handleGeom_SurfaceSf2,constboolPerformNowtrue)Section的另一个核心在于可以计算交线在两个曲面上的PCurve有一些局部边界工具需要依赖此例如SplitShape。这里的PCurve被附加在了交线TopoDS_Edge上可以通过BRep_Tool::CurveOnSurface来获取。voidComputePCurveOn1(constboolB)voidComputePCurveOn2(constboolB)staticocc::handleGeom2d_CurveCurveOnSurface(constTopoDS_EdgeE,constTopoDS_FaceF,doubleFirst,doubleLast,bool*theIsStorednullptr)还有就是Section支持追溯父级当从 Section 的结果中拿到一条交线Edge时可以使用HasAncestorFaceOn1或HasAncestorFaceOn2方法来反向查询这条交线是由第一个输入形状的哪个面Face和第二个输入形状的哪个面相交生成的。boolHasAncestorFaceOn1(constTopoDS_ShapeE,TopoDS_ShapeF)constboolHasAncestorFaceOn2(constTopoDS_ShapeE,TopoDS_ShapeF)const4.5 BRepAlgoAPI_BooleanOperationBRepAlgoAPI_BooleanOperation是上述BRepAlgoAPI_Fuse、BRepAlgoAPI_Cut、BRepAlgoAPI_Common和BRepAlgoAPI_Section的共同基类支持通过枚举参数替代上述中的任一个。voidSetOperation(constBOPAlgo_Operation theBOP)enumBOPAlgo_Operation{BOPAlgo_COMMON,BOPAlgo_FUSE,BOPAlgo_CUT,BOPAlgo_CUT21,BOPAlgo_SECTION,BOPAlgo_UNKNOWN}5. occt的布尔扩展工具布尔扩展主要指的就是能实现General Fuse效果的工具类似于Cell布尔、非流行布尔的概念。在occt中“General Fuse”在底层工具中有一个统一的概念BOPAlgo而到了上层工具中主要有BRepAlgoAPI_BuilderAlgo、BRepAlgoAPI_Splitter两个。5.1 BRepAlgoAPI_BuilderAlgo工具BRepAlgoAPI_BuilderAlgo是底层BOPAlgo_Builder的 BRep 层简易封装是通用相交、分割构建器。它用相交拓扑切割所有原始形体仅输出全部被分割后的碎片拓扑不会主动进行合并。输出的Shape往往是Compound也就是碎片集合其中碎片的类型可以是solid、face等任意。其中碎片之间的关系是通过共用TShape体现的例如两个贴面的box做BuilderAlgo所得结果是一个包含两个solid的Compound对象但是它下面只有11个去重面因为有两个face是相同的、仅Orientation方向不同。BRepAlgoAPI_BuilderAlgo()voidSetArguments(constNCollection_ListTopoDS_ShapetheLS)voidBuild(constMessage_ProgressRangetheRangeMessage_ProgressRange())overrideconstTopoDS_ShapeShape()overrideBRepAlgoAPI_BuilderAlgo支持一些参数控制。voidSetNonDestructive(constbooltheFlag);voidSetGlue(constBOPAlgo_GlueEnum theGlue);voidSetCheckInverted(constbooltheCheck);voidSimplifyResult(constbooltheUnifyEdgestrue,constbooltheUnifyFacestrue,constdoubletheAngularTolPrecision::Angular());voidSetToFillHistory(constbooltheHistFlag);NonDestructive这是一个关于输入形状保护的开关。默认行为False算法为了构建结果可能会“复用”输入形状内部的拓扑结构并且可能会改变其数据。注意只是入参是否还可以继续使用不代表是否存在“子拓扑原位复用”。Glue粘合/缝合模式用于处理相切但无体积干涉的情况。注意前提是用户已知无体积干涉的情况相当于跳过了求交环节直接构建碎片。CheckInverted检查是否存在面的方向发生了内翻的情况。Simplify自动对结果简化主要是消除缝合线接口内部会一并处理History的也可用自行使用ShapeUpgrade_UnifySameDomain来简化模型。FillHistory默认是会记录History的除非主动关闭了BRepAlgoAPI_BuilderAlgo是所有API级别布尔工具的基类所以这些控制参数也同样适用于它们。下面以几个典型场景介绍一下Builder的碎片情况。5.1.1 两体相交两个存在相交干涉的box的BRepAlgoAPI_BuilderAlgo碎片3个solid去重后18个Face。5.1.2 体面相交一个face在一个Box的内部它们的BRepAlgoAPI_BuilderAlgo碎片有两个box多了一个空内腔shellface还是原来的face。也就相当于face将自己压印在box的内部。一个face插入一个Box它俩的BRepAlgoAPI_BuilderAlgo碎片有三个一个box和两个face。也就是原来的face被分割成了两个box也是多个一个内腔shell且内腔shell与外壳shell还共享一个Edge并且box外壳交界的那个face会有一个内环wire。5.2 BRepAlgoAPI_Splitter工具BRepAlgoAPI_Splitter是BRepAlgoAPI_BuilderAlgo的子类它是专门用Tool来分割指定目标对象的它只关心目标对象被分割后的碎片。相当于从BRepAlgoAPI_BuilderAlgo的碎片集合中挑选出来源于指定对象的。BRepAlgoAPI_Splitter()voidSetArguments(constNCollection_ListTopoDS_ShapetheLS)voidSetTools(constNCollection_ListTopoDS_ShapetheLS)两个存在相交干涉的box的BRepAlgoAPI_BuilderAlgo碎片2个solid去重后12个Face6. BOPAlgo算法工具BOPAlgo_Builder是通用相交切割器BOPAlgo_BOP是标准布尔的算子基类Fuse/Cut/Common/Section父类BOPAlgo_CellsBuilder是单元提取器。整体使用逻辑就是先分割成碎片单元然后再自定义提取。6.1 BOPAlgo_CellsBuilderBOPAlgo_CellsBuilder是BOPAlgo_Builder的子类在Builder分割出所有Cell碎片的基础上增加了提取特定Cell的能力。BOPAlgo_Builder的能力完全可以参考BRepAlgoAPI_BuilderAlgo下面就仅补充一下CellBuilder的提取能力。CellBuilder支持材料概念。constTopoDS_ShapeGetAllParts()const//相当于直接获取BRepAlgoAPI_BuilderAlgo的结果voidAddAllToResult(constinttheMaterial0,constbooltheUpdatefalse)//将所有cell加入结果集//如果theMaterial非0则将所有cell都定义成指定的材料“0”表示无材料属性。//如果theUpdate为true则主动调用RemoveInternalBoundaries消除相邻同材料cell的内部边界voidRemoveAllFromResult()//清空结果集voidAddToResult(constNCollection_ListTopoDS_ShapetheLSToTake,constNCollection_ListTopoDS_ShapetheLSToAvoid,constinttheMaterial0,constbooltheUpdatefalse)//取Take中的公共的、且不是来自于Void中的任一个的cell加入结果集//To be taken into result the part must be IN for all shapes from the list theLSToTake and must be OUT of all shapes from the list theLSToAvoidvoidRemoveFromResult(constNCollection_ListTopoDS_ShapetheLSToTake,constNCollection_ListTopoDS_ShapetheLSToAvoid)voidRemoveInternalBoundaries()//融合相邻的相同材料的单元voidMakeContainers()//构建容器对已经选入结果的分片单元按维度自动封装成符合 OCCT 拓扑层级的强类型容器除了碎片单元VERTEX、EDGE、FACE或SOLID还有一个“容器”的概念类型有WireWIRES for EDGEShellSHELLS for FACESCompSolidCOMPSOLIDS for SOLIDS其实就是对碎片进行归类。默认情况结果Shape是一个Compound下一级就是碎片结构形如Compound { Solid1, Solid2, Face1, Face2, Edge1 … }。如果构建了容器MakeContainers那么Compound下一级是容器容器再一级才是碎片结构形如Compound { CompSolid1, CompSolid2, Shell1, Shell2, Wire1… }。注意只能满足共享face的Solid才能进入同一个CompSolid否则就每个独立装入一个CompSolidFace和Edge也是类似的道理。CellBuilder也具备融合能力主要体现在RemoveInternalBoundaries接口。6.1.1 AddAllToResult 分析源码如下。其中重点关注theMaterial的取值影响。若theMaterial取值为0则表示不为cell定义材料并不是材料取为0。这对RemoveInternalBoundaries影响很大结合RemoveInternalBoundaries的源码可以看出它仅处理定义了材料属性的cell。voidBOPAlgo_CellsBuilder::AddAllToResult(constStandard_Integer theMaterial,constStandard_Boolean theUpdate){myShapeMaterial.Clear();myMaterials.Clear();myMapModified.Clear();//myShapemyAllParts;//if(theMaterial!0){TopTools_ListOfShape*pLSMmyMaterials.Bound(theMaterial,TopTools_ListOfShape());//TopoDS_IteratoraIt(myAllParts);for(;aIt.More();aIt.Next()){constTopoDS_ShapeaPartaIt.Value();myShapeMaterial.Bind(aPart,theMaterial);pLSM-Append(aPart);}}//if(!theUpdate){PrepareHistory(Message_ProgressRange());}else{RemoveInternalBoundaries();}}voidBOPAlgo_CellsBuilder::RemoveInternalBoundaries(){if(myMaterials.IsEmpty()){return;}......}6.1.2 RemoveInternalBoundaries 分析关于RemoveInternalBoundaries的效果删除【相同 material 标记、同维度两个 Cell 之间互相配对的共享边界】不同 material、不同维度、外边界完全不动。目前观察到的现象是需要区分Sheet和Solid两种。Sheet并集时可以去除Face间的内部Edge效果如下图所示。提醒一些针对此场景SimplifyResult是无效的虽然是共面的平面但可能Face底层并未共享同一个Surface对象。Solid并集时只能消除Solid之间的共享Face却无法去除共面Face间的公共Edge。这也很好理解RemoveInternalBoundaries处理的对象是cell而针对Solid Cell关注的是共享Face不关注共享Edge的问题。可以考虑使用UnifySameDomain来清理内部Edge。标准的Fuse工具默认不会消除Face间的碎片边界却默认自动消除solid碎片间的边界效果如下图所示。
返回列表