← 返回首页

CATIA V5 CAA 特征选择代理机 使用指南

CATIA V5 CAA 特征选择代理机 使用指南

作者:CATIA开发者指南
发布时间:2026年6月8日 15:21
原文链接:https://mp.weixin.qq.com/s?__biz=MzkxNTQ0MTY0NQ==&mid=2247486514&idx=1&sn=112d465d1cec62ae5d012733c8aaed80&chksm=c15e5eb0f629d7a6b7848cf5e89c0b58ad132cdab27c83c1b36562e6f99e8ea6d1bc384208af&cur_album_id=2800898825187262468&scene=189#wechat_redirect


前面几篇文章已经讲过 CATStateCommand、常用 dialog agent、自定义特征和 CATOtherDocumentAgent。本文单独展开机械建模中最容易混淆的一组选择代理机:CATFeatureAgentCATFeatureImportAgent

它们都属于 MechanicalModelerUI framework,都用于机械上下文中的选择,也都继承自 CATPathElementAgent。但二者解决的问题并不一样:

CATFeatureAgent 负责“在机械上下文里选择并解释对象”。
CATFeatureImportAgent 负责“选择外部 Part 几何,并把它导入目标 Part 形成外部引用”。

如果只把它们看成“更高级的 CATPathElementAgent”,很容易在装配上下文、BRep featurization 和外部引用持久化上踩坑。

1. 先看继承和位置

在 dialog agent 体系里,它们的位置可以简化成:

CATCommand
  -> CATDialogAgent
       -> CATAcquisitionAgent
            -> CATPathElementAgent
                 -> CATFeatureAgent
                      -> CATFeatureImportAgent

这意味着它们首先仍然是选择 agent:

  • 可以添加到 CATDialogState
  • 可以用 IsOutputSetCondition 触发 transition;
  • 单选结果仍然通过 GetValue() 读取 CATPathElement
  • 多选结果仍然通过 GetListOfValues() 读取 CATSO
  • 类型过滤仍然基于接口,例如 AddElementType(IID_xxx)

但它们比普通 CATPathElementAgent 多了一层机械建模语义:

  • 能处理 mechanical feature、face、edge、BRep 等选择;
  • 能控制是否把选择对象 featurize 成 BRep feature;
  • 能理解 Product 装配上下文中的当前 component;
  • 能把 Visu mode 文档在选择时自动切换到 Design mode;
  • 默认 tooltip 和用户选择过滤行为更贴近机械建模命令。

官方文档还明确说明:这两个类应该直接使用,不建议派生。需要扩展过滤逻辑时,优先使用类型过滤、ordered type list、SetFilter 或状态机 action 中的业务检查。

2. 快速差异表

对比点 CATFeatureAgent CATFeatureImportAgent
继承关系 继承 CATPathElementAgent 继承 CATFeatureAgent
核心用途 机械上下文选择 feature、BRep、拓扑子元素 选择其它 Part 几何并导入目标 Part
是否导入外部几何 不导入,只返回选择路径或 featurized 对象 会导入,导入对象聚合在目标 Part 的 External References 下
装配外部选择 默认禁止,可用 CATFAgAllowSelectionInContext 放开 不能像 CATFeatureAgent 那样禁止外部 component 选择
SetActiveObjectPath 含义 指定当前/目标 component,默认行为下只允许在该路径对应文档内选择 指定要把外部选择导入到哪个 Part
GetValue() 语义 返回选择路径 返回选择路径;发生导入时返回导入后对象的路径
类型检查 选择时按接口过滤 可选择是否在导入后再按接口检查
典型风险 临时 BRep feature 没有保存或删除 把外部引用导入到错误 Part,或忘记处理 Keep Link 设置

一句话选型:

需要机械上下文选择,用 CATFeatureAgent。
需要把外部 Part 几何导入目标 Part,用 CATFeatureImportAgent。

3. CATFeatureAgent 解决什么问题

普通 CATPathElementAgent 能选对象,但它并不主动处理机械建模里这些问题:

  • 用户点到的是 face、edge、vertex 还是某个 mechanical feature;
  • 这个拓扑选择是否需要转换成稳定可引用的 BRep feature;
  • 当前命令运行在 Product 中时,什么叫“当前 Part”;
  • 用户是否允许选到当前 component 以外的几何;
  • 选择路径的 leaf 是否已经变成 featurized 的 BRep feature。

CATFeatureAgent 的职责就是在 CATPathElementAgent 之上补上这些机械语义。

典型场景:

场景 推荐用法
Part Design 命令中选择一个支撑面 CATFeatureAgent + 面/BRep 接口过滤
GSD 命令中选择 wire、edge、surface CATFeatureAgent,按需要设置 featurization mode
自定义特征需要保存一个拓扑输入 只有需要稳定 BRep 引用时才启用 featurization
Product 环境中只允许选当前 Part 默认行为 + SetActiveObjectPath
Product 环境中允许选其它 component 设置 CATFAgAllowSelectionInContext,再用 ElementInContext 判断来源

构造函数的主要参数如下:

CATFeatureAgent(
const CATString&          iId,
  CATClassId                iType       = NULL,
  CATDlgEngBehavior         iBehavior   = NULL,
  CATMfFeaturizeMode        iMode       = 0,
const CATBaseUnknown_var& iSupport    = NULL_var,
  CATFeatureAgentBehavior   iAgBehavior = NULL);

参数可以这样记:

参数 含义
iId agent 标识,也用于资源文件中的提示、undo/redo 标题等
iType 期望选择对象实现的接口;为 NULL 时不在构造阶段限制
iBehavior dialog engine 行为位,例如 CATDlgEngWithPSOHSO、CATDlgEngWithPrevaluation
iMode BRep featurization 模式,默认 MfNoFeaturization
iSupport featurized 对象的支撑 feature;某些 mode 需要提供
iAgBehavior CATFeatureAgent 自己的行为位

如果不显式传 iBehavior,它有两个默认行为和普通 CATPathElementAgent 相反:默认带 tooltip,默认启用用户选择过滤。

4. Featurization 不要默认打开

CATFeatureAgent 最重要也最危险的能力是 featurization。

在 CAA 机械建模里,用户点到的拓扑对象有时不能直接作为特征输入长期保存。为了让后续更新、命名和上下文关系更稳定,系统可以把选中的几何转换成一个 BRep feature。这个 BRep feature 至少实现 CATIMfBRep

常见 mode 来自 CATMfBRepDefs.h

mode 含义
MfNoFeaturization 不创建 BRep feature
MfFunctionalFeaturization 创建 functional BRep feature
MfRelimitedFeaturization 创建 relimited BRep feature
MfBorderFeaturization 创建 border BRep feature
MfWireFeaturization 创建 wire BRep feature
MfPermanentBody BRep feature 使用 permanent body
MfTemporaryBody BRep feature 使用 temporary body
MfSelectingFeatureSupport 以 selecting feature 作为 support
MfLastFeatureSupport 以 last feature 作为 support

文档里有一句非常关键:featurization 只在确实需要时使用。原因是,一旦创建了 BRep feature,你只有两个正确选择:

  • 保留它:用 CATIDescendants 等机制把它聚合到合适的 feature 下,让系统管理自动删除。
  • 删除它:用 CATICutAndPastable 删除,不要把临时对象留在模型里。

判断当前选择是否被 featurize:

CATPathElement *path = _featureAgent->GetValue();
if (NULL != path && TRUE == _featureAgent->FeaturizedElement(path))
{
  CATBaseUnknown *brepFeature = _featureAgent->GetElementValue(path);
// brepFeature should implement CATIMfBRep.
}

选择建议:

只需要知道用户选了哪个 feature,不要 featurize。
需要把 face/edge 等拓扑输入作为稳定机械引用保存,再考虑 featurize。

5. 装配上下文和 SetActiveObjectPath

CATFeatureAgent 在 Product 装配上下文中最容易让人误会。

默认行为下,当当前文档是 Product 时,CATFeatureAgent 禁止用户选择当前 component 外部的几何。这里的“当前 component”默认来自当前 UI active object,也可以用 SetActiveObjectPath 改成命令指定的路径:

_featureAgent->SetActiveObjectPath(targetPartPath);

默认行为下,这表示:

只允许用户在 targetPartPath 对应的 Part 文档中选择。

如果设置了 CATFAgAllowSelectionInContext

_featureAgent->SetAgentBehavior(
  MfNoFeaturization,
  NULL_var,
  CATFAgAllowSelectionInContext);

此时含义就变了:

允许用户在装配上下文中选择其它 component 的几何。
SetActiveObjectPath 不再起“限制选择范围”的作用。

可以用 ElementInContext 判断选择是否发生在当前 Part 外部:

CATPathElement *path = _featureAgent->GetValue();
int inContext = _featureAgent->ElementInContext(path);

if (0 == inContext)
{
// Selected element is in the current Part.
}
elseif (1 == inContext)
{
// Selected element is in another Part.
}

这个判断只告诉你“选在哪里”,不等于已经建立外部引用。如果要把外部 Part 的几何保存为当前 Part 的引用,应该看 CATFeatureImportAgent

6. CATFeatureImportAgent 解决什么问题

CATFeatureImportAgent 继承自 CATFeatureAgent,但它的关键词不是“选择”,而是“导入”。

在 Product 环境中,用户可能需要在另一个 Part 上选择几何,然后当前命令把这个几何作为目标 Part 的输入。普通 CATFeatureAgent 即使允许外部选择,也只是让你拿到选择路径;它不负责把外部对象变成目标 Part 里的 External Reference。

CATFeatureImportAgent 会做这件事:

用户在其它 Part 中选择几何
  -> agent 把选择导入 SetActiveObjectPath 指定的目标 Part
  -> 导入对象聚合到目标 Part 的 External References feature 下
  -> GetValue 返回导入后对象的路径

构造函数如下:

CATFeatureImportAgent(
const CATString&          iId,
  CATClassId                iType       = NULL,
  CATDlgEngBehavior         iBehavior   = NULL,
  CATMfFeaturizeMode        iMode       = NULL,
const CATBaseUnknown_var& iSupport    = NULL_var,
  CATImportAgentBehavior    iAgBehavior = NULL);

CATFeatureAgent 很像,但 iAgBehavior 类型换成了 CATImportAgentBehavior。最常用的 import 行为位是:

行为位 作用
CATFIAgCheckTypesAfterImport 在装配上下文中,导入完成后再按 AddElementType 或 SetOrderedTypeList 的接口类型检查导入结果

SetActiveObjectPath 对它的含义非常具体:

这个 path 指向要接收导入对象的 Part。

最小示意:

_importAgent = newCATFeatureImportAgent(
"ExternalSupportId",
  IID_CATIMfBRep,
  CATDlgEngWithPSOHSO | CATDlgEngWithPrevaluation,
  MfNoFeaturization);

_importAgent->SetActiveObjectPath(targetPartPath);

导入发生后:

CATPathElement *importedPath = _importAgent->GetValue();
CATBaseUnknown *importedObject = _importAgent->GetElementValue(importedPath);

如果需要追踪后续机械导入信息,可以设置 applicative id:

GUID importId = /* generated by uuidgen -s or application code */;
HRESULT hr = _importAgent->SetImportApplicativeId(importId);

文档里特别说明:这个 id 只在 Part Infrastructure 选项中启用 Keep link 时适用。后续可以通过 CATIMmiMechanicalImportApplicative 检索相关机械导入信息。

7. 典型场景怎么选

可以按下面几种场景直接套:

场景 选择
在当前 Part 中选择一个 sketch、body、plane 或 feature CATPathElementAgent 或 CATFeatureAgent,看是否需要机械上下文处理
在当前 Part 中选择 face/edge,并作为机械特征输入 CATFeatureAgent
在 Product 中只允许选当前编辑 Part 内部几何 CATFeatureAgent 默认行为 + SetActiveObjectPath
在 Product 中允许选其它 component,但只做临时参考 CATFeatureAgent + CATFAgAllowSelectionInContext
在 Product 中选其它 Part 几何,并保存为当前 Part 外部引用 CATFeatureImportAgent
在另一个已打开文档窗口中交互选择,但不负责导入 CATOtherDocumentAgent
只是选普通对象,不涉及机械 feature/BRep/装配上下文 CATPathElementAgent

这里最容易混的是 CATOtherDocumentAgentCATFeatureImportAgent

CATOtherDocumentAgent 解决“到其它已打开文档窗口里怎么点对象”。
CATFeatureImportAgent 解决“装配上下文中外部 Part 几何怎么导入当前 Part”。

它们不是替代关系。一个偏交互窗口代理,一个偏机械外部引用导入。

8. 最小 CATFeatureAgent 模板

下面是一个状态命令中选择机械对象的最小片段。真实项目中 IID_CATIExpectedInterface 应替换成你实际期望的接口。

头文件保存 agent 指针:

#include"CATStateCommand.h"

classCATFeatureAgent;

classMySelectFeatureCmd : public CATStateCommand
{
CmdDeclareResource(MySelectFeatureCmd, CATStateCommand);

public:
MySelectFeatureCmd();
virtual ~MySelectFeatureCmd();
virtualvoidBuildGraph();

private:
CATBoolean OnFeatureSelected(void *iData);

private:
  CATFeatureAgent *_featureAgent;
};

构造、析构和状态图:

#include"CATFeatureAgent.h"
#include"CATDialogState.h"
#include"CATDialogTransition.h"
#include"CATDlgEngUtility.h"
#include"CATMfBRepDefs.h"

MySelectFeatureCmd::MySelectFeatureCmd()
  : CATStateCommand("MySelectFeatureCmd"),
    _featureAgent(NULL)
{
}

MySelectFeatureCmd::~MySelectFeatureCmd()
{
if (NULL != _featureAgent)
  {
    _featureAgent->RequestDelayedDestruction();
    _featureAgent = NULL;
  }
}

voidMySelectFeatureCmd::BuildGraph()
{
  _featureAgent = newCATFeatureAgent(
"FeatureSelectionId",
    IID_CATIExpectedInterface,
    CATDlgEngWithPSOHSO | CATDlgEngWithPrevaluation | CATDlgEngRepeat,
    MfNoFeaturization);

  CATDialogState *stSelect = GetInitialState("SelectFeatureStateId");
  stSelect->AddDialogAgent(_featureAgent);

AddTransition(
    stSelect,
    stSelect,
IsOutputSetCondition(_featureAgent),
Action((ActionMethod)&MySelectFeatureCmd::OnFeatureSelected));
}

读取选择结果:

CATBoolean MySelectFeatureCmd::OnFeatureSelected(void *iData)
{
  CATPathElement *path = _featureAgent->GetValue();
if (NULL == path)
  {
return FALSE;
  }

  CATBaseUnknown *selected = _featureAgent->GetElementValue(path);
if (NULL == selected)
  {
return FALSE;
  }

int outsideCurrentPart = _featureAgent->ElementInContext(path);
  CATBoolean wasFeaturized = _featureAgent->FeaturizedElement(path);

// Query expected interfaces and store only what your feature really owns.

  _featureAgent->InitializeAcquisition();
return TRUE;
}

如果命令只想选择一次,把 transition 的目标状态改成 NULL 或后续状态;如果需要连续选择,则像上面一样回到同一状态,并在 action 末尾 InitializeAcquisition()

9. 最小 CATFeatureImportAgent 模板

下面的模板表示:命令在 Product/Part 机械上下文中运行,用户可以选择外部 Part 的几何,agent 把它导入 targetPartPath 指向的 Part。

#include"CATFeatureImportAgent.h"
#include"CATDialogState.h"
#include"CATDialogTransition.h"
#include"CATDlgEngUtility.h"
#include"CATMfBRepDefs.h"

voidMyImportSupportCmd::BuildGraph()
{
  _importAgent = newCATFeatureImportAgent(
"ExternalSupportSelectionId",
    IID_CATIExpectedInterface,
    CATDlgEngWithPSOHSO | CATDlgEngWithPrevaluation,
    MfNoFeaturization,
    NULL_var,
    CATFIAgCheckTypesAfterImport);

  _importAgent->SetActiveObjectPath(_targetPartPath);

  CATDialogState *stSelect = GetInitialState("SelectExternalSupportStateId");
  stSelect->AddDialogAgent(_importAgent);

AddTransition(
    stSelect,
NULL,
IsOutputSetCondition(_importAgent),
Action((ActionMethod)&MyImportSupportCmd::OnExternalSupportSelected));
}

读取导入后的路径:

CATBoolean MyImportSupportCmd::OnExternalSupportSelected(void *iData)
{
  CATPathElement *importedPath = _importAgent->GetValue();
if (NULL == importedPath)
  {
return FALSE;
  }

  CATBaseUnknown *importedObject = _importAgent->GetElementValue(importedPath);
if (NULL == importedObject)
  {
return FALSE;
  }

int createdCount = _importAgent->HowManyElementsCreated(importedPath);

// Store the imported object/path according to your feature model.
// The object is now in the target Part external references context.

return TRUE;
}

如果业务需要区分导入批次或后续追踪导入来源,可以在开始选择前设置 GUID:

GUID importId = /* generated once for this import operation */;
_importAgent->SetImportApplicativeId(importId);

注意这里的 _targetPartPath 必须是目标 Part 的路径,不是随便一个选择对象的路径。这个路径错了,导入对象就会进入错误的 Part 上下文。

如果导入结果还需要 BRep featurization,再把 MfNoFeaturization 换成合适的 MfxxxFeaturization 组合,并按 mode 要求传入 support。不要在还没想清楚生命周期和 support 的时候,把 featurization 放进最小模板里。

10. 程序化设置选择值

CATFeatureAgent 还提供了两个方法,可以把已有路径当成用户选择那样交给 agent 处理:

intSetValueToSelect(CATPathElement *iValue);
intSetListOfValuesToSelect(CATSO *iList);

这适合“命令启动时已有预输入”或“从其它逻辑转交选择结果”的场景。关键坑是:这两个方法只是设置待处理值,不会自动让 agent 进入 accepted valuation。

正确流程是:

if (1 == _featureAgent->SetValueToSelect(path))
{
  _featureAgent->SetValuation();
}

多选时才用 SetListOfValuesToSelect,并且 agent 行为要支持 CATDlgEngMultiAcquisition。否则应该使用 SetValueToSelect

11. 常见坑

1. 把 CATFeatureImportAgent 当成 CATFeatureAgent 的“升级版”

CATFeatureImportAgent 会导入外部对象,副作用比普通选择大得多。只是想在当前 Part 里选 face/edge,不要用它。

2. 允许外部选择后直接保存原对象指针

CATFAgAllowSelectionInContext 只表示允许用户在其它 component 上选对象,不表示外部引用已经建立。要持久化到当前 Part,考虑 CATFeatureImportAgent 或专门的 external reference 机制。

3. Featurization 打开后不管理 BRep feature 生命周期

featurized 对象不是普通临时指针。保留就要聚合到合适位置,删除就要用正确接口删除。最糟糕的写法是拿到指针、存一半、既不聚合也不删除。

4. SetActiveObjectPath 的含义混用

CATFeatureAgent,默认行为下它限制当前可选 component;对 CATFeatureImportAgent,它指定外部对象要导入的目标 Part。两者同名但语义不同。

5. 忘记导入后再检查类型

外部选择导入前后对象路径可能变化。对 CATFeatureImportAgent,如果业务依赖导入后的对象接口,建议使用 CATFIAgCheckTypesAfterImport,并在 action 中再次 QueryInterface

6. 多选仍然只读 GetValue()

启用 CATDlgEngMultiAcquisition 后,要用 GetListOfValues()GetElementValue(path) 适合逐个 path 处理,不要假设单选 API 会自动代表整个列表。

7. 忘记清空 agent 输出

重复采集时,如果 action 结束没有 InitializeAcquisition(),同一状态可能立刻再次满足 IsOutputSetCondition

8. 把 prevaluation 当最终选择

启用 CATDlgEngWithPrevaluation 后,agent 可能在预选阶段产生 prevalue。真正创建模型对象时,要确认 transition 是正式选择触发,而不是 hover 预选逻辑。

9. 忽略 Visu 到 Design 的切换成本

CATFeatureAgent 选择 Visu mode 文档元素时会自动转 Design mode。这很方便,但在大装配里可能带来明显性能和内存影响。

10. 只 include 头文件,忘记模块依赖

CATFeatureAgent.hCATFeatureImportAgent.h 位于 MechanicalModelerUI。使用 featurization mode 时还会接触 MecModInterfaces/PublicInterfaces/CATMfBRepDefs.h。Imakefile 里要确认相关模块依赖。

12. 推荐使用流程

写新命令时,可以按下面流程判断:

1. 用户是不是要选择机械模型里的 feature / face / edge / BRep?
   否 -> 先看 CATPathElementAgent
   是 -> 继续

2. 选择结果是否需要作为当前 Part 的外部引用保存?
   是 -> CATFeatureImportAgent
   否 -> CATFeatureAgent

3. 是否只是当前 Part 内部选择?
   是 -> CATFeatureAgent 默认行为即可
   否 -> 继续

4. 是否只是允许参考其它 component,不导入?
   是 -> CATFeatureAgent + CATFAgAllowSelectionInContext

5. 是否需要把外部 Part 几何导入目标 Part?
   是 -> CATFeatureImportAgent + SetActiveObjectPath(targetPartPath)

6. 是否需要稳定 BRep 引用?
   是 -> 选择合适 MfxxxFeaturization,并管理创建出的 BRep feature
   否 -> MfNoFeaturization

13. 总结

CATFeatureAgentCATFeatureImportAgent 都服务于机械建模选择,但边界要分清:

要做什么 用什么
普通对象选择 CATPathElementAgent
当前 Part 或机械上下文中的 feature/BRep 选择 CATFeatureAgent
Product 中允许选择其它 component,但不导入 CATFeatureAgent + CATFAgAllowSelectionInContext
选择其它 Part 几何并导入当前/目标 Part CATFeatureImportAgent
只是在其它已打开文档窗口中代理一次选择 CATOtherDocumentAgent

实际开发里建议保守一点:先用 MfNoFeaturization 把状态机和类型过滤跑通,确认业务确实需要稳定 BRep 引用时,再启用 featurization。外部几何也是一样:只是临时参考就不要导入;需要成为当前 Part 的持久输入,再使用 CATFeatureImportAgent

这两个 agent 的难点不在“怎么 new”,而在“选择结果属于哪个机械上下文,以及后续是否要被模型长期拥有”。只要这个问题想清楚,代码通常会自然很多。

评论