Technical note
CAD 几何聚合为什么不能简单等同于 Boolean Union
从共形网格和多体装配处理中的实际问题出发,讨论 CAD/CAE 几何聚合为什么不能只理解成 Boolean Fuse,以及装配语义、接口关系、互斥体域和虚拓扑如何改变聚合问题本身。
背景:最开始我也把“聚合”理解成 Fuse
多个 CAD 实体需要一起进入后续流程时,最自然的想法就是:
把它们 Boolean Fuse。
如果最后得到一个合法的结果,似乎问题就结束了。
对于一部分简单模型,这确实有效。
特别是目标只是:
把多个重叠实体合成一个几何整体。
但最近开始真正处理多体装配和共形网格以后,我越来越觉得:
聚合并不是一个单纯的 Boolean 问题。
甚至在很多场景里:
把所有东西 Fuse 成一个 Shape
反而会破坏后续真正需要的信息。
这也是最近重新思考整个聚合模块的起点。
先问目标,再选几何操作
“把多个 Shape 合起来”这句话本身太模糊。
至少在 CAE 流程里,可能存在几种完全不同的目标。
第一种是普通装配。
我们希望:
保留零件;
保留层次;
只识别接触和相交关系。
第二种是共形网格。
我们希望:
相邻体之间拥有一致接口;
网格节点可以在界面上匹配;
不能出现重复体域。
第三种是某些外部区域或空气域处理。
这时可能需要:
把内部实体对外部域产生的切割真正物化出来。
第四种是单纯几何合并。
这时才更接近传统 Fuse。
这些目标需要的最终拓扑并不一样。
所以我现在越来越觉得聚合入口首先应该回答:
为什么要聚合。
而不是直接进入:
用哪个 Boolean 算法。
装配体通常不应该被轻易融合
一个大型装配模型中的每个 Solid 往往都有自己的意义。
例如:
材料;
零件编号;
边界条件;
网格参数;
显示属性。
如果为了“聚合”把几百个 Solid 全部 Fuse 成少数几个 Shape,虽然几何上可能更干净,但原始结构也可能被破坏。
更麻烦的是:
Fuse 后的 Face 和原始 Face 之间不再是一一对应。
于是后续还需要做大量 History 迁移。
如果目标只是:
识别哪些零件接触;
哪些零件相交;
哪些接口需要共形;
那么一开始就全局 Fuse 其实太重了。
这种场景更适合先保留装配结构,再建立对象之间的接口关系。
共形网格关注的是 Interface,不是“一个 Solid”
共形网格最核心的问题并不是:
最终 Shape 数量越少越好。
真正需要保证的是:
相邻计算域之间的接口一致。
假设 Solid A 和 Solid B 相交。
如果分别直接剖分:
A 的表面网格
和
B 的表面网格
可能各自都合法。
但双方在交界处并不一定拥有相同分割。
这会导致后续体网格无法建立真正的共享界面。
所以需要处理的是:
A 与 B 之间的 Interface。
它可能要求:
切分 Face;
生成共享 Edge;
重构局部拓扑;
或者建立等价的虚拓扑约束。
这件事和“把 A、B Fuse 成一个 Solid”其实不是同一个问题。
Boolean 成功,不代表仿真拓扑正确
这是最近比较明显的一个认识。
一个 Boolean 结果可能:
算法执行成功;
B-Rep 有效;
但仍然不满足网格需求。
例如:
两个体被错误融合成一个域;
原本应该保留的内部接口消失;
部分交界没有形成一致分割;
存在重叠体域;
某些 Sheet 没有被正确纳入处理。
所以聚合结果的 Validation 不能只使用:
BRepCheck。
还需要检查:
输入域有没有静默丢失;
输出域之间是否仍然重叠;
预期 Interface 是否都存在;
接口是否唯一;
自由面和 Sheet 是否被正确保留;
拓扑变化是否可追踪。
这种验证更接近“仿真拓扑正确性”。
全局 Boolean 最大的问题是复杂度快速增长
多个复杂 Solid 一起进入 Boolean 时,计算量很容易迅速上升。
本质上算法需要处理大量:
候选对象;
候选 Face 对;
求交;
Pave;
Fragment;
后续重建。
即使前面通过包围盒过滤掉大量完全无关对象,真正集中在一个高密度装配区域里的 Candidate 仍然可能很多。
所以最开始的优化思路通常是:
分组;
局部化;
批处理;
Macro-first;
减少重复求交。
这些方法都有效。
但继续往后做,我越来越觉得性能优化不能只发生在 Boolean 内部。
更大的优化机会可能来自:
不要让不需要物化的关系进入 Boolean。
Interface Graph 改变了问题组织方式
如果先建立对象间关系:
Solid A ── Interface ── Solid B
那么后续算法就可以围绕 Interface 工作。
例如先判断:
Shared;
Touch;
Intersecting;
Overlap;
Gap。
只有确实需要几何切分的关系,才进入更重的几何操作。
这样原来的问题:
对 N 个 Solid 做一次大型聚合。
逐渐变成:
先建立稀疏关系图;
再处理真正相关的局部子图。
对于大型装配体,这个思路很有吸引力。
因为大多数对象实际上不会和所有其他对象发生关系。
如果可以稳定复用已经计算过的 Interface,后面很多步骤也不需要重新从全局 B-Rep 开始。
虚拓扑提供了另一条路径
以前我的默认想法是:
网格需要共形,
就必须先把 CAD B-Rep 改成完全共形。
后来开始意识到,这不是唯一方式。
某些情况下,真正需要的是:
网格器知道哪些逻辑边、逻辑面应该共享。
如果网格底座能够理解这些关系,那么部分拓扑调整可以不立即物化到原始 CAD。
例如:
一张面在逻辑上被多个 Interface 分区;
几条碎边在网格层视为同一条逻辑边;
两侧不同拓扑引用被标记为同一个共享接口。
这类虚拓扑不能解决所有问题。
真正存在体域重叠时,几何还是需要处理。
但它提供了一种新的选择:
只在必要时修改真实 B-Rep。
对于复杂模型,这有可能显著减少高成本 Boolean。
装配路径和切割路径应该分开
这也是我最近比较确定的一点。
并不是所有模型都应该进入同一套聚合流程。
如果目标是装配:
优先保留对象;
建立 Interface;
只处理必要的局部冲突。
如果目标涉及空气域、包围体或者真正的空间分割:
则需要更积极地物化切割,
确保最后得到互斥体域。
这两条路径在前处理阶段可能共享:
AABB;
候选对;
Interface 分析;
局部关系图。
但最后的执行策略不应该完全一样。
如果把所有场景都塞进“Union”这个概念里,后面会越来越难解释每一种行为。
聚合正确性要优先于速度
大型模型上,Boolean 很慢是一个很明显的问题。
所以很容易把重点放在:
怎么把几十分钟缩短成几分钟。
但共形网格场景里还有一个更重要的约束:
不能因为快而漏掉 Interface。
如果为了提速把一个真实相交关系误判为无关,最终可能导致:
重复体域;
非共形接口;
体网格失败。
这种结果通常比算法慢更难处理。
所以目前我更认可的顺序是:
先保证拓扑和接口正确;
再在这个前提下局部化;
缓存;
复用;
减少真实 Boolean。
性能优化必须建立在可验证的准确性上。
Sheet 是一个容易被忽略的边界情况
聚合流程很容易以 Solid 为中心。
但实际模型里可能同时存在:
Solid;
Shell;
Sheet;
Free Face。
如果流程只对 Solid 建图和执行,很可能出现:
实体部分处理正确,
Sheet 被静默绕过。
这对后续面网格同样是问题。
所以“输入对象是否完整进入处理链”本身应该成为 Validation 的一部分。
这类问题也提醒我:
聚合不能只围绕一个成功 Boolean 结果设计,
还必须围绕输入语义完整性设计。
我现在更愿意把聚合理解成拓扑准备
做到这里以后,我已经不太愿意把整个模块简单叫作:
Union。
更准确的目标其实是:
为后续网格和仿真准备正确的计算拓扑。
其中可能包含:
关系识别;
接口建立;
局部切分;
真实 Boolean;
虚拓扑;
Domain 构造;
拓扑验证。
Boolean 只是其中一种工具。
它仍然非常重要,但不应该再定义整个问题。
当前还没有完全解决的问题
这套方向还在持续验证。
第一,复杂 Interface 的稳定识别仍然很难。
尤其是:
近相切;
微小重叠;
容差敏感;
复杂曲面交线。
第二,虚拓扑能覆盖到什么程度,还取决于网格器的能力。
第三,真实切割和逻辑接口之间需要稳定的一致性协议。
第四,大型装配图上的增量更新还没有完全发挥出来。
理想状态下,修改一个局部对象以后不应该重新分析整个装配。
第五,最终 Validation 还需要更多真实模型积累。
尤其需要证明:
接口没有漏;
体域不重复;
Sheet 不丢失;
网格结果稳定。
这些都是后续比“Boolean 是否成功”更重要的指标。
小结
以前我把 CAD 聚合理解成:
多个 Shape
↓
Boolean
↓
一个结果
现在更愿意理解成:
多个几何域
↓
建立关系
↓
识别 Interface
↓
决定哪些关系需要物化
↓
局部 Boolean / 虚拓扑 / Domain 调整
↓
验证计算拓扑
这两种思路最大的区别是:
第一种以几何操作为中心。
第二种以最终计算语义为中心。
对 CAD 建模来说,Boolean Union 仍然是非常重要的基础能力。
但对 CAE 前处理来说,我现在越来越觉得:
几何聚合真正需要解决的,
不是怎么把很多 Shape 变成更少的 Shape,
而是怎样生成正确、可追踪、适合后续网格的计算拓扑。
这也是最近开始重新设计整个聚合和几何底座的根本原因。