MEAICAD预约演示
技术博客/二次开发
二次开发

CATIA 二次开发:CAA 对象选择代理进阶,精准抓取零件与几何

2026-08-19#CATIA#二次开发

一、痛点引入

上回我们用 CATIndicationAgent 实现了"两点画直线",但工业场景里很少让你直接点屏幕。更多时候,领导的需求是这样:

"批量选中所有 M8 螺栓,自动统计数量。""点击某个面,自动提取这个面的所在零件和材料。"

手动点选容易漏、容易多选,还分不清你点的是几何元素还是产品节点。CATIA 的 CATPathElementAgent 就是专门解决这个问题的:它让用户在 3D 视图里点,脚本自动判断类型、提取上下文、拿到真正的业务对象。


二、核心思路

本篇文章在上一篇状态机命令的基础上,把鼠标点击代理从 CATIndicationAgent 升级为 CATPathElementAgent,实现"对象选择 类型过滤 路径解析 上下文提取"的完整链路。

用户点击 3D 视图
    
CATPathElementAgent 捕获选择
    
AddElementType 过滤允许的类型(Part/产品/几何)
    
GetValue() 拿到 CATPathElement 路径
    
解析路径  拿到选中对象 + 父级 Part/Product
    
输出信息或执行下一步业务

你需要准备

  • 已配置好的 CAA RADE 开发环境(参考 08-15 文章)
  • 一个继承 CATStateCommand 的命令类(参考 08-17 文章)
  • 熟悉 BuildGraph() 四步法

三、环境搭建(3分钟)

与上一篇相同,新建一个 CAA 模块,核心文件结构如下:

MySelectModule.m\
  ├── IdentityCard.h
  ├── Imakefile.mk
  └── PublicInterfaces\
      └── MySelectCmd.h
  └── src\
      └── MySelectCmd.cpp

Imakefile.mk 关键 LINK_WITH

LINK_WITH = $(WIZARD_LINK) \
            CATApplicationFrame \
            CATDialogEngine \
            CATVisualization \
            CATMathematics \
            MecModInterfaces \
            ProductStructureInterfaces \
            ObjectSpecsModeler

CATPathElementAgent 来自 CATDialogEngineCATVisualization;解析出的几何对象需要 MecModInterfaces(Part 上下文)和 ProductStructureInterfaces(Product 上下文)。


四、核心代码

下面是一个完整命令类,实现:用户在 Part 或 Product 中点选一个对象,命令自动判断它是几何元素、零件还是产品节点,并打印名称与父级上下文。

// MySelectCmd.h
#include "CATStateCommand.h"
#include "CATPathElementAgent.h"

class MySelectCmd : public CATStateCommand
{
    CATDeclareClass;
public:
    MySelectCmd();
    virtual ~MySelectCmd();

    virtual void BuildGraph();

    // 选择完成后的处理动作
    void OnElementSelected(CATCommand * iCmd, CATNotification * iNotif,
                           CATCommandClientData iData);

private:
    CATPathElementAgent * _pSelectAgent;
};
// MySelectCmd.cpp
#include "MySelectCmd.h"

// 必要的头文件
#include "CATPathElement.h"
#include "CATUnicodeString.h"
#include "CATISpecObject.h"           // 通用对象接口
#include "CATIPrtContainer.h"         // Part 容器
#include "CATIPrtPart.h"              // Part 对象
#include "CATIProduct.h"              // Product 对象
#include "CATIMfBRepFeature.h"        // BREP 几何特征(面/边/顶点)
#include "CATIContainer.h"
#include "CATDialogAgent.h"

CATImplementClass(MySelectCmd, Implementation, CATStateCommand, CATNull);

MySelectCmd::MySelectCmd()
    : CATStateCommand(NULL, "MySelectCmd", CATCommandModeExclusive)
    , _pSelectAgent(NULL)
{
}

MySelectCmd::~MySelectCmd()
{
    if (_pSelectAgent) {
        _pSelectAgent->RequestDelayedDestruction();
        _pSelectAgent = NULL;
    }
}

void MySelectCmd::BuildGraph()
{
    // ========== 第1步:创建 CATPathElementAgent ==========
    _pSelectAgent = new CATPathElementAgent("SelectAgent");

    // 设置可选择类型:几何元素(BREP)、Part、Product
    // 实际过滤行为取决于 AddElementType 的接口标识
    _pSelectAgent->AddElementType(CATISpecObject::ClassId());

    // 行为:预高亮 + 点击即接受
    _pSelectAgent->SetBehavior(CATDlgEngWithPrevaluation
                              | CATDlgEngAcceptOnPrevaluate);

    // ========== 第2步:创建状态并把代理加入状态 ==========
    CATDialogState * pSelectState = GetInitialState("SelectState");
    pSelectState->AddDialogAgent(_pSelectAgent);

    // ========== 第3步:添加结束转移:选择完成后触发动作 ==========
    AddTransition(pSelectState, NULL,
                  IsOutputSetCondition(_pSelectAgent),
                  Action((ActionMethod)&MySelectCmd::OnElementSelected));
}

void MySelectCmd::OnElementSelected(CATCommand * iCmd,
                                    CATNotification * iNotif,
                                    CATCommandClientData iData)
{
    // ========== 第4步:获取选择路径 ==========
    CATPathElement * pPath = _pSelectAgent->GetValue();
    if (!pPath) return;

    CATULONG32 pathSize = pPath->GetSizeOfPath();
    if (pathSize == 0) return;

    // 路径最后一个元素通常是用户直接点击的对象
    CATBaseUnknown * pSelected = pPath->GetElement(pathSize);
    if (!pSelected) return;

    CATISpecObject_var spSelected = pSelected;
    if (!!spSelected) {
        CATUnicodeString name;
        spSelected->GetName(&name);
        printf("选中对象名称:%s\n", name.ConvertToChar());
    }

    // ========== 第5步:判断类型并提取上下文 ==========
    // 尝试解释为 BREP 几何特征
    CATIMfBRepFeature_var spBRep = pSelected;
    if (!!spBRep) {
        printf("类型判断:BREP 几何元素(面/边/顶点)\n");

        // 从路径中向上查找所在 Part
        for (CATULONG32 i = pathSize; i >= 1; --i) {
            CATBaseUnknown * pElem = pPath->GetElement(i);
            CATIPrtPart_var spPart = pElem;
            if (!!spPart) {
                CATUnicodeString partName;
                spPart->GetName(&partName);
                printf("所属 Part:%s\n", partName.ConvertToChar());
                break;
            }
        }
    }

    // 尝试解释为 Part 级别对象
    CATIPrtPart_var spPrtPart = pSelected;
    if (!!spPrtPart) {
        printf("类型判断:Part 文档根节点\n");
    }

    // 尝试解释为 Product 节点
    CATIProduct_var spProduct = pSelected;
    if (!!spProduct) {
        CATUnicodeString pn;
        spProduct->GetPartNumber(&pn);
        printf("类型判断:Product 节点,件号:%s\n", pn.ConvertToChar());

        // 获取父级 Product
        CATIProduct_var spParent = spProduct->GetFather();
        if (!!spParent) {
            CATUnicodeString parentPn;
            spParent->GetPartNumber(&parentPn);
            printf("父级 Product 件号:%s\n", parentPn.ConvertToChar());
        }
    }

    // 选择完成后,重置代理以便连续选择
    _pSelectAgent->InitializeAcquisition();
}

代码解析

  • CATPathElementAgent:专门的对象选择代理,返回一条"选择路径",路径上的每个节点代表从根到选中对象的层级。
  • AddElementType(CATISpecObject::ClassId()):限定可选对象类型。实际过滤精度与传入的接口 ID 有关,可组合多个 AddElementType 实现多选。
  • GetValue() / GetSizeOfPath() / GetElement(index):解析路径的核心 API,index 通常从 1 开始。
  • CATIMfBRepFeature:BREP 特征接口,用于判断用户选中的是面、边还是顶点。
  • InitializeAcquisition():重置代理,使命令可以连续接收下一次选择。

五、效果对比

对比项传统手动选择CAA 对象选择代理
耗时每次人工判断类型、逐层翻结构树点击即识别,毫秒级返回
出错率高(容易选到引用而非实例)极低(路径精确到实例)
可扩展性无法批量处理可作为后续自动化命令的第一步
上下文获取需手动打开父级查看代码直接解析路径拿到 Part/Product

六、进阶用法

进阶 1:限定只选特定类型

如果你只想让用户选择平面或产品节点,可以传入更精确的接口 ID:

// 只选平面(CATIPlane 接口,需包含对应头文件)
_pSelectAgent->AddElementType(CATIPlane::ClassId());

// 只选 Product 节点
_pSelectAgent->AddElementType(CATIProduct::ClassId());

进阶 2:多选模式 + 结果收集

通过 SetBehavior 开启多选,循环调用 GetValue() 直到用户按 Esc:

_pSelectAgent->SetBehavior(CATDlgEngWithPrevaluation
                          | CATDlgEngAcceptOnPrevaluate
                          | CATDlgEngMultiAcquisition);

// 在 OnElementSelected 中收集结果,判断结束条件
if (_pSelectAgent->IsEndPreselected()) {
    // 用户结束多选,统一处理已收集的对象
}

关注回复「CAA选择」获取完整源码

下一篇:CAA C++ 对话框与状态命令联动,手把手教你做带输入框的交互命令


_栏目:开发实战 | 发布日期:2026-08-19 | 字数:约1180字_

本文为基础实战分享。如需完整源码包、配套课程或企业内训,欢迎进一步了解付费体系。

咨询深入资源 →