在学习 BRepAlgoAPI_Cut、BRepAlgoAPI_Fuse、BRepAlgoAPI_Common 之前,最好先理解一个底层概念:interference。
在 OCCT Boolean 文档里,Boolean 算法可以分成两个主要阶段:
Intersection Part → 计算输入子形状之间的 interference
Building Part → 根据 Fuse / Common / Cut / Section 的规则构造结果
也就是说,Cut、Fuse、Common 的前半部分都要先回答同一个问题:
输入的 Vertex、Edge、Face、Solid 之间,哪些地方发生了几何接触、重合、相交或包含?
这个“接触、重合、相交、包含”的关系,在 OCCT Boolean 文档里就叫 interference。官方文档说明,GFA、BOA、SPA、SA 使用同一套数据结构;Intersection Part 负责计算 arguments 的 sub-shapes 之间的 interferences,而 Building Part 负责根据操作类型构造最终结果。(Open CASCADE)
很多初学者会把这几个概念混在一起:
intersection
interference
section
common
cut
fuse
在 OCCT Boolean 语境里,可以先这样区分:
| 概念 | 含义 |
|---|---|
interference | 输入子形状之间的几何关系或相互作用 |
Section | 把 interferences 中产生的点、边输出出来 |
Common | 根据 interference 和分类结果,保留共同区域 |
Cut | 根据 interference 和分类结果,保留 Arguments 中不属于 Tools 的区域 |
Fuse | 根据 interference 和分类结果,保留所有区域 |
例如一个 Box 被 Cylinder 打孔:
Box 和 Cylinder
↓
先计算 Face/Face、Edge/Face、Edge/Edge 等 interferences
↓
得到交线、交点、被分割的边和面
↓
Cut 根据 “Box - Cylinder” 的规则保留剩余部分
所以:
Interference 是 Boolean 运算的中间几何关系,不是最终的 Cut/Fuse/Common 结果。
OCCT 文档中把 interferences 分成两大类:
BRep interferences
Non-BRep interferences
BRep interference 发生在具有边界表示的子形状之间,也就是:
Vertex
Edge
Face
OCCT 的 BRep 子形状都有自身的几何容差。两个 BRep 子形状是否 interfere,不是简单地看数学上是否严格相交,而是看它们底层几何之间的距离是否小于等于两者容差之和。文档中列出了六类 BRep interference:Vertex/Vertex、Vertex/Edge、Vertex/Face、Edge/Edge、Edge/Face、Face/Face。(Open CASCADE)
可以简化成:
如果 distance(shapeA.geometry, shapeB.geometry)
<= Tol(shapeA) + Tol(shapeB)
那么它们在 OCCT Boolean 里可能被认为发生 interference。
也就是:
这里要特别注意:OCCT 的 Boolean 判断不是纯数学零距离判断,而是带容差的几何判断。
还有一种情况:两个 Shape 没有 Vertex/Edge/Face 层面的边界接触,但一个对象完全在另一个 Solid 内部。
这类情况叫 Non-BRep interference。
文档中列出四类:
Vertex/Solid
Edge/Solid
Face/Solid
Solid/Solid
例如:
一个小 Solid 完全在大 Solid 内部
但它们的边界没有相交
这时候没有 Face/Face 交线,也没有 Edge/Face 交点,但它们在 Boolean 分类上仍然有关系。OCCT 文档把这种“没有 BRep interference,但 S2 完全位于 Z1 内部”的情况定义为 Non-BRep interference。(Open CASCADE)
下面按维度从低到高整理。
两个顶点 Vi 和 Vj 发生 interference 的条件是:
两个顶点对应的 3D 点之间的距离
小于两个顶点容差之和
即:
其结果通常是生成一个新的顶点 Vn。新顶点的位置和容差来自一个能够包住原始两个顶点容差球的包围球。(Open CASCADE)
直观理解:
两个顶点非常接近
→ Boolean 认为它们可以合并或产生一个共同顶点
一个顶点 Vi 和一条边 Ej 发生 interference 的条件是:
顶点的 3D 点到 Edge 底层 3D 曲线的投影距离
小于等于 Vertex 容差 + Edge 容差
即:
结果包括:
1. 顶点 Vi
2. 必要时更新后的顶点容差
3. 顶点投影到 Edge 曲线上的参数 ti
文档中给出的容差更新形式是:
同时会记录投影点在 Edge 3D 曲线上的参数。(Open CASCADE)
这类 interference 非常重要,因为它意味着:
某个顶点落在某条边上
→ 这条边可能需要被这个顶点切开
例如:
Edge: A ----------- B
Vertex: V
如果 V 落在 Edge 上
结果可能变成:
A ----- V ----- B
一个顶点 Vi 和一个面 Fj 发生 interference 的条件类似:
顶点到 Face 底层 Surface 的投影距离
小于等于 Vertex 容差 + Face 容差
即:
结果包括:
1. 顶点 Vi
2. 更新后的顶点容差
3. 投影点在 Face Surface 上的参数 ui, vi
文档中同样给出了类似的容差更新形式,并记录投影点在曲面上的 (u, v) 参数。(Open CASCADE)
直观理解:
某个顶点落在某个面上
→ 后续 Building Part 需要知道这个点在面上的参数位置
两个 Edge 的 interference 有两种情况。
也就是两条 Edge 的 3D 曲线在某一段范围内重合或足够接近。
结果不是一个点,而是两条 Edge 各自曲线上的参数区间:
Edge Ei 上的参数范围 [ti1, ti2]
Edge Ej 上的参数范围 [tj1, tj2]
文档称这种情况为 common parts。(Open CASCADE)
例如:
E1: A ----------- B
E2: C ------ D
共同段:C ------ D
这种情况后面会引出一个重要概念:common block。
如果两条 Edge 只在一个或多个点处相交,结果是新的顶点 Vn,并记录这个交点分别在两条曲线上的参数:
ti: 交点在 Ei 曲线上的参数
tj: 交点在 Ej 曲线上的参数
文档说明,新顶点的位置和容差会根据两条曲线上最近点对应的容差球计算。(Open CASCADE)
直观理解:
两条边交于一点
→ 生成一个新 Vertex
→ 两条边都可能在该 Vertex 处被分割
Edge / Face interference 也分两种情况。
如果 Edge 的某一段与 Face 的 Surface 共同存在于一定容差内,结果是:
Edge 曲线上的参数范围 [ti1, ti2]
也就是这条 Edge 的某一段位于 Face 上。(Open CASCADE)
例如:
一条边贴在一个平面 Face 上
这不是简单的“一个交点”,而是“一段共同部分”。
如果 Edge 穿过 Face,或者只接触 Face 的某个点,结果是一个新顶点,并记录:
交点在 Edge 3D 曲线上的参数 ti
交点在 Face Surface 上的参数 ui, vi
文档说明,Edge/Face 点干涉会生成新顶点,并记录 3D 曲线参数以及面上的 (u, v) 参数。(Open CASCADE)
直观例子:
一条线段穿过一个平面
→ 交点成为新 Vertex
→ Edge 被交点切开
→ Face 上记录这个点的位置
Face / Face 是 Boolean 中最复杂、最重要的一类 interference。
两个 Face 的底层 Surface 如果在某些地方距离小于等于两者容差之和,就会发生 Face/Face interference。结果可能有两类。(Open CASCADE)
例如:
平面 Face 与圆柱 Face 相交
→ 得到一条或多条空间曲线
文档中称结果为 intersection curves,每条相交曲线都有对应的容差。(Open CASCADE)
这就是为什么 Cut(Box, Cylinder) 后会出现圆形孔口边:
Box 的平面 Face
Cylinder 的圆柱 Face
↓
Face/Face interference
↓
圆形 intersection curve
↓
后续成为 section edge / hole boundary
如果两个 Face 只在点上接触,也可能生成一个或多个新顶点。文档中说明,这些点会记录在两个 Face 的曲面参数空间中,即分别有对应的 (u, v) 参数。(Open CASCADE)
Non-BRep interference 用来处理“完全包含”的情况。
如果一个 Vertex 没有和 Solid 的任何子形状产生 BRep interference,但这个 Vertex 完全在 Solid 内部,则存在 Vertex/Solid interference。(Open CASCADE)
例如:
一个点完全在盒子内部
但不在盒子的任何面、边、点上
如果一条 Edge 及其子形状没有和 Solid 的任何子形状发生 BRep interference,但整条 Edge 完全在 Solid 内部,则存在 Edge/Solid interference。(Open CASCADE)
例如:
一条线段完全在盒子内部
没有穿过盒子的表面
如果一个 Face 及其子形状没有和 Solid 的任何子形状发生 BRep interference,但这个 Face 完全位于 Solid 内部,则存在 Face/Solid interference。(Open CASCADE)
如果一个 Solid 及其所有子形状都没有和另一个 Solid 的子形状发生 BRep interference,但整个 Solid 完全在另一个 Solid 内部,则存在 Solid/Solid interference。(Open CASCADE)
这个场景对 Boolean 很重要。例如:
小球完全在大盒子内部
两者表面不相交
对于 Common,结果应该是小球; 对于 Cut(大盒子, 小球),结果应该是被挖掉小球体积后的大盒子; 对于 Fuse,结果仍然要正确处理包含关系。
如果只看 Face/Face 交线,这种情况会“什么交线都没有”,但 Boolean 仍然必须知道包含关系。
OCCT 文档给出了 interference 的计算顺序:
Vertex/Vertex
Vertex/Edge
Edge/Edge
Vertex/Face
Edge/Face
Face/Face
Vertex/Solid
Edge/Solid
Face/Solid
Solid/Solid
这个顺序大体是从低维到高维。文档说明,这样可以避免在低层子形状已经发生干涉时,还重复计算高层 Shape 之间的冗余 interference。(Open CASCADE)
可以理解成:
先处理点
再处理边
再处理面
最后处理体的包含关系
为什么这样做?
因为高维 Shape 的关系往往可以被低维子形状的关系解释。
例如:
两个 Face 是否相交
可能已经通过它们的 Edge / Vertex 干涉得到部分信息
如果低维干涉已经足够说明问题,就可以减少高维计算的复杂度。
OCCT 文档总结了 interference 结果的三个规律:
第二点特别重要。
例如:
Vertex / Edge → 结果最多是 Vertex
Edge / Face → 结果可以是 Vertex 或 Edge 段
Face / Face → 结果可以是 Edge 曲线或 Vertex
也就是说:
Interference 产生的是“交集层级”的东西
而不是直接产生完整 Boolean 结果
这也解释了为什么 Section 的结果通常是 Vertex 和 Edge,而不是 Solid。
理解 interference 之后,还要理解几个配套概念:Pave、PaveBlock、CommonBlock。
在 OCCT 文档中,Vertex/Edge、Edge/Edge、Edge/Face 的 interference 很多时候会得到一个位于 Edge 上的 Vertex。Face/Face interference 很多时候会得到穿过某些 Vertex 的 intersection curves。为了记录一个 Vertex 在曲线上的位置,OCCT 使用 Pave。(Open CASCADE)
可以这样理解:
Pave = Vertex + parameter on curve
也就是:
Pave PV_i = (V_i, t_i)
其中:
V_i = 顶点
t_i = 这个顶点在曲线 C 上的参数
例如一条 Edge 的参数范围是 [0, 10]:
A(t=0) -------- V(t=4) -------- B(t=10)
那么 V 在这条曲线上的 Pave 就可以理解成:
(V, 4)
这使得 OCCT 可以按照参数排序顶点,从而把 Edge 分割成多个区间。
有了一组 Pave 后,就可以按参数排序:
PV1(t=0), PV2(t=4), PV3(t=10)
相邻两个 Pave 之间的曲线段就是 Pave Block。
文档定义中,Pave Block 是曲线对象在相邻 Pave 之间的一部分;有限 Edge 至少有一个由起点和终点 Pave 组成的 Pave Block。(Open CASCADE)
例如:
A(t=0) -------- V(t=4) -------- B(t=10)
会形成两个 Pave Block:
PB1 = A → V
PB2 = V → B
对 Boolean 来说,Pave Block 很重要,因为后续 Building Part 不是只处理完整的原始 Edge,而是处理被 interference 分割后的 Edge 段。
Pave Block 理论上有一个参数范围:
[t1C, t2C]
但端点 Vertex 有容差,曲线本身也有容差。由于顶点容差球的存在,靠近端点的一小段范围可能不能稳定地用于进一步干涉计算。
因此 OCCT 定义了 Shrunk Range:
Pave Block 中真正可以与其他 Shape 发生 interference 的那部分 3D 曲线参数范围。
文档说明,顶点的容差球会把理论参数范围缩小为一个 shrunk range,而 shrunk range 是 Pave Block 中可以参与其他 Shape 干涉的部分。(Open CASCADE)
可以想象成:
理论范围:
|---------------------------|
两端受顶点容差影响:
|xxx---------------------xxx|
Shrunk Range:
|-----------------|
这个概念的意义是提高 Boolean 的稳定性,避免在端点容差区域内重复或不稳定地判断交点。
Edge/Edge 和 Edge/Face interference 有时不会只产生一个点,而是产生一段共同部分。
例如:
两条 Edge 有一段重合
一条 Edge 有一段落在 Face 上
这些共同部分会用 Common Block 表示。
文档中说明,Edge/Edge 和 Edge/Face interferences 会产生 common parts;对于 Edge/Edge,common parts 是来自不同 base edge 的 pave blocks;如果这些 pave blocks 有相同边界顶点并且几何重合,就形成 common block。对于 Edge/Face,common parts 是落在 Face 上的 pave blocks。(Open CASCADE)
可以理解为:
CommonBlock = 几何上重合的一组 PaveBlock
例如:
Edge1: A -------- C -------- B
Edge2: D -------- E
如果 C-B 与 D-E 几何重合
那么:
PB(edge1, C-B)
PB(edge2, D-E)
会被组织成 CommonBlock
Common Block 对处理“重合边”“边贴在面上”“共面区域”等情况非常重要。
现在可以把整个 Boolean 流程串起来:
输入 Arguments / Tools
↓
拆解子形状 Vertex / Edge / Face / Solid
↓
计算 Interferences
↓
产生 Vertex、Intersection Curve、Pave、PaveBlock、CommonBlock
↓
分割原始 Shape
↓
Building Part 根据操作类型选择保留哪些部分
↓
得到 Fuse / Common / Cut / Section 结果
其中 Cut、Fuse、Common 的差异主要不在 Intersection Part,而是在 Building Part。文档中也说明,各类 Boolean 相关算法的主要区别在 Building Part;Intersection Part 是共用的。(Open CASCADE)
所以可以这样记:
Interference 负责“发现关系”
Building Part 负责“决定保留什么”
例如两个相交 Solid:
General Fuse:
保留所有被分割后的部分
Common:
只保留同时属于两个 Shape 的部分
Cut:
只保留属于 Arguments 且不属于 Tools 的部分
Fuse:
保留属于任意一个 Shape 的部分
Section:
输出 interference 产生的点和边
BRepAlgoAPI_Cut 的启发 #理解 interference 后,再看 Cut(Box, Cylinder) 就清楚很多。
你看到的是:
一个圆柱在盒子上打孔
OCCT 内部看到的是:
Box 的 Face 与 Cylinder 的 Face 发生 Face/Face interference
→ 产生 intersection curves
Box 的 Edge 可能与 Cylinder 的 Face 发生 Edge/Face interference
→ 产生新 Vertex 或参数范围
Cylinder 的 Edge 可能与 Box 的 Face 发生 Edge/Face interference
→ 产生新 Vertex 或参数范围
相交点成为 Pave
Pave 把 Edge 分割成 PaveBlock
共同段形成 CommonBlock
最后 Cut 的 Building Part 选择 Box 中不属于 Cylinder 的部分
所以 Boolean 后经常出现这些现象:
Face 数量增加
Edge 数量增加
原来的 Face 被切开
新增孔口边界
某些输入 Face 被 Modified
某些输入 Edge 产生 Generated shapes
某些输入子形状被 Deleted
这些都不是异常,而是 interference 计算和后续分割的自然结果。
Interference 是 OCCT Boolean 算法在构造结果之前,对输入 Shape 的子形状进行的“带容差的几何关系检测”。
它回答的问题不是:
最终结果是什么?
而是:
哪些 Vertex、Edge、Face、Solid 之间发生了接触、相交、重合或包含?
这些关系会生成哪些点、曲线、参数范围和分割段?
最终的 Cut、Fuse、Common、Section,都是在这些 interference 信息之上构建出来的。