occt的boolean工具
2026/9/7 19:17:26 网站建设 项目流程

1. 前言

occt中,最常用的布尔工具是BRepAlgoAPI_Fuse、BRepAlgoAPI_Cut和BRepAlgoAPI_Common,即所谓的并集、差集、交集,它们都属于标准的正则化布尔操作。
所有的布尔操作,都属于General Fuse Algorithm体系,也就是BRepAlgoAPI_BuilderAlgo,表示通用构建器:子类BRepAlgoAPI_BooleanOperation代表标准布尔,由它派生的即是上述三个工具以及BRepAlgoAPI_Section(交线提取器);其它的子类还有BRepAlgoAPI_Splitter,表示通用分割器。

在GFA体系中,cell是一个绕不开的概念:所有输入形状经过求交分割后,产生的每一个最小不可再分的拓扑单元就是一个 Cell:

  • 3D Cell = 最小实体块(Solid)
  • 2D Cell = 最小面片(Face)
  • 1D Cell = 最小线段(Edge)
  • 0D Cell = 顶点(Vertex)

BRepAlgoAPI_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. 布尔基础概念

TODO

4. occt的标准布尔的高级工具

occt中标准布尔,可以分为BRepAlgoAPI_FuseBRepAlgoAPI_CutBRepAlgoAPI_CommonBRepAlgoAPI_Section四种,前三个主要针对的都是同维度的流形体。它们都是BRepAlgoAPI_BuilderAlgo的子类,所以它们也具备设置BuilderAlgo所支持的一些参数。本小结主要关注它们自身的能力和使用要点。

4.1 BRepAlgoAPI_Fuse工具

布尔并集;支持“多-多”组合:SetArgumentsSetTools;要求模型是同维度的流形体;

voidSafeFuse(constTopoDS_Shape&shapeA,constTopoDS_Shape&shapeB,TopoDS_Shape&outResult){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)&report=fuseOp.GetReport();std::cerr<<"Fuse failed with "<<report->GetAlerts(Message_Error).Extent()<<" errors:"<<std::endl;report->Dump(std::cerr);return;}// 警告信息(非致命,但值得关注)if(fuseOp.HasWarnings()){constHandle(BOPAlgo_Report)&report=fuseOp.GetReport();std::cout<<"Fuse completed with warnings:"<<std::endl;report->Dump(std::cout);}outResult=fuseOp.Shape();}

4.2 BRepAlgoAPI_Cut工具

布尔差集;支持“多-多”组合:SetArgumentsSetTools;要求模型是同纬度的流形体;

4.3 BRepAlgoAPI_Common工具

布尔交集;支持“多-多”组合:SetArgumentsSetTools;要求模型是同纬度的流形体;

4.4 BRepAlgoAPI_Section工具

仅提取两个输入对象相交的部分,其结果是一个由交线(TopoDS_Edge)和交点(TopoDS_Vertex)组成的复合体(TopoDS_Compound)。
除了两个Shape之间的操作,它还支持两个Geom_Surface之间的求交:

BRepAlgoAPI_Section(constocc::handle<Geom_Surface>&Sf1,constocc::handle<Geom_Surface>&Sf2,constboolPerformNow=true)

Section的另一个核心在于,可以计算交线在两个曲面上的PCurve,有一些局部边界工具需要依赖此,例如SplitShape。这里的PCurve被附加在了交线(TopoDS_Edge)上,可以通过BRep_Tool::CurveOnSurface来获取。

voidComputePCurveOn1(constboolB)voidComputePCurveOn2(constboolB)staticocc::handle<Geom2d_Curve>CurveOnSurface(constTopoDS_Edge&E,constTopoDS_Face&F,double&First,double&Last,bool*theIsStored=nullptr)

还有就是,Section支持追溯父级,当从 Section 的结果中拿到一条交线(Edge)时,可以使用HasAncestorFaceOn1HasAncestorFaceOn2方法来反向查询:这条交线是由第一个输入形状的哪个面(Face)和第二个输入形状的哪个面相交生成的。

boolHasAncestorFaceOn1(constTopoDS_Shape&E,TopoDS_Shape&F)constboolHasAncestorFaceOn2(constTopoDS_Shape&E,TopoDS_Shape&F)const

4.5 BRepAlgoAPI_BooleanOperation

BRepAlgoAPI_BooleanOperation是上述BRepAlgoAPI_FuseBRepAlgoAPI_CutBRepAlgoAPI_CommonBRepAlgoAPI_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_BuilderAlgoBRepAlgoAPI_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_List<TopoDS_Shape>&theLS)voidBuild(constMessage_ProgressRange&theRange=Message_ProgressRange())overrideconstTopoDS_Shape&Shape()override

BRepAlgoAPI_BuilderAlgo支持一些参数控制。

voidSetNonDestructive(constbooltheFlag);voidSetGlue(constBOPAlgo_GlueEnum theGlue);voidSetCheckInverted(constbooltheCheck);voidSimplifyResult(constbooltheUnifyEdges=true,constbooltheUnifyFaces=true,constdoubletheAngularTol=Precision::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多了一个空内腔shell,face还是原来的face。也就相当于,face将自己压印在box的内部。
一个face插入一个Box,它俩的BRepAlgoAPI_BuilderAlgo碎片有三个:一个box和两个face。也就是原来的face被分割成了两个,box也是多个一个内腔shell,且内腔shell与外壳shell还共享一个Edge,并且box外壳交界的那个face,会有一个内环wire。

5.2 BRepAlgoAPI_Splitter工具

BRepAlgoAPI_SplitterBRepAlgoAPI_BuilderAlgo的子类,它是专门用Tool来分割指定目标对象的,它只关心目标对象被分割后的碎片。相当于,从BRepAlgoAPI_BuilderAlgo的碎片集合中,挑选出来源于指定对象的。

BRepAlgoAPI_Splitter()voidSetArguments(constNCollection_List<TopoDS_Shape>&theLS)voidSetTools(constNCollection_List<TopoDS_Shape>&theLS)

两个存在相交干涉的box的BRepAlgoAPI_BuilderAlgo碎片:2个solid,去重后12个Face

6. BOPAlgo算法工具


BOPAlgo_Builder是通用相交切割器,BOPAlgo_BOP是标准布尔的算子基类(Fuse/Cut/Common/Section父类),BOPAlgo_CellsBuilder是单元提取器。整体使用逻辑就是先分割成碎片单元,然后再自定义提取。

6.1 BOPAlgo_CellsBuilder

BOPAlgo_CellsBuilderBOPAlgo_Builder的子类,在Builder分割出所有Cell碎片的基础上,增加了提取特定Cell的能力。BOPAlgo_Builder的能力完全可以参考BRepAlgoAPI_BuilderAlgo,下面就仅补充一下CellBuilder的提取能力。
CellBuilder支持材料概念。

constTopoDS_Shape&GetAllParts()const//相当于直接获取BRepAlgoAPI_BuilderAlgo的结果voidAddAllToResult(constinttheMaterial=0,constbooltheUpdate=false)//将所有cell加入结果集//如果theMaterial非0,则将所有cell都定义成指定的材料;“0”表示无材料属性。//如果theUpdate为true,则主动调用RemoveInternalBoundaries消除相邻同材料cell的内部边界voidRemoveAllFromResult()//清空结果集voidAddToResult(constNCollection_List<TopoDS_Shape>&theLSToTake,constNCollection_List<TopoDS_Shape>&theLSToAvoid,constinttheMaterial=0,constbooltheUpdate=false)//取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 <theLSToAvoid>voidRemoveFromResult(constNCollection_List<TopoDS_Shape>&theLSToTake,constNCollection_List<TopoDS_Shape>&theLSToAvoid)voidRemoveInternalBoundaries()//融合相邻的相同材料的单元voidMakeContainers()//构建容器,对已经选入结果的分片单元,按维度自动封装成符合 OCCT 拓扑层级的强类型容器

除了碎片单元(VERTEXEDGEFACESOLID),还有一个“容器”的概念,类型有Wire:WIRES for EDGE,Shell:SHELLS for FACES,CompSolid:COMPSOLIDS for SOLIDS,其实就是对碎片进行归类。
默认情况,结果Shape是一个Compound,下一级就是碎片,结构形如:Compound { Solid1, Solid2, Face1, Face2, Edge1 … }。
如果构建了容器(MakeContainers),那么Compound下一级是容器,容器再一级才是碎片,结构形如:Compound { CompSolid1, CompSolid2, Shell1, Shell2, Wire1… }。注意,只能满足共享face的Solid才能进入同一个CompSolid,否则就每个独立装入一个CompSolid,Face和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();//myShape=myAllParts;//if(theMaterial!=0){TopTools_ListOfShape*pLSM=myMaterials.Bound(theMaterial,TopTools_ListOfShape());//TopoDS_IteratoraIt(myAllParts);for(;aIt.More();aIt.Next()){constTopoDS_Shape&aPart=aIt.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碎片间的边界,效果如下图所示。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询