Implementing a Mechanical Design Feature Building-实现 CATIBuild 与 CATIBuildShape 接口
摘要
本文介绍 CAAPriUserPad 用例。该用例阐述如何为机械设计特征实现 CATIBuild 与 CATIBuildShape 接口。文中以一个简化的凸台特征作为机械特征示例。强烈建议读者先掌握机械建模器 [1] 相关知识。
- 本用例将教会您什么
- CAAPriBuildUserPad 用例
- CAAPriBuildUserPad 的功能
- 如何运行 CAAPriBuildUserPad
- CAAPriBuildUserPad 代码所在位置
- CATIBuild 接口实现分步讲解
- CATIBuildShape 接口实现分步讲解
- 小结
- 参考文献
通过本用例您将学习到
本用例旨在帮助您迈出零件设计模块编程的第一步,核心目标是讲解实现机械设计特征的 CATIBuild 与 CATIBuildShape 接口所需的重要概念。具体而言,您将学习如何:
- 创建与特征关联的拓扑体
- 记录相关操作
在学习本用例之前,请先阅读文章《在更新机制中集成新的几何特征》[2],该文详细阐述了如何实现 CATIBuild 与 CATIBuildShape 接口。
CAAPriBuildUserPad 用例
CAAPriBuildUserPad 是 CAAPartInterfaces.edu 框架下的一个用例,用于演示零件接口框架(PartInterfaces)与机械建模器框架(MechanicalModeler)的各项功能。
CAAPriBuildUserPad 的作用
CAAPriBuildUserPad 的目的是演示如何在一个指定的形状特征(即用户自定义凸台)上实现 CATIBuild 和 CATIBuildShape 接口。
该用户自定义凸台已作为 ** 启动对象(StartUp)** 存在于 CAAPriFormFeature 特征库中,类型为 CAAPriUserPad。它属于形状特征,换言之,CAAPriUserPad 启动对象继承自 MechanicalFormFeature 启动对象 [3]。启动对象(StartUp)的层级结构

CAAPriBuildUserPadMain.m 模块包含一个主程序,该程序会创建一个零件文档,实例化 CAAPriUserPad 启动对象,调用其 Build 方法并保存生成的零件文档(图 2);再使用一个新草图重新实例化 CAAPriUserPad 启动对象,调用其 Build 方法,并将生成的零件保存到第二个零件文档中(图 3)。
图 2 第一次保存的凸台特征

图 3 第二次保存的凸台特征

详细解析构建过程
构建一个特征的过程就是创建其结果,该结果包含两部分:
- 关联几何结果
由几何建模器框架中的对象计算得到的关联几何结果,其类型为 CATBody,是一种拓扑对象。 - 作用域(Scope)为保证用户凸台的生命周期,并使其能被其他机械特征重复使用,Build 方法会创建一个对象,用于管理 CATBody 中 CATCell 的访问稳定性。该对象即为作用域,由用户凸台的过程化报告创建而成 [4]。
下图详细说明了形状特征的构建流程。形状特征属于实体特征(与曲面特征相对),可看作特征链中的一个环节。这些环节通过 ResultIN 和 ResultOUT 属性相互串联:实体特征的 ResultIN 属性引用特征链中上一个特征的 ResultOUT 属性。关于 ResultIN 与 ResultOUT 属性的完整说明,请参阅文章《应用于机械特征的规格 / 结果机制》[5]。
图 4:形状特征的构建过程

BuildShape 与 Build 方法的作用详解
BuildShape 方法:创建一个作用域(Scope)和名为 Topo C 的 CATBody —— 该结果直接关联到形状特征本身(也就是本例中的用户自定义凸台)。
Build 方法:创建一个作用域(Scope)和名为 Topo B 的 CATBody —— 该结果关联到 SolidB 特征(这个特征被称为形状特征的结果特征)。
Topo B 是通过对 Topo C(当前凸台自身几何)与 **SolidA 特征关联的几何(Topo A)** 执行布尔逻辑运算计算得出的。SolidA 是特征链中当前特征之前的上一个形状特征。
运行 CAAPriBuildUserPad 的方法
运行 CAAPriBuildUserPad 前,需要先配置编译环境,编译该用例及其依赖项,再配置运行环境,最后执行用例 [6]。
运行命令
Windows 系统
e:>CAAPriBuildUserPadMain outputDirectory\CAAUserPad1.CATPart
outputDirectory\CAAUserPad2.CATPart
UNIX 系统
$ CAAPriBuildUserPadMain outputDirectory/CAAUserPad1.CATPart
outputDirectory/CAAUserPad2.CATPart
参数说明
- outputDirectory:文件保存目录,用于存储生成的两个 CATPart 文件
- CAAUserPad1.CATPart:保存初次创建的凸台特征
- CAAUserPad2.CATPart:保存修改后的凸台特征
CAAPriBuildUserPadMain 代码位置
CAAPriBuildUserPadMain 用例包含一个名为 CAAPriBuildUserPad 的主程序,位于 CAAPartInterfaces.edu 框架的 CAAPriBuildUserPadMain.m 模块中。
CATIBuild 与 CATIBuildShape 接口的实现代码位于同一框架下的 CAAPriBuildUserPad.m 模块中。
Windows 路径
InstallRootDirectory\CAAPartInterfaces.edu\CAAPriBuildUserPad.m\
InstallRootDirectory\CAAPartInterfaces.edu\CAAPriBuildUserPadMain.m\
Unix 路径
InstallRootDirectory/CAAPartInterfaces.edu/CAAPriBuildUserPad.m/
InstallRootDirectory/CAAPartInterfaces.edu/CAAPriBuildUserPadMain.m/
其中:InstallRootDirectory 为 CAA 光盘的安装目录。
CATIBuild 接口实现分步讲解
CATIBuild 接口通过一个名为 CAAPriEBuild 的类实现,该类是迟绑定类型 CAAPriUserPad 的代码扩展类。Build 是该接口唯一的方法,其结构固定如下:
...
HRESULT CAAPriEBuild::Build ()
{
HRESULT rc = E_FAIL ;
// 声明所需指针
Declaring the Useful Pointers
CATTry
{
// 计算特征形状
Computing the Form of the Feature
// 清除所有可能的更新错误
Removing all Possible Update Errors
// 为过程报告检索数据
Retrieving Data for the Procedural Report
// 创建过程报告
Creating the Procedural Report
// 运行拓扑算子
Running the Topological Operators
// 存储过程报告
Storing the Procedural Report
// 清理无用数据
Cleaning the Useless Data
}
// 错误处理
// 处理 CATMfErrUpdate 类型错误
CATCatch(CATMfErrUpdate , pUpdateError)
{
Managing the CATMfErrUpdate Error
}
// 处理通用 CATError 类型错误
CATCatch(CATError , pError)
{
Managing the CATError Error
}
CATEndTry
return rc ;
}
...
该方法包含 CATTry 与 CATCatch 代码块,因为部分方法可能会抛出异常错误 [7]
声明有用的指针
在 CATTry 代码块之前,需要声明所有指针:
- 在 CATTry 与 CATCatch 块中使用的指针:例如用户自定义凸台上的 CATIUpdateError 接口指针
piUpdateErrorOnThis。 - 在 CATTry 块中初始化,且在调用可能抛出异常的方法之前未释放的指针。
CATIUpdateError * piUpdateErrorOnThis = NULL;
CATIBuildShape * piBuildShape = NULL;
CATIMfProcReport * piProcReport = NULL;
CATGeoFactory * piGeomFactory = NULL;
CATDynBoolean * pOperatorBool = NULL;
CATSoftwareConfiguration * pSoftConfig = NULL ;
rc = QueryInterface( IID_CATIUpdateError , (void**) &piUpdateErrorOnThis);
if ( FAILED(rc) ) return rc ;
所有这些指针将在后续章节中详细说明。
计算特征的形状
在计算特征的最终结果之前,必须先计算出它的形状。这一步通过 BuildShape 方法来完成。
...
CATIBuildShape * piBuildShape = NULL;
rc = QueryInterface(IID_CATIBuildShape,(void**)&piBuildShape);
if ( SUCCEEDED(rc) )
{
int val = piBuildShape->BuildShape();
if ( 0 == val )
{
rc = E_FAIL ;
}
piBuildShape->Release();
piBuildShape = NULL ;
}
...
BuildShape 方法既可能抛出异常,也可能返回错误码。
清除所有可能的更新错误
更稳妥的做法是清除当前用户凸台特征可能关联的所有更新错误。为此,可使用 CATIUpdateError 接口中的 UnsetUpdateError 方法。有关该接口的详细说明,请参阅文章《更新错误说明》[8]。
...
rc = QueryInterface( IID_CATIUpdateError , (void**) &piUpdateErrorOnThis);
if ( SUCCEEDED(rc) )
{
piUpdateErrorOnThis->UnsetUpdateError();
}
...
用户凸台的 CATIUpdateError 接口实现,由迟绑定类型 MechanicalFeature 的扩展类提供。由于用户凸台的迟绑定类型继承自 MechanicalFeature 迟绑定类型(见图 1),因此可直接使用该接口实现。
获取过程报告所需数据
该步骤包含三个子步骤:
- 获取ResultIN特征
- 获取两个CATBody(ResultIN 的与当前特征的)
- 校验数据
获取 ResultIN 特征
...
// 获取当前特征上的 CATIShapeFeatureBody 接口指针
CATIShapeFeatureBody * pIShapeFeatureBodyOnThis = NULL ;
if ( SUCCEEDED(rc) )
{
rc = QueryInterface( IID_CATIShapeFeatureBody,(void**) &pIShapeFeatureBodyOnThis);
}
// 定义用于接收 ResultIN 特征的智能指针
CATISpecObject_var spResultIn ;
if ( SUCCEEDED(rc) )
{
// 获取所有输入体的属性列表
CATListValCATISpecAttribute_var *pListSpecAttribute = NULL ;
pListSpecAttribute = pIShapeFeatureBodyOnThis->GetBodyINAttributes();
if ( NULL != pListSpecAttribute )
{
// 取列表中第一个输入属性
CATISpecAttribute_var spSpecAttribute = (*pListSpecAttribute)[1];
if ( NULL_var != spSpecAttribute )
{
// 从属性中获取对应的规范对象(即 ResultIN 特征)
spResultIn = spSpecAttribute->GetSpecObject();
}
...
}
}
...
该形状特征实现了 CATIShapeFeatureBody(机械建模器框架)接口。通过该接口可以获取与特征关联的 ResultIN 属性。
该属性 spSpecAttribute 始终是 GetBodyINAttributes 方法返回列表中的第一个元素。
与通常做法一样,要获取该属性所引用的特征,需使用 CATISpecAttribute(对象规范建模器框架)接口的 GetSpecObject 方法。
spResultIn 将成为过程报告所使用的两个要素之一,另一个要素则是当前特征本身。
获取两个 CATBody(ResultIN 的与当前特征的)
第一个是与 ResultIN 特征关联的 CATBody。在图 4 中,它是名为 TopoA 的 CATBody。您始终可以使用 CATIShapeFeatureBody(机械建模器框架)接口来获取。
GetBodyIN 方法返回列表中的第一个元素,即为 ResultIN 特征的 CATBody,命名为 spCATBodyOnResultIn。
...
CATBody_var spCATBodyOnResultIn ;
if ( SUCCEEDED(rc) )
{
CATListValCATBaseUnknown_var *pListBodyIn = NULL ;
pListBodyIn = pIShapeFeatureBodyOnThis->GetBodyIN("CATBody");
if ( NULL != pListBodyIn )
{
spCATBodyOnResultIn = (*pListBodyIn)[1];
...
}
}
...
第二个是与当前特征关联的 CATBody,即由 BuildShape 方法计算出的形状。在图 4 中,它是名为 TopoC 的 CATBody。您始终可以使用 CATIShapeFeatureBody(机械建模器框架)接口来获取。GetShape 方法返回列表中的第一个元素,即为当前特征的 CATBody,命名为 spCATBodyOnThis。
...
// 定义当前特征的CATBody智能指针
CATBody_var spCATBodyOnThis ;
if ( SUCCEEDED(rc) )
{
// 获取形状体列表指针
CATListValCATBaseUnknown_var *pListBody = NULL ;
pListBody = pIShapeFeatureBodyOnThis->GetShape("CATBody");
if ( NULL != pListBody )
{
// 取列表第一个元素作为当前特征的CATBody
spCATBodyOnThis = (*pListBody)[1];
...
}
}
...
数据校验
如果ResultIN 特征不存在,但特征形状存在,说明该形状特征是特征链中的第一个特征,因此构建操作即可完成。
“创建过程报告”“运行拓扑算子” 和 “存储过程报告” 这些步骤将被跳过。
如果特征形状不存在,则视为错误,Build 方法将返回错误码 E_FAIL。
创建过程报告
过程报告是通过拓扑报告为后续单元生成名称,从而创建特征作用域的手段。过程报告由 CATIMfProcReport 接口管理。
首先要在构建操作期间,通过过程日志声明后续单元。对于形状特征,需要跟踪的规范对象始终是当前特征本身;如果 ResultIN 对应的实体存在,也需要一并包含 ResultIN。
...
CATLISTV(CATBaseUnknown_var) ListSpec;
CATListOfCATUnicodeString ListKeys;
ListSpec.Append( this );
ListKeys.Append( MfKeyNone );
if (NULL_var != spCATBodyOnResultIn)
{
ListSpec.Append( spResultIn);
ListKeys.Append( MfKeyNone );
}
...
- ListSpec:需要跟踪的规范对象列表
- ListKeys:与之关联的键值列表
两个列表长度保持一致。键值默认使用 MfKeyNone。若使用其他键值,表示需要用用户自定义信息替换节点的历史关系,键值必须与拓扑报告所提供的信息相匹配。
...
if ( SUCCEEDED(rc) )
{
rc = QueryInterface( IID_CATIMfProcReport , (void**) &piProcReport );
if ( SUCCEEDED(rc) )
{
int BoolOper = 1;
piProcReport->CreateProcReport(ListSpec,ListKeys,BoolOper);
}
}
...
获取到用户凸台上的 CATIMfProcReport 接口指针 piProcReport 后,便可通过 CreateProcReport 方法创建过程报告。
该方法的最后一个参数设为 1,这是因为计算结果(作用域)将关联到实体特征,而非用户凸台特征本身。在图 4 中,该实体特征名为 SolidB。
注意:piProcReport 是在 Build 方法开头声明的,以便能在 CATCatch 代码块中对其进行释放。
运行拓扑算子
该步骤包含三个固定的子步骤:
- 获取几何工厂接口指针,用于创建拓扑算子与拓扑结构;
- 获取过程报告所使用的拓扑日志;
- 创建几何对象并将其关联到当前特征。
获取几何工厂接口
几何工厂由 CATGeoFactory 接口管理。该接口由零件文档的几何容器实现 [9]。
通过在零件文档上实现的 CATIContainerOfDocument 接口,您可以获取此容器。CATILinkableObject 接口是每个特征用于获取其所属文档的通用方式。
...
// 如果此前操作成功
if ( SUCCEEDED(rc) )
{
// 定义可关联对象接口指针,用于获取特征所属文档
CATILinkableObject *piLinkableObjectOnUserPad= NULL;
rc = QueryInterface( IID_CATILinkableObject,
(void**)& piLinkableObjectOnUserPad);
if ( SUCCEEDED(rc) )
{
// 获取用户凸台特征所在的文档
CATDocument * pDocument = NULL ;
pDocument = piLinkableObjectOnUserPad->GetDocument();
if ( NULL != pDocument )
{
// 获取文档容器接口
CATIContainerOfDocument * pIContainerOfDocument = NULL ;
rc = pDocument->QueryInterface(IID_CATIContainerOfDocument,
(void**)& pIContainerOfDocument );
if ( SUCCEEDED(rc) )
{
// 获取结果容器(几何容器)
CATIContainer * pIContainerOnGeomContainer = NULL ;
rc = pIContainerOfDocument->GetResultContainer
(pIContainerOnGeomContainer);
if ( SUCCEEDED(rc) )
{
// 从几何容器查询得到几何工厂接口指针
rc = pIContainerOnGeomContainer->QueryInterface( IID_CATGeoFactory ,
(void**) &piGeomFactory );
...
}
...
GetResultContainer 是 CATIContainerOfDocument 接口中用于获取几何容器的方法。
piGeomFactory 是指向几何工厂接口的指针。
该指针在 Build 方法开头声明,以便可以在 CATCatch 块中对其进行释放。
获取拓扑日志
随后,过程报告会提供一个指向新拓扑日志的指针,该日志将记录所有拓扑操作。
...
CATTopData TopData ;
if ( SUCCEEDED(rc) )
{
CATCGMJournalList *pCGMJournalList = piProcReport->GetCGMJournalList();
TopData.SetJournal(pCGMJournalList) ;
pSoftConfig = new CATSoftwareConfiguration();
TopData.SetSoftwareConfiguration(pSoftConfig) ;
}
...
pCGMJournalList 是指向拓扑日志的指针。该指针禁止释放。
pSoftConfig 是在 Build 方法开头声明的指针,以便可以在 CATCatch 代码块中对其进行释放。
创建最终几何图形
本小节的目的是对
pResultBody 这个 CATBody 实例进行赋值。该指针是局部声明的,并没有在方法开头统一声明。这是可行的,因为它的生命周期由 CATCatch 块中的 DeletedProcReport 方法管理。
...
CATBody *pResultBody = NULL ;
....
...
需要考虑两种情况:
-
当前用户凸台并非特征集中的第一个实体特征如果
spCATBodyOnResultIn(与 ResultIN 特征关联的 CATBody 智能指针)不为空,说明该用户凸台存在上游输入 RESULTIN,因此它不是形体特征中的第一个实体特征。
if (NULL_var != spCATBodyOnResultIn)
{
CATDynBooleanType internalOperType = CATBoolUnion;
pOperatorBool = ::CATCreateDynBoolean(piGeomFactory,
&TopData,
internalOperType,
spCATBodyOnResultIn,
spCATBodyOnThis);
if ( NULL != pOperatorBool )
{
pOperatorBool->Run();
pResultBody = pOperatorBool->GetResult();
}
}
在用户凸台特征的形状(spCATBodyOnThis)与上一个特征的拓扑结果(spCATBodyOnResultIn)之间执行布尔运算。
作为 CATCreateDynBoolean 全局函数第二个参数传入的拓扑日志也会被同步更新。
pOperatorBool 是在 Build 方法开头声明的 CATDynBoolean 接口指针。
pResultBody 为运算后的拓扑结果,即图 4 中名为 TopoB 的 CATBody。
用户凸台是特征集中的第一个实体特征
与结果关联的实体是通过 CATIBuildShape 接口创建的实体。但由于一个拓扑结果只能关联至唯一的几何特征,因此需要创建一个新的 CATBody。
不过,虽然每个几何特征对应唯一的 CATBody,但不同 CATBody 之间可以共享单元(cell)。因此,最终的 CATBody 将使用由 CATIBuildShape 接口创建的实体中的单元(域)来创建。
...
pResultBody = piGeomFactory->CreateBody();
if ( NULL != pResultBody )
{
CATDomain *Domain = NULL;
int NbDomain = spCATBodyOnThis->GetNbDomains();
for (int i = 1; i <= NbDomain; i++)
{
Domain = spCATBodyOnThis->GetDomain(i);
pResultBody->AddDomain(Domain);
}
}
...
spCATBodyOnThis 是指向由 CATIBuildShape 接口创建的 CATBody 的智能指针。该指针的赋值操作已在 ** 获取两个 CATBody(ResultIN 与当前特征)** 小节中完成。
存储过程报告
现在正是存储(填充)与用户凸台几何结果创建相对应的过程报告的时机。这一工作由 CATIMfProcReport::StoreProcReport 方法完成。
...
if ( SUCCEEDED(rc) )
{
if ( NULL != pResultBody )
{
int BoolOper = 1 ;
piProcReport->StoreProcReport(pResultBody,Copy, BoolOper);
}
else
{
CATMfErrUpdate *pErrorNoIntersection = new CATMfErrUpdate();
CATUnicodeString Diagnostic("Error during boolean operation.");
pErrorNoIntersection->SetDiagnostic(1,Diagnostic);
CATThrow(pErrorNoIntersection);
}
}
}
...
StoreProcReport 方法的最后一个参数 BoolOper,其取值与 CreateProcReport 方法中的该参数保持一致。
清理无用数据
在 CATTry 代码块的最后部分,需要清理在第一部分 “声明所需指针” 中定义、但在 CATTry 块内未被释放 / 删除的数据。例如,
piBuildShape 指针不在此处释放:如果 BuildShape 方法未抛出异常,该指针会在调用完 BuildShape 后立即释放,详见 “计算特征形状” 小节。通常需要处理以下内容:
- 所有需从拓扑容器中移除的对象,可通过 CATGeoFactory 接口的 Remove 方法实现(本示例中无相关操作)。
- 所有尚未删除的对象:
pOperatorBool(拓扑算子)。 - 所有尚未释放的指针(通常包含以下四个指针):
piUpdateErrorOnThispiProcReportpSoftConfigpiGeomFactory
错误处理
在前面的操作过程中可能会抛出一些异常,CATTry 代码块会捕获这些异常,CATCatch 代码块则负责处理异常。
错误主要分为两类:
- CATMfErrUpdate
- CATError
每个 CATCatch 代码块都会处理错误,并清理在 Build 方法开头声明的所有指针。
处理 CATMfErrUpdate 类型错误
最高层级的错误类型为 CATMfErrUpdate。这类错误会原样重新抛出,不做任何修改。
...
CATCatch ( CATMfErrUpdate , pUpdateError)
{
if(NULL != piUpdateErrorOnThis)
{
piUpdateErrorOnThis->SetUpdateError(pUpdateError);
piUpdateErrorOnThis->Release();
piUpdateErrorOnThis = NULL ;
}
// 此处清理在 Build 方法开头声明的指针
CATRethrow ;
}
...
处理 CATError 类型错误
所有其他类型的错误均继承自 CATError。以下代码用于关联诊断信息与错误对象。
...
CATCatch ( CATError , pError)
{
CATMfErrUpdate *pErrorToThrow = new CATMfErrUpdate();
pErrorToThrow->SetDiagnostic(1,pError->GetNLSMessage());
::Flush(pError);
if(NULL != piUpdateErrorOnThis)
{
piUpdateErrorOnThis->SetUpdateError(pErrorToThrow);
piUpdateErrorOnThis->Release();
piUpdateErrorOnThis = NULL ;
}
// 此处清理在 Build 方法开头声明的指针
CATThrow(pErrorToThrow);
}
...
创建一个新的 CATMfErrUpdate 对象。作为 CATError 类型的 pError,必须在错误处理过程中被释放。全局函数 Flush 用于完成该释放操作。
清理指针
在两个 CATCatch 代码块中,必须完成以下操作:
- 删除结果:即与特征及其作用域关联的新建 CATBody。该操作通过 DeleteProcReport 方法实现。
对于在第一部分 “声明所需指针” 中定义的变量,还需执行:
- 通过 CATGeoFactory 接口的 Remove 方法,从拓扑容器中移除相关对象(本示例中无需执行此操作)。
- 删除拓扑算子:
pOperatorBool - 释放所有在 CATTry 块中未释放的指针。对于一个形状特征,通常至少包含以下五个指针:
piUpdateErrorOnThispiProcReportpSoftConfigpiGeomFactorypiBuildShape
CATIBuildShape 接口分步实现
CATIBuildShape 接口通过名为 CAAPriEBuildShape 的类实现,该类是迟绑定类型 CAAPriUserPad 的数据扩展类。BuildShape 是此接口唯一的方法,其结构固定如下:
...
int CAAPriEBuildShape::BuildShape ()
{
int rcode = 1 ; // 正常
HRESULT rc = E_FAIL;
// 声明所需指针
CATTry
{
// 清除所有可能存在的更新错误
// 为过程报告获取数据
// 创建过程报告
// 运行拓扑算子
// 存储过程报告
// 清理无用数据
}
// 错误处理
CATCatch(CATMfErrUpdate , pUpdateError)
{
// 处理 CATMfErrUpdate 类型错误
}
CATCatch(CATError , pError)
{
// 处理 CATError 类型错误
}
CATEndTry
if ( FAILED(rc) )
{
rcode = 0 ;
}
return rcode ;
}
...
该方法包含 CATTry 和 CATCatch 代码块,因为部分方法在执行时可能会抛出异常 [7]。
声明所需指针
在 CATTry 代码块之前,需要声明所有指针:
- 在 CATTry 与 CATCatch 块中均会使用的指针,例如用户凸台上 CATIUpdateError 接口的指针
piUpdateErrorOnThis。 - 在 CATTry 块中初始化,且在调用可能抛出异常的方法之前未被释放的指针。
...
CATIUpdateError * piUpdateErrorOnThis = NULL;
CATTopPrism * pOperatorPrism = NULL;
CATIPrtProfile * pPrtProfile = NULL;
CATIMfProcReport * piProcReport = NULL;
CATGeoFactory * piGeomFactory = NULL;
CATSoftwareConfiguration * pSoftConfig = NULL ;
CATBody_var spBodyOnProfile ;
...
所有这些指针将在后续章节中详细说明。
清除所有可能的更新错误
清除当前用户凸台特征上可能存在的所有更新错误,会使程序更安全。为此,可使用 CATIUpdateError 接口中的 UnsetUpdateError 方法。
...
rc = QueryInterface( IID_CATIUpdateError , (void**) &piUpdateErrorOnThis);
if ( SUCCEEDED(rc) )
{
piUpdateErrorOnThis->UnsetUpdateError();
}
...
获取过程报告所需数据
该步骤包含三个子步骤,分别是:
- 获取轮廓
- 获取并检查与轮廓关联的 CATBody
获取轮廓
轮廓是用户凸台(UserPad)特征的一个属性,通过字符串 “Profile” 进行引用。
...
CATMathDirection ExtrusionDirection ;
CATISpecObject_var spSpecObjectOnProfileElt;
if ( SUCCEEDED(rc) )
{
CATISpecObject * pSpecObjectOnThis = NULL;
rc = QueryInterface( IID_CATISpecObject , (void**) &pSpecObjectOnThis );
if ( SUCCEEDED(rc) )
{
CATUnicodeString strProfile = "Profile";
CATISpecAttribute * pProfileAtt = NULL ;
pProfileAtt = pSpecObjectOnThis->GetAttribute(strProfile);
pSpecObjectOnThis->Release();
pSpecObjectOnThis = NULL ;
if ( NULL != pProfileAtt )
{
CATISpecObject * pSpecObjectOnProfileAtt = NULL;
pSpecObjectOnProfileAtt = pProfileAtt->GetSpecObject();
...
pProfileAtt 是用户凸台的 “轮廓” 属性。pSpecObjectOnProfileAtt 是与该属性关联的特征。通过对 pSpecObjectOnProfileAtt 查询 CATIPrtProfile 接口,可以获取拉伸方向 ExtrusionDirection 以及轮廓本身 spSpecObjectOnProfileElt。
...
if ( NULL != pSpecObjectOnProfileAtt )
{
rc = pSpecObjectOnProfileAtt->QueryInterface( IID_CATIPrtProfile ,
(void**) &pPrtProfile );
pSpecObjectOnProfileAtt->Release();
pSpecObjectOnProfileAtt = NULL ;
if ( SUCCEEDED(rc) )
{
CATMathPlane SketchPlane ;
rc = pPrtProfile->GetPlane(SketchPlane) ;
if ( SUCCEEDED(rc) )
{
CATMathVector normalDir;
SketchPlane.GetNormal(normalDir);
ExtrusionDirection = normalDir ;
if ( SUCCEEDED(rc) )
{
pPrtProfile->GetElement(1,spSpecObjectOnProfileElt) ;
...
拉伸凸台的方向(拉伸方向
ExtrusionDirection)已定义为草图平面的法向。通过 CATIPrtProfile 接口的 GetElement 方法获取的轮廓 spSpecObjectOnProfileElt,将作为过程报告所跟踪的特征。完整来说,如果
spSpecObjectOnProfileElt、pSpecObjectOnProfileAtt 或 pProfileAtt 为 NULL 或 NULL_var,则按如下方式抛出更新错误 [8]:...
CATMfErrUpdate *pError = new CATMfErrUpdate();
CATUnicodeString Diagnostic("xxxxx");
pError->SetDiagnostic(1,Diagnostic);
CATThrow(pError);
...
在这种情况下,CATTry代码块会被中断。
获取并检查与轮廓关联的 CATBody
pPrtProfile 是指向用户凸台(User Pad)的轮廓(Profile)属性所引用特征的 CATIPrtProfile 接口指针。本部分的作用是计算构成待拉伸轮廓的 CATBody,即 spBodyOnProfile。但在此之前,需要先执行若干检查以验证轮廓的有效性。
...
if ( SUCCEEDED(rc) )
{
int nbContour = pPrtProfile->GetContourCount();
if (nbContour == 1)
{
CATBody_var LocalBody ;
pPrtProfile->GetBody(0,LocalBody);
CATDomain * pDomain = LocalBody->GetDomain(1);
CATWire_var spWireOnDomain(pDomain);
if (spWireOnDomain != NULL_var)
{
CATBoolean isClosed = spWireOnDomain->IsClosed();
if(TRUE != isClosed)
{
CATMfErrUpdate *pErrorNotClosedProfile = new CATMfErrUpdate();
CATUnicodeString Diagnostic("关联的轮廓未闭合");
pErrorNotClosedProfile->SetDiagnostic(1,Diagnostic);
CATThrow(pErrorNotClosedProfile);
}
...
如果轮廓存在错误,将会生成并抛出
pErrorNotClosedProfile 错误,以中断整个流程。轮廓通过有效性验证后,通过
CATIPrtProfile 接口的 GetBody 方法计算得到 spBodyOnProfile。该 CATBody 应在方法执行结束时从拓扑容器中移除。
...
pPrtProfile->GetBody(1,spBodyOnProfile);
if ( NULL_var == spBodyOnProfile )
{
CATMfErrUpdate *pErrorNoProfileToExtrude = new CATMfErrUpdate();
CATUnicodeString Diagnostic("无待拉伸元素");
pErrorNoProfileToExtrude->SetDiagnostic(1,Diagnostic);
CATThrow(pErrorNoProfileToExtrude);
...
创建过程报告
过程报告是借助拓扑报告生成后续几何单元名称,进而生成特征作用域的一种方式。过程报告由 CATIMfProcReport 接口管理。首先需要在构建操作期间,通过过程日志声明后续几何单元。
...
CATLISTV(CATBaseUnknown_var) ListSpec;
CATListOfCATUnicodeString ListKeys;
if ( SUCCEEDED(rc) )
{
ListSpec.Append( spSpecObjectOnProfileElt );
ListKeys.Append( MfKeyExtrudedFrom );
}
...
ListSpec 为要跟踪的规范列表,ListKeys 为对应的关键字列表。此处仅有一个规范对象,即轮廓 spSpecObjectOnProfileElt,其关联关键字设为 MfKeyExtrudedFrom。
...
if ( SUCCEEDED(rc) )
{
rc = QueryInterface( IID_CATIMfProcReport , (void**) &piProcReport );
if ( SUCCEEDED(rc) )
{
int BoolOper = 0;
piProcReport->CreateProcReport(ListSpec,ListKeys,BoolOper);
}
}
...
获取到用户凸台的 CATIMfProcReport 接口指针 piProcReport 后,即可通过 CreateProcReport 方法创建过程报告。该方法最后一个参数为默认值 0,表示运算结果(作用域)将直接赋予当前特征本身【见图 1】。
注意:piProcReport 在 Build 方法开头声明,以便在 CATCatch 块中进行释放。
运行拓扑算子
该步骤包含三个固定的子步骤:
- 获取几何工厂接口指针,用于创建拓扑算子与拓扑结构;
- 获取过程报告所使用的拓扑日志;
- 创建需与特征关联的几何图形。
获取几何工厂
详见实现 Build 方法中的 “获取几何工厂接口” 小节。
获取拓扑日志
详见实现 Build 方法中的 “获取拓扑日志” 小节。
创建拉伸体算子
使用以下参数创建拉伸体(Prism)算子:
- piGeomFactory:几何工厂,详见 “获取几何工厂接口” 小节
- TopData:拓扑日志,详见 “获取拓扑日志” 小节
- spBodyOnProfile:待拉伸的轮廓,详见 “获取并检查与轮廓关联的 CATBody” 小节
- ExtrusionDirection:凸台拉伸方向,详见 “获取轮廓” 小节
- startOffset:第一边界的偏移值,设为 0,表示凸台从草图平面开始
- endOffset:最终边界的偏移值
...
CATBody *pResultBody = NULL ;
if ( SUCCEEDED(rc) )
{
CATLength endOffset = 30.;
CATLength startOffset = 0.;
pOperatorPrism = CATCreateTopPrism(piGeomFactory,
&TopData,
spBodyOnProfile,
&ExtrusionDirection,
startOffset,
endOffset);
...
凸台操作会生成一个正向实体(凹槽操作则为负向实体),使用 CATBoolUnion 参数来标识该操作类型。通过调用两次 SetLimit 方法,可以分别定义拉伸的起始边界与终止边界。
if ( NULL != pOperatorPrism )
{
// 设置布尔运算类型为合并
pOperatorPrism->SetOperation(CatBoolUnion);
CATTopLimitType startLimitType = CatLimOffsetFromProfile;
CATTopPropagationType startPropagType = CatPropagSingle;
// 为算子定义第一边界(起始边界)
pOperatorPrism->SetLimit(CatLimStart,
startLimitType,
1,
startOffset,
NULL,
CATBody_var(NULL_var),
startPropagType,
FALSE);
// 为算子定义第二边界(终止边界)
CATTopLimitType endLimitType = CatLimOffsetFromProfile;
CATTopPropagationType endPropagType = CatPropagSingle;
pOperatorPrism->SetLimit(CatLimEnd,
endLimitType,
0,
endOffset,
NULL,
CATBody_var(NULL_var),
endPropagType,
FALSE);
// 执行拉伸运算
pOperatorPrism->Run();
// 获取运算生成的实体
pResultBody = pOperatorPrism->GetResult();
...
pResultBody 是图【图 1】中名为 TopoC 的 CATBody,它与用户凸台的形状相关联。注意:pResultBody 并未在方法开头声明。由于它的生命周期由 CATCatch 块中的 DeleteProcReport 方法管理,因此无需在方法开头声明。
存储过程报告
现在需要存储(填充)与用户凸台几何结果创建相对应的过程报告。该工作由 CATIMfProcReport::StoreProcReport 方法完成。
...
if ( SUCCEEDED(rc) )
{
if ( NULL != pResultBody )
{
int BoolOper = 0 ;
piProcReport->StoreProcReport(pResultBody,NoCopy,BoolOper);
}
else
{
CATMfErrUpdate *pErrorBuildShape = new CATMfErrUpdate();
CATUnicodeString Diagnostic("执行 BuildShape 操作时出错");
pErrorBuildShape->SetDiagnostic(1,Diagnostic);
CATThrow(pErrorBuildShape);
}
}
...
StoreProcReport 方法的最后一个参数 BoolOper,其取值与 CreateProcReport 方法中的该参数保持一致。
清理无用数据
在 CATTry 代码块的最后部分,需要清理在第一部分 “声明有效指针” 中定义、但在 CATTry 块执行期间未被释放或删除的数据。例如,
pPrtProfile 指针无需在此处释放,因为它已在 CATTry 块中被安全释放(本文未描述,可参考对应代码)。- 所有需从拓扑容器中移除的对象:此处仅有
spBodyOnProfile - 所有尚未删除的对象:此处仅有拓扑算子
pOperatorPrism - 所有尚未释放的指针:
piUpdateErrorOnThispiProcReportpSoftConfigpiGeomFactory
错误处理
本部分内容与 Build 方法中的 “错误处理” 部分完全一致。仅根据方法执行过程中使用的数据不同,“清理无用数据” 环节存在差异。
在 BuildShape 方法的两个 CATCatch 代码块中,必须完成以下操作:
- 移除结果对象:即与特征及其作用域相关联的新建 CATBody。该操作通过
DeleteProcReport方法实现,详见 Build 方法中的 “处理 CATMfErrUpdate 类型错误” 部分。
对于在第一部分 “声明有效指针” 中定义的数据,还需执行:
- 从拓扑容器中移除无用的 CATBody:
spBodyOnProfile - 删除拓扑算子:
pOperatorPrism - 释放所有在 CATTry 块中未释放的指针:
piUpdateErrorOnThispiProcReportpSoftConfigpiGeomFactorypPrtProfile
简要总结
本示例演示了形状特征构建过程的管理实现方法。
希望和大家一起交流学习

浙公网安备 33010602011771号