Implementing a Mechanical Design Feature Building-实现 CATIBuild 与 CATIBuildShape 接口

摘要

本文介绍 CAAPriUserPad 用例。该用例阐述如何为机械设计特征实现 CATIBuildCATIBuildShape 接口。文中以一个简化的凸台特征作为机械特征示例。强烈建议读者先掌握机械建模器 [1] 相关知识。
  • 本用例将教会您什么
  • CAAPriBuildUserPad 用例
    • CAAPriBuildUserPad 的功能
    • 如何运行 CAAPriBuildUserPad
    • CAAPriBuildUserPad 代码所在位置
  • CATIBuild 接口实现分步讲解
  • CATIBuildShape 接口实现分步讲解
  • 小结
  • 参考文献

通过本用例您将学习到

本用例旨在帮助您迈出零件设计模块编程的第一步,核心目标是讲解实现机械设计特征的 CATIBuildCATIBuildShape 接口所需的重要概念。具体而言,您将学习如何:
  • 创建与特征关联的拓扑体
  • 记录相关操作

在学习本用例之前,请先阅读文章《在更新机制中集成新的几何特征》[2],该文详细阐述了如何实现 CATIBuild 与 CATIBuildShape 接口。

CAAPriBuildUserPad 用例

CAAPriBuildUserPad 是 CAAPartInterfaces.edu 框架下的一个用例,用于演示零件接口框架(PartInterfaces)与机械建模器框架(MechanicalModeler)的各项功能。

CAAPriBuildUserPad 的作用

CAAPriBuildUserPad 的目的是演示如何在一个指定的形状特征(即用户自定义凸台)上实现 CATIBuildCATIBuildShape 接口。
该用户自定义凸台已作为 ** 启动对象(StartUp)** 存在于 CAAPriFormFeature 特征库中,类型为 CAAPriUserPad。它属于形状特征,换言之,CAAPriUserPad 启动对象继承自 MechanicalFormFeature 启动对象 [3]。
启动对象(StartUp)的层级结构

图片

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

图 2 第一次保存的凸台特征

图片

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

图片

 

详细解析构建过程

构建一个特征的过程就是创建其结果,该结果包含两部分:
  1. 关联几何结果
    由几何建模器框架中的对象计算得到的关联几何结果,其类型为 CATBody,是一种拓扑对象。
  2. 作用域(Scope)为保证用户凸台的生命周期,并使其能被其他机械特征重复使用,Build 方法会创建一个对象,用于管理 CATBody 中 CATCell 的访问稳定性。该对象即为作用域,由用户凸台的过程化报告创建而成 [4]。
下图详细说明了形状特征的构建流程。形状特征属于实体特征(与曲面特征相对),可看作特征链中的一个环节。这些环节通过 ResultINResultOUT 属性相互串联:实体特征的 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 代码块中对其进行释放。

运行拓扑算子

该步骤包含三个固定的子步骤:
  1. 获取几何工厂接口指针,用于创建拓扑算子与拓扑结构;
  2. 获取过程报告所使用的拓扑日志;
  3. 创建几何对象并将其关联到当前特征。

获取几何工厂接口

几何工厂由 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 );
                      ...
       }
...
GetResultContainerCATIContainerOfDocument 接口中用于获取几何容器的方法。
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(拓扑算子)。
  • 所有尚未释放的指针(通常包含以下四个指针):
    • piUpdateErrorOnThis
    • piProcReport
    • pSoftConfig
    • piGeomFactory

错误处理

在前面的操作过程中可能会抛出一些异常,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 块中未释放的指针。对于一个形状特征,通常至少包含以下五个指针:
    • piUpdateErrorOnThis
    • piProcReport
    • pSoftConfig
    • piGeomFactory
    • piBuildShape

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 ;
}
...

该方法包含 CATTryCATCatch 代码块,因为部分方法在执行时可能会抛出异常 [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();
       }
...

获取过程报告所需数据

该步骤包含三个子步骤,分别是:
  1. 获取轮廓
  2. 获取并检查与轮廓关联的 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,将作为过程报告所跟踪的特征。
完整来说,如果 spSpecObjectOnProfileEltpSpecObjectOnProfileAttpProfileAttNULLNULL_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 块中进行释放。

运行拓扑算子

该步骤包含三个固定的子步骤:
  1. 获取几何工厂接口指针,用于创建拓扑算子与拓扑结构;
  2. 获取过程报告所使用的拓扑日志;
  3. 创建需与特征关联的几何图形。

获取几何工厂

详见实现 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
  • 所有尚未释放的指针:
    • piUpdateErrorOnThis
    • piProcReport
    • pSoftConfig
    • piGeomFactory

错误处理

本部分内容与 Build 方法中的 “错误处理” 部分完全一致。仅根据方法执行过程中使用的数据不同,“清理无用数据” 环节存在差异。
在 BuildShape 方法的两个 CATCatch 代码块中,必须完成以下操作:
  • 移除结果对象:即与特征及其作用域相关联的新建 CATBody。该操作通过 DeleteProcReport 方法实现,详见 Build 方法中的 “处理 CATMfErrUpdate 类型错误” 部分。
对于在第一部分 “声明有效指针” 中定义的数据,还需执行:
  • 从拓扑容器中移除无用的 CATBody:spBodyOnProfile
  • 删除拓扑算子:pOperatorPrism
  • 释放所有在 CATTry 块中未释放的指针:
    • piUpdateErrorOnThis
    • piProcReport
    • pSoftConfig
    • piGeomFactory
    • pPrtProfile

简要总结

本示例演示了形状特征构建过程的管理实现方法。
 
 
 
posted @ 2026-04-02 13:38  Breadss  阅读(5)  评论(0)    收藏  举报