Mechanical Modeler

Building Combined Curves

Implementing CATIBuild
Use Case
Creating a New Geometrical Feature : The Combined Curve > Building Combined Curves

Abstract

This article explains how to build the result of the combined curve.


What You Will Learn With This Use Case

This use case demonstrates how to build the result of a geometrical feature which is a wireframe feature. The build is done by the update mechanism through the CATIBuild interface. The article entitled "Integrating a New Geometrical Feature in the Update Mechanism" [1] explains in details this interface and how to implement it. 

From V5R15, the use case has been enriched to build or not the result, a choice managed by the CATIMechanicalProperties interface [8].

[Top]

The CAAMmrCombinedCurve Use Case

CAAMmrCombinedCurve is a use case of the CAAMechanicalModeler.edu framework that illustrates Mechanical Modeler frameworks capabilities.

[Top]

What Does the CAAMmrCombinedCurve Use Case Do

This article explains how the Combined Curves implements the CATIBuild interface. This interface is called whenever someone wants to update an object. The Build method, the unique method of this interface produces:

The following picture explains the process of the Build method in the case of a surfacic (wireframe) feature:

Fig.1: Surfacic Feature Build
 

All the inputs specifications of the feature will be followed by the procedural report. The CATIMechanicalImport interface will be used to check if the result must be built of not.

The final part of the Use Case describes how to manage any potential error that may occur during the Combined Curve building .

[Top]

How to Launch CAAMmrCombinedCurve

See the section entitled "How to Launch the Combined Curve Use Case" in the "Creating a New Geometrical Feature: The Combined Curve" use case for a detailed description of how this use case should be launched. 

Launch CATIA, when the application is ready, follow the scenario described below:

The following picture shows the CAACombinedCurve.CATPart, on left when the result of the combined curve is computed, and on right otherwise.

 

On right note that the icon of the combined curve shows that the geometrical feature is deactivated:

(*) The file is located in the directory CAAMechanicalModeler.edu/InputData

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Where to Find the CAAMmrCombinedCurve Code

The CAAMmrCombinedCurve use case is made one class,CAAEMmrCombinedCurveBuild, located in the CAAMmrCombinedCurve.m module of the CAAMechanicalModeler.edu framework:

Windows InstallRootDirectory\CAAMechanicalModeler.edu\CAAMmrCombinedCurve.m\
Unix InstallRootDirectory/CAAMechanicalModeler.edu/CAAMmrCombinedCurve.m/

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Step-by-Step

By implementing the CATIBuild interface, you will define how a Combined Curve is build, i.e. how to compute the two extruded surfaces and their intersection, and how to integrate these operations in the procedural journal. This interface contains one method, the Build method, whose the contents is the following:

...
HRESULT CAAEMmrCombinedCurveBuild::Build ()
{
   HRESULT rc = E_FAIL ;
   
   Declaring the Useful Pointers
   
   CATTry
   {
      Checking the build activation
      if ( DeactivateState == 0 )
      {
         Removing all Possible Update Errors Associated with the Combined Curve
         Retrieving Data for the Procedural Report
         Creating the Procedural Report
         Running the Topological Operators 
         Storing the Procedural Report and the Algorithm Configuration
         Cleaning the Useless Data
      }
   }
   
   // Managing the Errors
   
   CATCatch(CATMfErrUpdate , pUpdateError)  
   {
      Managing the CATMfErrUpdate Error
   }
   CATCatch(CATError , pError)
   {
      Managing the CATError Error
   }
   
   CATEndTry
   
   return rc ;
}
...

This method contains a CATTry and CATCatch sections because some methods can throw an error. [3]

At last, the Implementing the CATIBuild Interface section describes how to create the new data extension for the Combined Curve feature.

[Top]

Declaring the Useful Pointers

Before the CATTry section you declare all the pointers:

...
    CATIUpdateError          * piUpdateErrorOnThis        = NULL;

    CATTopPrism              * pCurve1Extrude             = NULL;
    CATTopPrism              * pCurve2Extrude             = NULL;
    CATHybOperator           * pIntersect                 = NULL;

    CATBody                  * pCurve1ExtrudeBody         = NULL ;
    CATBody                  * pCurve2ExtrudeBody         = NULL ;

    CATIMfProcReport         * piProcReport               = NULL;
    CATGeoFactory            * piGeomFactory              = NULL;
    CATSoftwareConfiguration * pSoftConfig                = NULL;
    int                      IsConfigToStore              = NULL;
...

All this pointers will be explained in the next sections.

[Top]

Checking the Build Activation

This part consists in to check the status of the combined curve in term of build's activation. This information is managed by the CATIMechanicalProperties interface [8].

...
  int DeactivateState = 0 ;
  CATIMechanicalProperties *pMechProp = NULL ;
  rc = QueryInterface(IID_CATIMechanicalProperties,(void **) & pMechProp);

  DeactivateState = pMechProp->IsInactive();

  if ( 1 == DeactivateState )
  {
     QueryInterface(IID_CATIMfProcReport,(void**) &piProcReport );

     rc = piProcReport->InactivateResult();
     piProcReport->Release();
     piProcReport = NULL ;

...

If the geometrical feature is deactivated, the InactivateResult method of the CATIMfProcReport interface must be used. This interface, CATIMfProcReport, is natively implemented by a geometrical feature. 

Once the procedural report is deactivated, you can leave the CATTry section. But before you must release piProcReport, the CATIMfProcReport interface pointer. It is the only one pointer declared in the Declaring the Useful Pointers section, and valuated in this section.

This check about the deactivation must be done in the CATTry section because the InactivateResult method of the CATIMfProcReport can through an error. In this case, piProcReport will be released in the CATCatch section.

[Top]

Removing all Possible Update Errors Associated with the Combined Curve

It is safer to remove all possible update error that may be associated with the current Combined Curve feature. To do so, use the UnsetUpdateError of the CATIUpdateError interface.

...
       rc = QueryInterface( IID_CATIUpdateError , (void**) &piUpdateErrorOnThis);
       if ( SUCCEEDED(rc) )
       {
          piUpdateErrorOnThis->UnsetUpdateError();
       }
...

The implementation of CATIUpdateError interface for Combined Curve is provided by an extension of late type MechanicalFeature. Since CombinedCurve late type derives from MechanicalFeature late type [4], you automatically benefit from this implementation.

[Top]

Retrieving the Data for the Procedural Report

This step consists in three sub-steps which are :

Retrieving the two Input Curves and the two Input Directions

With the CAAIMmrCombinedCurve interface [5] it is easy to retrieve the Combined Curve input curves and directions.

...
       CATISpecObject    *piSpecOnCurve1     = NULL;
       CATISpecObject    *piSpecOnCurve2     = NULL;
       CATISpecObject    *piSpecOnDirection1 = NULL; 
       CATISpecObject    *piSpecOnDirection2 = NULL; 

       CAAIMmrCombinedCurve *piCombinedCurve = NULL;
       rc = QueryInterface( IID_CAAIMmrCombinedCurve , (void**) &piCombinedCurve );
       if ( SUCCEEDED(rc) )
       {
          // Retrieves curves and directions
          rc = piCombinedCurve->GetCurve    ( 1 , &piSpecOnCurve1     );
          if ( SUCCEEDED(rc) )
              rc = piCombinedCurve->GetDirection( 1 , &piSpecOnDirection1 );
          if ( SUCCEEDED(rc) )
             rc = piCombinedCurve->GetCurve    ( 2 , &piSpecOnCurve2     );
          if ( SUCCEEDED(rc) )
             rc = piCombinedCurve->GetDirection( 2 , &piSpecOnDirection2 );
...

Once the inputs are retrieved, you can generate an error if one of them are not valid. 

...
          if ( FAILED(rc) )
          {
             if ( NULL != piSpecOnCurve1 )
             {
                piSpecOnCurve1->Release();
                piSpecOnCurve1 = NULL;
             }
             if ( NULL != piSpecOnCurve2 )
             {
                piSpecOnCurve2->Release();
                piSpecOnCurve2 = NULL;
             }
             if ( NULL != piSpecOnDirection1 )
             {
                piSpecOnDirection1->Release();
                piSpecOnDirection1 = NULL; 
             }
             if ( NULL != piSpecOnDirection2 )
             {
                piSpecOnDirection2->Release();
                piSpecOnDirection2 = NULL; 
             }

             CATMfErrUpdate *pErrorNoValidInput = new CATMfErrUpdate();
             CATUnicodeString Diagnostic("Invalid inputs.");
             pErrorNoValidInput->SetDiagnostic(1,Diagnostic);

             CATThrow(pErrorNoValidInput);
          }
       }
...

pErrorNoValidInput is a CATMfErrUpdate error. Before to throw the error, all the none-null pointers declared in the CATTry section, in other words the inputs of the Combined Curve, are released. 

Note: In the use case we have chosen to generate an update error if the inputs of the combined curve are wrong. You can also considerer that it is an internal error, so do not generate an error but only use the HRESULT mechanism. In this last case, the "Update Diagnosis" dialog box will not appear in case of error. Refer to the "A Description of Update Errors" article [6] for details about the update errors.

Retrieving the two CATMathDirections Corresponding to the two Input Directions

Retrieving the geometrical directions of the two input directions is even easier. You just have to get a pointer on CATLine from the input direction, and then ask this CATLine for its mathematical direction.

...
       CATMathDirection MathDirection1,MathDirection2 ;

       if ( SUCCEEDED(rc) )
       {
          CATLine *piLine1 = NULL;
    
          rc = piSpecOnDirection1->QueryInterface( IID_CATLine , ( void**) &piLine1 );
    
          if ( SUCCEEDED(rc) )
          {
             piLine1->GetDirection(MathDirection1);
             ...
          }
       }

       if ( SUCCEEDED(rc) )
       {
          CATLine *piLine2 = NULL;
    
          rc = piSpecOnDirection2->QueryInterface( IID_CATLine , ( void**) &piLine2 );
    
          if ( SUCCEEDED(rc) )
          {
             piLine2->GetDirection(MathDirection2);
             ...
          }
       }      
...

These input curves and directions will be now asked to give their geometry so that you can compute the two extruded surfaces.

Retrieving the two CATBody Corresponding to the two Input Curves

A method of CATIGeometricalElement retrieves the CATBody corresponding to a feature.

...
       CATBody_var spiBodyOfCurve1,spiBodyOfCurve2 ;

       if ( SUCCEEDED(rc) )
       {
          CATIGeometricalElement *piGeometricalElementOnCurve1 = NULL;
          rc = piSpecOnCurve1->QueryInterface ( IID_CATIGeometricalElement , 
                                             (void**) &piGeometricalElementOnCurve1 );
    
          if ( SUCCEEDED(rc) )
          {
             spiBodyOfCurve1 = piGeometricalElementOnCurve1->GetBodyResult();
             ...
          }
       }

       if ( SUCCEEDED(rc) )
       {
          CATIGeometricalElement *piGeometricalElementOnCurve2 = NULL;
          rc = piSpecOnCurve2->QueryInterface ( IID_CATIGeometricalElement , 
                                                (void**) &piGeometricalElementOnCurve2 );
    
          if ( SUCCEEDED(rc) )
          {
             spiBodyOfCurve2 = piGeometricalElementOnCurve2->GetBodyResult();
             ...
          }
       }
...

Once again, you do not have to worry about the implementation of CATIGeometricalElement for your Combined Curve or input curves. For example, the parent late type GeometricalElement3D [4] of CombinedCurve has an extension that provides the implementation for CATIGeometricalElement.

[Top]

Creating the Procedural Report

The procedural report is the means to generate the scope of the feature by using the topological report to generate the name of the following cells. The procedural report is managed by the CATIMfProcReport interface. 

The first thing is to declare the following cells by the procedural journal during the Build operation. In general, in the case of a surfacic feature, all the input specifications are followed:

...
       CATLISTV(CATBaseUnknown_var) ListSpec;
       CATListOfCATUnicodeString    ListKeys;
       if ( SUCCEEDED(rc) )
       {
             ListSpec.Append( piSpecOnCurve1     ); 
             ListKeys.Append( MfKeyNone          );
    
             ListSpec.Append( piSpecOnDirection1 ); 
             ListKeys.Append( MfKeyNone          );
    
             ListSpec.Append( piSpecOnCurve2     ); 
             ListKeys.Append( MfKeyNone          );
    
             ListSpec.Append( piSpecOnDirection2 ); 
             ListKeys.Append( MfKeyNone          );
       }
...

ListSpec is the list of specifications to follow, and ListKeys is the list of associated keys. These two lists have the same size. The default value of a key is MfKeyNone. A different key value will indicate that the historical relationship of a node should be replaced with a user information. The value of the key must be in relationship with the information given by the topological report.

...
       if ( SUCCEEDED(rc) )
       {
          rc = QueryInterface( IID_CATIMfProcReport , (void**) &piProcReport );
          if ( SUCCEEDED(rc) )
          {
             int BoolOper = 0;
             piProcReport->CreateProcReport(ListSpec,ListKeys,BoolOper); 
          }
       }
...

Once the CATIMfProcReport interface pointer on the combined curve is retrieved, piProcReport, you can create the procedural report thanks to the CreateProcReport method. The last argument of this method is 0, the default value, because the result ( the scope ) will be affected to the feature itself [Fig.1]. Note that piProcReport is declared at the top of the Build method because it can be released in a CATCatch section.

[Top]

Running the Topological Operators

This step consists in three sub-steps which are always:

Retrieving the Geometrical Factory

The geometrical factory is handled by the CATGeoFactory interface. This interface is implemented by the geometrical container of the Part document [7]. You retrieve this container thanks to the CATIContainerOfDocument interface implemented on the Part document. The CATILinkableObject interface is the means for each feature to retrieve its containing document.

...
       if ( SUCCEEDED(rc) )
       {
          CATILinkableObject *piLinkableObjectOnCombinedCurve = NULL;
          rc = QueryInterface( IID_CATILinkableObject, 
                               (void**)& piLinkableObjectOnCombinedCurve );
          
          if ( SUCCEEDED(rc) )
          {
             CATDocument * pDocument = NULL ;
             pDocument = piLinkableObjectOnCombinedCurve->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 );
                      ...
       }
...

The GetResultContainer is the method of the CATIContainerOfDocument to retrieve the geometrical container. piGeomFactory is the pointer on the geometrical factory interface. This pointer is declared at the beginning of the Build method because it can be released in a CATCatch section.

Retrieving the Topological Journal

The procedural report then provides a pointer on a new topological journal that will log all topological operations.

...
       CATTopData TopData ;
       if ( SUCCEEDED(rc) )
       {
          CATCGMJournalList *pCGMJournalList = piProcReport->GetCGMJournalList();  
          TopData.SetJournal(pCGMJournalList) ;
...

pCGMJournalList is the pointer on the topological journal. This pointer must not be released. pSoftConfig is a pointer declared at the beginning of the Build method because it can be released in a CATCatch section.

Retrieving the Algorithm Configuration
The "CATSoftwareConfiguration" pointer (pSoftConfig) is needed to get the version of the Combined Curve feature [9].
This information is used to determine which type of algorithm will be used to compute the result.
This Software Configuration is stored on the feature instance and has to be retrieved using "CATMmrAlgoConfigServices::GetConfiguration".
If your feature has not been built yet, "IsConfigToStore = 1".
Then, the value set by "TopData.SetSoftwareConfiguration" has to be stored using CATMmrAlgoConfigServices::StoreConfiguration at the end of build process of the feature.
...
       rc = QueryInterface(IID_CATISpecObject,(void **) & pSOCombinedCurve);
       if(SUCCEEDED(rc)&&pSOCombinedCurve != NULL)
       {
           rc = CATMmrAlgoConfigServices::GetConfiguration(pSOCombinedCurve ,pSoftConfig ,IsConfigToStore);
           if(SUCCEEDED(rc))
           {
               // SetSoftwareConfig 
               TopData.SetSoftwareConfiguration(pSoftConfig) ;
               // release pSoftConfig after the procedural report ending
           }
       }

...

Note that "pSoftConfig" and "IsConfigToStore" are declared at the beginning of the Build method because they will be useful at its end and because pSoftConfig can be released in a CATCatch section.
 

Creating the Resulting Geometry

The combined curve geometry is computed thanks three operations:

The first surface is created by a CATTopPrism operator. pCurve1Extrude is a CATTopPrism interface pointer declared at the top of the Build method. 

...
       if ( SUCCEEDED(rc) )
       {
          CATLength StartOffset = 1000;
          CATLength EndOffset   = -StartOffset;

          pCurve1Extrude = ::CATCreateTopPrism ( piGeomFactory   ,
					    &TopData ,
					    spiBodyOfCurve1  ,
					    &MathDirection1 ,
					    StartOffset     ,
					    EndOffset);
 
          if ( NULL != pCurve1Extrude)
          {
             pCurve1Extrude->Run();

             pCurve1ExtrudeBody = pCurve1Extrude->GetResult();
          }        
          ...
       }
...

pCurve1ExtrudeBody is an intermediary CATBody corresponding to the first surface. It is also declared at the top of the Build method. Once the combined curve body will be computed, pCurve1ExtrudeBody should be removed from the geometric container.

The second surface is also created by a CATTopPrism operator. pCurve2Extrude is a CATTopPrism interface pointer declared at the top of the Build method. 

...
          pCurve2Extrude = ::CATCreateTopPrism ( piGeomFactory   ,
                                            &TopData,
					    spiBodyOfCurve2  ,
					    &MathDirection2 ,
					    StartOffset     ,
					    EndOffset);
	
          if ( NULL != pCurve2Extrude)
          {
             pCurve2Extrude->Run();
       
             pCurve2ExtrudeBody = pCurve2Extrude->GetResult ();
          }
       }
...

pCurve2ExtrudeBody is an intermediary CATBody corresponding to the first surface. It is also declared at the top of the Build method. Once the combined curve body will be computed, pCurve2ExtrudeBody should be removed from the geometric container.

At last, the final result is created by a CATHybOperator operator. pIntersect is a CATHybOperator interface pointer declared at the top of the Build method. pResultBody is the resulting topology. 

...
       CATBody   *pResultBody = NULL ;

       if ( SUCCEEDED(rc) &&  (NULL!=pCurve2ExtrudeBody) && (NULL!=pCurve1ExtrudeBody) )
       {
          pIntersect = ::CATCreateTopIntersect ( piGeomFactory      ,
					      &TopData ,
					      pCurve1ExtrudeBody ,
					      pCurve2ExtrudeBody );
   
          if ( NULL != pIntersect )
          {
             pIntersect->Run();
            
             pResultBody= pIntersect->GetResult ();
            
          }
       }
...

Note that pResultBody  is not declared at the top of the method. It is not necessary once its lifecycle is managed by the DeletedProcReport method in the CATCatch sections.

[Top]

Storing the Procedural Report and the Algorithm Configuration

It is now high time to store (fill) the procedural report corresponding to the creation of the geometric result of the Combined Curve. That's the job of the CATIMfProcReport::StoreProcReport method.

In addition, it is also time to store the Algorithm Configuration, if it is needed...
In deed, when the software configuration is retrieved, an integer (IsConfigToStore) determines if it is needed to store this data on the feature instance.
This configuration, used to version the feature, has to be stored, at least, on the first Build Time.[9

The storage of this data on the feature instance is done thanks to CATMmrAlgoConfigServices::StoreConfiguration method.

  ...
       if ( SUCCEEDED(rc) )
       {
          if ( NULL != pResultBody )
          {
             int BoolOper = 0 ; 
             piProcReport->StoreProcReport(pResultBody,NoCopy,BoolOper); 
              
             if(IsConfigToStore == 1) 
             { 
                 CATMmrAlgoConfigServices::StoreConfiguration(pSOCombinedCurve ,pSoftConfig); 
             } 
          }
          else
          {
             CATMfErrUpdate *pErrorNoIntersection = new CATMfErrUpdate();
             CATUnicodeString Diagnostic("The two extruded curves do not intersect.");
             pErrorNoIntersection->SetDiagnostic(1,Diagnostic);

             CATThrow(pErrorNoIntersection);
          }
       }
  ...

The last argument of the StoreProcReport method, BoolOper, is the same as the value in the CreateProcReport method. 

[Top]

Cleaning the Useless Data

In this last part of the CATTry section, you clean the data declared in the first section entitled "Declaring the Useful Pointers" and not released/deleted during the CATTry section.

[Top]

Managing the Error

Some errors may be thrown during these previous operations, the CATTry bloc catches them and the CATCatch blocks treats the error. There are two kinds of errors:

Each CATCatch section processes the error and cleans the pointers declared at the top of the Build method.

Managing the CATMfErrUpdate Error

The highest-level errors are of CATMfErrUpdate type. The error is re-thrown without modification.

...
    CATCatch ( CATMfErrUpdate , pUpdateError)
    {
        if(NULL != piUpdateErrorOnThis) 
        {
            piUpdateErrorOnThis->SetUpdateError(pUpdateError);

            piUpdateErrorOnThis->Release();
            piUpdateErrorOnThis = NULL ;
        }

        // Here the pointers declared at the top of the Build method are cleaned
        
        CATRethrow ;
     }
...
Managing the CATError Error

All other types of errors derive from CATError. The following code associates the diagnostic and the error with the Combined Curve:

...
    CATCatch ( CATError , pError) 
    {

        CATMfErrUpdate *pErrorToThrow = new CATMfErrUpdate();
        pErrorToThrow->SetDiagnostic(1,pError->GetNLSMessage());

        ::Flush(pError);

        if(NULL != piUpdateErrorOnThis) 
        {
            piUpdateErrorOnThis->SetUpdateError(pErrorToThrow);

            piUpdateErrorOnThis->Release();
            piUpdateErrorOnThis = NULL ;
        }

        // Here the pointers declared at the top of the Build method are cleaned

        CATThrow(pErrorToThrow);
    }   
    ...

A new CATMfErrUpdate is created. pError, the CATError, must be released. The Flush global function do that.

Cleaning the Pointers

In the two CATCatch sections it is important to :

and for the data declared in the first section entitled "Declaring the Useful Pointers":

[Top]

Implementing the CATIBuild Interface

To implement the CATIBuild interface, you just have to create a new extension of Combined Curve. Its class name is CAAEMmrCombinedCurveBuild.

This part of CAAEMmrCombinedCurveBuild.cpp aims at declaring this new extension.

...
CATImplementClass(CAAEMmrCombinedCurveBuild,
                  DataExtension,
                  CATBaseUnknown,
                  CombinedCurve);


#include "TIE_CATIBuild.h" 
TIE_CATIBuild( CAAEMmrCombinedCurveBuild);
...

Do not forget to update your dictionary to declare CombinedCurve has been extended to implement CATIBuild.

[Top]


In Short

This paper demonstrates a complete implementation of the CATIBuild interface for the Combined Curve mechanical feature, that can now take part in the update of a Part document.

[Top]


References

[1] Integrating a New Geometrical Feature in the Update Mechanism
[2] Generic Naming Overview
[3] Managing Errors Using Exceptions
[4] Creating Combined Curve's Catalog
[5] Creating Combined Curve's Interface of Type
[6] A Description of Update Errors
[7] The Structure of a Part Document
[8] Enabling Combined Curve's Result Deactivation
[9] Configuration and Versioning in Mechanical Modeler
[Top]

History

Version: 1 [Apr 2000] Document created
Version: 2 [Jan 2003] Document updated
Version: 3 [Jan 2005] Document updated for build deactivation integration
Version: 4 [Jan 2007] Document updated for Algorithm Configuration Services
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.