一、前言
春节期间,笔者发布了一个关于 CATIA 获取结构树信息的视频,算是一个预热,这期内容咱们就来解析该功能的底层代码。学会如何遍历结构树,对于CATIA二开来说,是一项很重要的技术手段。但坦白地说,遍历结构树这样的需求并不常见,大部分情况下,我们只需要拿到当前激活的零件activePart即可,而复杂的项目如果需要跨零件或者跨产品进行自动化操作,就必须按层级遍历树上的元素,以便获取非激活产品(零件)内的几何元素。
[video(video-4TEyKyuS-1613828469640)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=929173635)(image-https://ss.csdn.net/p?http://i1.hdslb.com/bfs/archive/8ca89a73408b83e5d6fef4cfca639bcdbaeec347.jpg)(title-获取 CATIA 结构树信息)] // 获取当前激活的零件 activePart = catia.ActiveEditor.ActiveObject as Part;
在遍历结构树之前,应该确保CATIA软件已经打开一个模型文件,即存在一个ActiveEditor。为了方便后续代码的测试工作,笔者新建了一个极具破环性💣的试验模型树结构:根节点下包含两个产品子节点,每个产品子节点下又包含一个或多个零件,每个零件下包含一个3D Shape。
二、方法及步骤
自己挖坑还得自己填😂。为了帮助读者们理解其中的层次和逻辑关系,笔者绘制了图2,结合图示,看代码会更轻松。
遍历的第一步必然是获取模型文件的根节点,这里就用到了我们**《CATIA二次开发—API梳理》**一期中提到的Service,通过 editor-level 的service获取根节点的Occurrence model;
// 调用 editor-level service PLMProductService service = (PLMProductService)CATIA.ActiveEditor.GetService("PLMProductService"); // Getting the root occurrence of the editor VPMRootOccurrence vpmRootOcc = service.RootOccurrence;
从Occurrence model中获得根产品的Reference ,这一步很重要,需要从Occurrence model切换为Reference-instance model,才能往纵深处遍历;
VPMReference vPMRefOnRoot = vpmRootOcc.ReferenceRootOccurrenceOf;
从根节点中获取所有的instance(即图2中的1.1和 1.2),vpmInstsL1
是一个集合;
VPMInstances vpmInstsL1 = vpmRefOnRoot.Instances;
遍历第一层子节点(变量命名中也包含当前节点所在层数,例如上述vpmInstsL1中的L1表示其位于第一层),并获取每个instance 的reference,以便获取下一个层级的实例;
for (int i = 1; i < vpmInstsL1.Count + 1; i++) { VPMInstance vpmInstL1 = vpmInstsL1.Item(i) as VPMInstance; // 拿到reference才能拿到instances VPMReference vpmRefInstL1 = vpmInstL1.ReferenceInstanceOf; ... ... }
除了根节点,所有PLM实体都具有 Reference 和 Instance, Reference作用在于获取该节点子实例的集合
此时我们已经可以拿到1.1 A.1(1.1.1)这个产品节点,需要继续往下递进,同样通过Instances属性获取此节点的所有实例,并再次遍历;
VPMInstances vpmInstsL2 = vpmRefInstL1.Instances; for (int j = 1; j < vpmInstsL2.Count + 1; j++) { VPMInstance vpmInstL2 = vpmInstsL2.Item(j) as VPMInstance; VPMReference vpmRefInstL2 = vpmInstL2.ReferenceInstanceOf; ... ... }
这时已经到了第二层,我们可以顺利地拿到1.1.1 A.1(Physical Product00029)这个节点,如果还需要再递进一层,那就是第三层,即到了3D Shape,此时获取实例集合的方式有所变化,因为该层是实际用于表达几何元素的层级,且没有子节点,获取方式由原先的Instances属性变为RepInstances属性。
🔔3D Shape中的几何图形集、零件几何体等不算作其子节点
VPMRepInstances vpmRefInstsL3 = vpmRefInstL2.RepInstances; for (int k = i; k < vpmRefInstsL3.Count + 1; k++) { VPMRepInstance vpmRepInstL3 = vpmRefInstsL3.Item(k) as VPMRepInstance; VPMRepReference vpmRepRefL3 = vpmRepInstL3.ReferenceInstanceOf; }
到此,对于图2的结构树已完成遍历,大家完全可以根据此逻辑,举一反三。但又有另外一个问题浮出水面:假如我们不知道结构树长啥样,我们又该如何去遍历呢❓ 能不能实现提供任意一个模型文件都能像图3所示返回其结构树的层次关系❓ 关于这个问题,正是我视频中所实现的功能,这部分功能本期不展开,留给读者们独立思考的空间。
图3.产品模型结构示意
🔉 当然,遍历结构树的方法不限于此。以下是笔者在 COE 论坛的QA,提供了另一种解决的思路。
Q(cao bingyong):
Hi, I am new in V6 COM development, and recently encountered a problem of getting the GeoSet from another part (not in active) which is in another product. I can use the following code to get the root product , but have no idea to find the child product of the root one by name, not to mention, to find the part inside. So, can anyone help? Thanks a lot!
pLMProductService.EditedContent.Item(1)
A(Mahefa Ralijaona):
Hello, There are I think several ways to do this. Here is one of them: not necessarily the fastest or the simplest, but it's one way. Hope it helps. Sub CATMain() ' Getting active editor (the current tab) Dim oActiveEditor As Editor Set oActiveEditor = CATIA.ActiveEditor ' Getting the root occurrence of the editor Dim vpmRootOcc As VPMRootOccurrence Set vpmRootOcc = oActiveEditor.GetService("PLMProductService").RootOccurrence ' Getting all its children Dim vpmRootChildrenOcc As VPMOccurrences Set vpmRootChildrenOcc = vpmRootOcc.Occurrences ' Getting the first one (28629.1 in your case) Dim vpmRootChild1Occ As VPMOccurrence Set vpmRootChild1Occ = vpmRootChildrenOcc.Item(1) ' Getting the first part inside your 28629.1 (instance 28628.2 of the 3DPart in your case) Dim vpmPart1Occ As VPMOccurrence Set vpmPart1Occ = vpmRootChild1Occ.Occurrences.Item(1) ' Getting the part instance, then the reference Dim vpminstPart As VPMInstance Set vpminstPart = vpmPart1Occ.InstanceOccurrenceOf Dim vpmrefPart As VPMReference Set vpmrefPart = vpminstPart.ReferenceInstanceOf ' Getting the 3DShape instance, then the 3DShape reference Dim vpmrepinstPart As VPMRepInstance Set vpmrepinstPart = vpmrefPart.RepInstances.Item(1) Dim vpmreprefPart As VPMRepReference Set vpmreprefPart = vpmrepinstPart.ReferenceInstanceOf End Sub
三、参考资料
《3DEXPEROENCE Automation Help》