occt中的History机制
1. 前言
拓扑追踪机制,一般会有两个层次的概念:一种是某个操作前后新旧拓扑的映射,另一种是标志的持久化,一般会称之为“拓扑命名机制”,这种要求模型存盘后还能恢复。
occt没有持久化的id或者Handle的概念,一般要想存盘后还能重新定位,一般是要通过TNaming来自行给拓扑对象命名。实际上,本专栏另一篇文件介绍基于XCAF文档实现属性读写的介绍中,使用的就是此机制。本文关注的主要第一种概念,一种瞬时、过程性的追踪,当用户执行一个操作(如布尔运算、倒角、拉伸切除)时,需要能力建立输入拓扑与输出拓扑之间的映射关系,这是后续属性继承的基础。
Parasolid接口中有tracking的概念,ACIS中也有历史公告板的工具,在occt中主要是BRepTools_History工具。下面会分别介绍三种内核获取拓扑映射的方法。
2. Parasolid中的拓扑追踪映射
Parasolid有一个全局变更记录机制,一般称之为“BULLETIN”,每当接口被调用,内核会自动将这次修改拆解为一系列原子操作,并记录到当前会话的 BULLETIN 日志中。
TODO
3. ACIS中的拓扑追踪映射
acis的api接口,可选一个DELTA_STATE参数,内核会将模型从操作前状态变换到操作后状态所需的所有原子变更信息存入其中。
TODO
4. occt中的History机制
occt中,每个算法对象可以记录它的入参Shape和结果Shape之间的映射关系。在这套体系中,它关注的是入参Shape在结果Shape中是否还存在、哪些与之关联,有三个概念:Modified、Generated 和 IsDeleted。
4.1 映射状态分类:Modified、Generated 、IsDeleted
Modified,修改,表示输入形状被替换或分割。它的几何或拓扑在操作中发生了变化,但是维度一般不会改变。
- 一个面被切割成多个子面,那么子面与原面是Modified关系(几何没变,但是拓扑边界变了);
- 一个面被平移,新面和原面也是Modified关系(几何发生改变);
Generated,生成,表示从输入形状新生出拓扑元素。它的维度一般会发生改变。
- 一个边在拉伸后生成一个面;
- 两个边相交生成一个顶点;
IsDeleted,已删除,表示输入形状在操作后被彻底移除,没有直接对应的新形状留下。
- 两个体重合的内部面,在合并时被完全移除
一个注意事项:入参Shape可以既是Deleted,又存在Generated映射对象。例如,在一个复杂操作中,一个边先拉伸了一个Face,但是最后自身又被倒角删除了。
此外,任意的Shape,Modified和Generated的结果不能相交。
4.2 Reused状态
occt的Shape/TShape是一个可高度复用的对象,导致一个入参Shape,可能完完整整的存在于结果Shape中。例如拉伸一个面,所得棱柱的底面对象,可能与入参Face完全相同(两个TopoDS_Face对象满足IsEqual或者IsSame)。我将这种称之为“Reused”。
4.3 BRepTools_History工具
很多occt的算法对象可以直接提供Modified/Generated/IsDeleted接口,但为了统一简便用法,提供了一个统一的BRepTools_History工具,并且基于此提供了统一的Merge功能。
4.3.1 构建
提供模板构造函数,要求算法对象存在Modified/Generated/IsDeleted接口。会从算法对象内部的History数据中,读取入参theArguments其下所有Shape对象的映射信息。
template<classTheAlgo>BRepTools_History(constNCollection_List<TopoDS_Shape>&theArguments,TheAlgo&theAlgo)可以主动往History中添加映射信息
voidAddGenerated(constTopoDS_Shape&theInitial,constTopoDS_Shape&theGenerated);voidAddModified(constTopoDS_Shape&theInitial,constTopoDS_Shape&theModified);voidRemove(constTopoDS_Shape&theRemoved);voidReplaceGenerated(constTopoDS_Shape&theInitial,constTopoDS_Shape&theGenerated);voidReplaceModified(constTopoDS_Shape&theInitial,constTopoDS_Shape&theModified);4.2 合并
将两段映射链 S→T 和 T→Q 合并为一段 S→Q。
两个History的Merge操作,就是将能去除的中间环节去除。一旦合并,两个算法中间的Shape就不存在于History中了;
voidMerge(constocc::handle<BRepTools_History>&theHistory23);4.3.2 查询
constNCollection_List<TopoDS_Shape>&Generated(constTopoDS_Shape&theInitial)const;constNCollection_List<TopoDS_Shape>&Modified(constTopoDS_Shape&theInitial)const;boolIsRemoved(constTopoDS_Shape&theInitial)const;