Technical note

面贴合与近接触修复

记录 CAD/CAE 几何修复中的一个工程判断:shape 有效不代表适合共形网格。面对 near contact、weak intersection 和模糊界面风险,修复目标不是强行改模型,而是在用户可确认的局部范围内做最小必要调整。


背景

前面几篇文章主要围绕 ShapeFixSewingFilling、free edge、open boundary 和局部补面展开。

这些问题大多可以从 BRep 拓扑或几何边界里比较直接地观察出来。比如 shape 无效、shell 不闭合、存在自由边、局部缺面、wire 不稳定。

但在 CAD/CAE 前处理里,还有一类更麻烦的问题:

shape 本身可能是有效的;
面也没有明显缺失;
BRepCheck_Analyzer 可能通过;
但后续网格仍然不稳定。

这类问题经常出现在近接触、弱相交、模糊界面和局部极小间隙附近。

从 CAD 几何角度看,它们未必是错误。从 CAE 网格角度看,它们却可能导致共形界面不明确、局部单元质量很差、接触关系难以识别,甚至导致网格失败。

这也是几何修复里比较难的一层:

修复目标不再只是让 shape valid,
而是让模型更适合后续网格和仿真流程。

Near contact 的问题

Near contact 可以理解为两个几何区域非常接近,但没有形成明确拓扑关系。

例如:

两个面之间有极小间隙;
两个零件局部几乎贴合;
一个面非常接近另一个实体边界;
局部边界距离小于后续网格尺寸;
接触关系在几何上没有明确表达。

这些情况从 BRep 角度未必是 invalid。两个面没有相交,也没有拓扑错误,只是距离很近。

但对网格来说,问题就复杂了。

如果网格尺寸大于这个间隙,网格器可能无法稳定表达这段距离。

如果两个区域本来应该接触,但几何上留了很小缝隙,后续共形界面可能无法建立。

如果两个区域本来不应该接触,但修复时被错误贴合,又会改变模型语义。

所以 near contact 的关键不在于“能不能修”,而在于:

该不该修。

这类问题不能简单当成 free edge,也不能直接用 Sewing 处理。Sewing 解决的是已有面之间拓扑未连接的问题;near contact 处理的是空间关系和后续网格风险。

Weak intersection 更麻烦

明显的几何相交通常比较容易判断。

两个实体穿透了,或者面之间有清晰交线,系统可以考虑布尔、切分、imprint 或其他几何处理。

Weak intersection 更麻烦。

它可能表现为:

两个面只在很小区域擦碰;
相交区域非常短;
交线不稳定;
局部几何几乎相切;
布尔结果对容差非常敏感;
网格阶段表现为模糊界面。

这类问题的风险在于,它处在“接触”和“不接触”之间。

从几何修复角度看,直接布尔可能太重。

从网格角度看,不处理又可能导致界面不稳定。

从用户语义角度看,系统也不能擅自决定两个区域到底应该贴合、分离,还是保持弱相交状态。

所以 weak intersection 更适合进入专门的风险修复流程,而不是被普通 Sewing、Filling 或 ShapeFix 混在一起处理。

真正难的是界面语义

很多 CAD/CAE 修复问题,最后都会落到一个问题:

界面语义不明确。

例如:

两个面应该是接触界面,还是应该保持间隙;
两个实体应该共形,还是应该独立划分;
局部极小缝隙是建模误差,还是设计特征;
弱相交是导入误差,还是建模结果;
贴合后是否会改变材料区域或边界条件。

这些不是几何 API 能直接回答的问题。

ShapeFix 不知道用户希望保留间隙。

Sewing 不知道两个零件能不能缝成一个区域。

Filling 不知道补出来的面是否符合仿真语义。

布尔运算也不知道当前相交是错误还是设计。

因此,面贴合与近接触修复必须带上下文。

这个上下文至少包括:

模型后续是否需要共形网格;
当前区域是否属于同一零件或同一体域;
用户是否确认需要贴合;
局部修改是否会影响边界条件;
修复后是否仍能追踪原始拓扑语义;
是否支持回滚。

没有这些上下文,系统不应该静默做强修复。

面贴合不是吸附

面贴合类修复最容易被误解成“把相近的面吸附到一起”。

这个理解非常危险。

在 CAD/CAE 场景里,面贴合的目标不是消灭所有间隙,也不是让模型看起来更干净。

它的目标应该是:

在确认需要修复的局部区域内,
用尽可能小的几何变化降低后续网格风险。

也就是说,它应该是局部的、保守的、可验证的。

不应该做:

全局扫描所有近距离面并自动贴合;
只要距离小于某个值就移动几何;
跨零件自动合并界面;
不检查后续影响就替换模型;
没有用户确认就改变接触关系。

更合理的做法是:

先检测 near contact 风险;
把风险区域聚成局部 region;
判断是否影响后续网格;
生成候选修复;
评估修复前后风险变化;
只接受最小必要修改;
高风险操作需要用户确认。

这里的“最小必要”很重要。

因为 CAD/CAE 修复不是重新设计模型。越少改动越容易解释,也越容易回滚。

为什么不能直接 Sewing

Near contact 很容易被误当成 Sewing 问题。

两个面靠得很近,看起来像是应该连上。但它们未必存在可缝合边界,也未必应该拓扑连接。

Sewing 适合处理:

已有面之间边界几何接近;
它们应该形成共享拓扑;
问题本质是拓扑未连接。

Near contact 处理的是:

面之间空间距离很小;
拓扑关系不明确;
后续网格可能不稳定;
是否贴合取决于工程语义。

两者不是同一类问题。

如果把 near contact 当成 Sewing,可能会出现几个风险:

把本来分离的零件缝到一起;
改变装配间隙;
破坏接触定义;
影响材料区域识别;
导致后续边界条件丢失或错位。

所以 Sewing 可以是某些修复流程的后处理,但它不能替代 near contact 判断。

为什么也不能直接布尔

另一个直觉做法是:既然界面不明确,那就做布尔或切分。

布尔当然是处理几何相交和界面压印的重要工具。但在 weak intersection 或 near contact 场景里,直接布尔不一定是最合适的第一选择。

原因有几个。

第一,布尔成本高。复杂模型上,布尔切分可能非常耗时,也可能引入大量细碎拓扑。

第二,弱相交对容差敏感。相交区域很小或几乎相切时,布尔结果可能不稳定。

第三,布尔会改变拓扑结构。这可能影响后续选择、边界条件、材料区域和显示索引。

第四,near contact 不一定是相交。没有实际交线时,布尔本身未必能解决“距离太近导致网格风险”的问题。

所以面贴合类修复并不是要替代布尔,而是处理另一类问题:

当模型不适合直接强布尔,
但局部关系又会影响网格时,
是否可以做更小、更可控的局部调整。

修复目标是降低风险

面贴合与近接触修复应该有一个清晰目标:降低后续流程风险。

这里的风险可以来自:

局部间隙小于网格尺寸;
两个面距离过近导致小单元;
界面无法形成共形关系;
弱相交导致边界不稳定;
模糊接触导致区域识别困难;
局部 open boundary 与 near contact 混合出现。

修复的目标不是让几何“更漂亮”,也不是把所有问题一次性消掉。

而是在不破坏模型语义的前提下,让关键风险下降。

一个合理的修复结果应该能回答:

修复前风险在哪里;
修复后风险是否下降;
几何移动量是否足够小;
是否引入新的相交或间隙;
是否改变了不相关区域;
是否适合继续网格流程。

如果修复后模型变化很大,即使风险下降,也不一定是可接受结果。

因为用户需要的是可信修复,而不是强行改模型。

候选方向要可解释

面贴合类修复通常需要决定一个调整方向。

例如局部面应该向哪里移动、沿什么方向靠近、是否沿法向、是否沿参考轴、是否根据最近障碍物关系决定方向。

这些都是实现上的关键点,但公开文章里没必要展开完整算法。

从工程原则上,可以这样理解:

方向应该来自局部几何关系;
方向应该尽量稳定;
方向应该避免引入新的碰撞;
方向应该优先服务修复目标;
方向不明确时不应该强修。

候选方向不是越多越好。

方向越多,搜索空间越大,也越容易出现难以解释的结果。

对于用户来说,更重要的是系统能说明:

为什么建议沿这个方向调整;
调整影响哪些局部面;
调整量是否足够小;
修复后风险是否下降;
是否支持预览和撤销。

这比暴露内部候选方向生成算法更有价值。

找最小有效修改

面贴合往往涉及一个位移量。

位移太小,风险没有下降。

位移太大,模型语义可能被破坏。

所以这类修复不应该简单使用固定偏移值。

更合理的原则是:

从小位移开始尝试;
评估风险是否下降;
避免过度修改;
达到目标后停止;
无法稳定改善时放弃自动修复。

也就是说,修复不是追求“移动到某个固定位置”,而是寻找:

最小有效修改。

这个思想很适合 CAD/CAE 场景。

因为很多模型来自外部导入,原始几何可能有误差,但不能被随意大幅修改。

最小有效修改可以降低风险,同时保留更多原始模型语义。

具体搜索策略、步长、评分方式、停止条件都属于实现细节,公开讨论到原则层面就够了。

修复前后要能对比

面贴合类修复最不能缺的是风险评估。

没有评估,就无法判断修复是否有效。

只要移动了几何,不代表修复成功。

修复前后至少要对比:

near contact 区域是否减少;
局部最小间距是否改善;
是否产生新的穿透;
是否产生新的 near contact;
是否影响其他不相关区域;
是否改善后续网格边界;
shape validity 是否仍然通过。

对于共形网格目标,还可以关注:

界面是否更明确;
T-junction 风险是否下降;
open boundary 是否减少;
局部网格尺寸是否更合理;
接触区域是否更稳定。

这里的重点是“对比”。

单独看修复后的模型,很难判断它是否真的更好。

只有比较修复前后的风险变化,才能决定是否接受这次调整。

这也是面贴合类修复不能只返回一个新 shape 的原因。它应该返回带评估信息的修复结果。

必须预览和确认

面贴合与近接触修复比普通 Sewing、补面更需要预览。

因为它改变的是几何位置关系。

用户必须知道哪些区域被移动了、移动方向是什么、移动量大概是多少、修复后接触关系有什么变化。

预览可以包括:

风险区域高亮;
修复前后位置对比;
候选调整方向;
受影响面集合;
最小间隙变化;
是否仍存在残留风险。

用户确认后再提交修改。

这种交互流程对工程软件很重要。因为系统无法完全替用户判断接触关系和设计意图。

即使算法认为风险下降,用户也可能不希望这样修。

所以高风险修复应该遵循:

系统检测;
系统建议;
系统预览;
用户确认;
系统提交;
系统报告;
支持撤销。

这比后台静默修复更符合 CAD/CAE 修复的工程边界。

修复必须局部化

面贴合修复应该尽量局部化。

输入最好是一个明确 region,而不是整个模型。

输出也应该只影响必要的局部面或局部 patch。

原因很简单:

局部修复更容易解释;
局部修复更容易验证;
局部修复更容易回滚;
局部修复不容易误改模型其他部分;
局部修复更符合用户选择意图。

全局 near contact 自动修复风险很高。

尤其是大型装配体或复杂 CAD/CAE 模型里,局部间隙可能很多,其中有些是缺陷,有些是设计,有些是无关区域。

系统不应该把所有近距离区域都当成待修复对象。

更可控的方式是:

先检测全局风险;
把风险以 region 形式展示;
用户选择要处理的区域;
系统生成局部候选修复;
修复后只替换局部结果。

这样能兼顾自动检测和人工确认。

不能破坏拓扑语义

面贴合类修复很容易影响拓扑语义。

例如移动一个面以后,可能会影响:

原来的边界条件对应面;
材料区域;
接触界面;
零件间隙;
用户选择历史;
显示和拾取索引;
后续布尔或网格流程。

所以修复时不能只看几何位置。

还要考虑:

是否保留原有 face 语义;
是否需要更新拓扑映射;
是否影响属性绑定;
是否影响工程树对象;
是否需要重新生成显示;
是否写入撤销栈。

这也是为什么面贴合不能作为一个孤立算法存在。

它必须和文档管理、拓扑映射、显示选择、撤销系统配合。

在工程实现里,几何算法只是中间一环。

真正让功能可用的是完整的模型更新流程。

和网格边界形成闭环

上一篇文章讲到,可以从网格边界反推几何问题。

面贴合与近接触修复正好可以和这个检测形成闭环。

流程可以理解成:

网格边界检测发现风险;
风险聚成局部 region;
映射回几何 face / edge;
判断是否属于 near contact 或 weak intersection;
生成局部修复候选;
执行最小必要调整;
重新检查几何和网格边界风险。

这样修复就不是凭感觉进行,而是有检测依据、有修复目标、有结果验证。

这个闭环很重要。

因为面贴合类修复不是传统意义上的“坏拓扑修复”。它更像是面向后续网格质量的几何风险控制。

只有修复前后风险确实下降,才能说明这次修复有意义。

和 Splitter 的关系

在一些 CAD/CAE 流程里,共形界面可以通过几何切分或布尔压印来处理。例如使用 Splitter 将相接触或相交的几何区域切分成一致边界。

这类方法适合处理明确接触、明确相交和需要拓扑共形的情况。

但 near contact 和 weak intersection 有时候处在更尴尬的位置:

距离太近,网格不稳定;
又没有形成清晰交线;
直接 Splitter 成本高;
直接 Sewing 语义不对;
直接忽略后续风险大。

这时面贴合类修复可以作为一种更局部、更保守的预处理思路。

它不是替代 Splitter,也不是替代布尔。

它更像是在进入重型几何处理之前,先尝试用最小必要调整消除某些模糊界面。

当然,这类策略必须谨慎使用。

对于必须严格共形的真实接触链,仍然应该通过明确的几何切分或共形聚合来保证拓扑一致性。

面贴合更适合处理局部、可确认、可预览的 near contact 风险。

不确定时就放弃

面贴合类修复有一个重要原则:

不确定时,宁可不自动修。

遇到下面情况,就应该停止自动修复,转为提示用户:

无法判断两个区域是否应该接触;
候选方向不稳定;
小位移无法降低风险;
需要大幅修改几何才有效;
修复后引入新的相交;
修复后影响其他区域;
用户没有确认高风险操作;
修复目标和模型语义冲突。

这类失败不是坏事。

几何修复里最危险的不是失败,而是系统自信地做了错误修改。

尤其在 CAD/CAE 场景里,错误修复可能影响后续仿真结果,比保留问题更难排查。

所以面贴合修复应该是保守的。系统可以提供建议,但不应该为了“自动修复率”强行修改模型。

结果应该包含什么

这类修复结果不适合只返回 TopoDS_Shape

它应该包含更丰富的信息:

是否成功;
是否有改进;
风险是否下降;
受影响区域;
调整方向;
调整量级;
是否产生新相交;
shape validity 是否通过;
是否建议用户接受;
是否仍有残留风险;
修复后的 shape。

可以抽象成:

struct FittingResult
{
    bool success = false;
    bool improved = false;
    bool valid = false;

    double maxDisplacement = 0.0;
    double riskBefore = 0.0;
    double riskAfter = 0.0;

    TopoDS_Shape resultShape;
    std::string message;
};

这只是示意,不代表实际接口设计。

重点是:这类修复必须能解释“为什么接受结果”。否则用户只看到模型被移动了,却不知道它是否真的解决了网格风险。

公开讨论的边界

这篇文章讨论的是工程思路,不展开完整实现。

尤其不适合展开:

完整候选方向生成逻辑;
具体 offset 搜索策略;
风险评分公式;
具体阈值;
停止条件;
失败模型日志;
内部策略名称;
真实类名和接口名;
客户模型截图;
自动调度策略表。

更适合公开的是这些原则:

面贴合不是强行吸附;
修复目标是最小必要调整;
必须服务后续共形网格;
必须有修复前后风险对比;
必须支持预览、确认和回滚;
不确定时应该放弃自动修复。

这样既能分享工程判断,又不会暴露实现细节。

小结

把 near contact、weak intersection 和面贴合放到几何修复体系里,我现在更认可这样的边界:

shape valid 不代表适合共形网格;
near contact 不等于普通面缝隙;
weak intersection 不一定适合直接布尔;
面贴合不是把所有近处都吸到一起;
修复目标应该是风险下降,而不是几何完美;
修改量应该尽量小;
修复范围应该尽量局部;
结果必须可预览、可验证、可回滚;
无法判断用户语义时不应该自动修复。

这类修复比 Sewing、补面更敏感。

它已经不只是几何拓扑修复,而是面向 CAE 前处理的模型风险控制。

所以它必须放在专门的修复模块里,而不是导入阶段、网格阶段或显示阶段随手处理。

CAD/CAE 几何修复的目标不是把模型改得越干净越好。很多时候,过度修复反而会破坏模型语义。

面贴合与近接触修复尤其如此。

这类问题的难点在于:

它们不一定让 shape invalid,但会影响后续网格和共形界面;
它们不一定应该被自动修,但又不能完全忽略;
它们可能需要非常小的局部调整,也可能需要用户确认后放弃修复。

所以更稳妥的工程原则是:

先检测风险;
再定位 region;
再判断语义;
再生成候选修复;
再做最小必要调整;
再验证风险是否下降;
最后由用户确认和回滚机制兜底。

从这个角度看,面贴合不是一个单独算法,而是一套面向共形网格的保守修复流程。

它和前面几篇文章里的 ShapeFixSewingFilling、free edge、局部补面、网格边界检测一起,组成了一个更完整的 CAD/CAE 几何修复体系:基础几何要有效,局部拓扑要清楚,网格边界要稳定,复杂风险要可解释地处理。

这也是我现在对几何修复模块的一个最终判断:

修复不是为了替用户重建模型,
而是为了在尽量保留模型语义的前提下,
让后续工程流程更稳定。