3. CATIA对象模型核心概念

CATIA的二次开发本质上是在操作一棵由COM对象组成的树。理解这棵树的层次关系,比记住任何一段代码都重要。因为一旦你清楚“谁包含谁、谁引用谁”,就能自己推导出访问路径,而不是靠死记硬背API文档。

一、对象层次:从Application到Sketch

CATIA的自动化对象模型是一棵严格的父子树。最顶层是Application,它代表整个CATIA进程本身,是所有操作的入口。Application之下挂着一个Documents集合,这个集合里存放着当前打开的所有文档。每个文档根据类型不同,可能是PartDocument、ProductDocument、DrawingDocument等。对于零件设计自动化来说,我们最关心的是PartDocument。

PartDocument本身是一个“容器文档”,它并不直接包含几何特征。真正的几何数据藏在它内部的Part对象里。Part之下是Bodies集合,一个Part可以包含多个Body,其中第一个通常是PartBody(主实体)。每个Body内部又包含Sketches集合、Shapes集合等。Sketch就是我们常说的草图,它是二维轮廓的载体,也是大多数三维特征的起点。

这条链路可以概括为:Application → Documents → PartDocument → Part → Bodies → Body → Sketches → Sketch。每一层都是通过上一层的属性或方法来获取的,不存在“跳级”访问的捷径。

Application CATIA进程入口 .Documents Documents 所有已打开文档的集合 .Item(1) / .ActiveDocument PartDocument 零件文档容器 .Part Part 几何数据根对象 .Bodies Bodies 实体集合(含PartBody) .Item(1) / .Item("PartBody") Body 实体容器 .Sketches Sketches 草图集合 .Item(1) .Shapes Shapes 三维特征集合 访问路径速查 Application.Documents → PartDocument.Part → Part.Bodies.Item(1) → Body.Sketches.Item(1) 每层用 . 逐级向下访问

二、对象引用:如何拿到你想要的节点

在VBA或C#中,访问这棵树有两种典型方式。第一种是逐级向下,从Application开始一层层取属性:

Dim app As Application
Set app = CATIA

Dim docs As Documents
Set docs = app.Documents

Dim pd As PartDocument
Set pd = docs.Item(1)          ' 按索引取第一个文档

Dim prt As Part
Set prt = pd.Part

Dim bodies As Bodies
Set bodies = prt.Bodies

Dim body As Body
Set body = bodies.Item("PartBody")  ' 按名称取主实体

Dim sketches As Sketches
Set sketches = body.Sketches

Dim sk As Sketch
Set sk = sketches.Item(1)

第二种是利用ActiveDocument快捷入口。当CATIA当前激活的窗口就是目标零件时,可以直接写:

Dim pd As PartDocument
Set pd = CATIA.ActiveDocument

Dim prt As Part
Set prt = pd.Part

两种方式没有优劣之分,但逐级访问更稳健,因为它不依赖“当前激活的是哪个文档”。在批量处理多个文档时,逐级访问几乎是唯一可靠的选择。

关键区别:PartDocument是文档层面的对象,负责文件打开、保存、关闭;Part是几何层面的对象,负责特征创建、更新、查询。很多初学者会混淆两者,试图在PartDocument上找Bodies,结果当然找不到。

三、集合遍历:Bodies与Sketches的循环访问

Bodies和Sketches都是集合对象,它们支持Count属性和Item方法。遍历的标准写法是:

Dim i As Integer
For i = 1 To bodies.Count
    Dim b As Body
    Set b = bodies.Item(i)
    Debug.Print "Body名称: " & b.Name
Next i

注意CATIA集合的索引从1开始,不是0。这是COM自动化中常见的约定,写循环时务必确认。Sketches的遍历同理:

Dim j As Integer
For j = 1 To body.Sketches.Count
    Dim s As Sketch
    Set s = body.Sketches.Item(j)
    Debug.Print "草图: " & s.Name
Next j

如果只想找特定名称的对象,可以用Item("名称")直接定位,比循环遍历更高效。但要注意,如果名称不存在,Item会抛出错误,所以实际代码中通常配合错误处理使用。

四、一个完整的遍历示例

下面这段代码遍历当前零件文档中的所有Body,并打印每个Body下的草图数量。它把前面讲的层次关系和集合遍历串在了一起:

Sub ListAllSketches()
    Dim pd As PartDocument
    Set pd = CATIA.ActiveDocument
    
    Dim prt As Part
    Set prt = pd.Part
    
    Dim bodies As Bodies
    Set bodies = prt.Bodies
    
    Dim i As Integer, j As Integer
    For i = 1 To bodies.Count
        Dim b As Body
        Set b = bodies.Item(i)
        Debug.Print "Body: " & b.Name & " | 草图数: " & b.Sketches.Count
        
        For j = 1 To b.Sketches.Count
            Dim s As Sketch
            Set s = b.Sketches.Item(j)
            Debug.Print "  - " & s.Name
        Next j
    Next i
End Sub

运行后,立即窗口会输出类似下面的结果(示例数据):

Body: PartBody | 草图数: 3
  - Sketch.1
  - Sketch.2
  - Sketch.3
Body: Body.2 | 草图数: 1
  - Sketch.4

这个输出直接反映了对象树的实际结构:PartBody下有3个草图,Body.2下有1个草图。如果你在开发中拿到的结果与预期不符,第一件事就是检查遍历的起点是否正确——是遍历了所有Body,还是只遍历了PartBody。

五、常见陷阱与验证方法

第一个陷阱是空引用。如果ActiveDocument不是PartDocument(比如当前激活的是ProductDocument),那么pd.Part会直接报错。稳妥的做法是先判断文档类型:

If TypeName(CATIA.ActiveDocument) = "PartDocument" Then
    ' 安全访问
End If

第二个陷阱是集合索引越界。在遍历前先检查Count是否大于0,可以避免不必要的运行时错误。第三个陷阱是对象未更新。通过API创建草图或特征后,有时需要调用Part.Update()才能让几何数据真正生效,否则后续遍历可能读不到刚创建的对象。

验证对象引用是否正确,最直接的方法是在立即窗口打印对象的Name属性。如果打印出的名称与你预期的一致,说明引用链路是通的;如果报错或名称为空,就需要往回追溯是哪一层取错了对象。

本节核心结论:CATIA对象模型是一棵严格的父子树,访问必须逐级向下。Application是入口,Documents是文档集合,PartDocument是零件文档,Part是几何根,Bodies和Sketches是集合。集合索引从1开始,遍历用Count+Item,定位用Item("名称")。理解这条链路,后续所有特征创建和参数修改都有了稳定的操作基础。