Mechanical Design

3D Functional Tolerancing & Annotation

Accessing Geometry from an Annotation

Accessing and manipulating geometry on which annotation is applied
Use Case

Abstract

This article discusses the CAATpiAccessGeometry use case. This use case explains how to access the geometry referenced by a 3D annotation. It also illustrate how to perform some topological evaluation on the accessed geometry .


What You Will Learn With This Use Case

This use case is intended to help you to use Technological Product Specifications (TPS) interfaces [1]. The use case demonstrates  CATITPS interface usage to retrieve the TTRSs features (Technologicaly and Topologicaly Related Surface) referenced by a 3D annotation . It also illustrates how to scan the TTRS structure with CATITTRS interfaces to retrieve the RGE (Reference Geometrical Elements).  CATIRGE  and CATIRGETopology interfaces are used to retrieve topological cells from the geometry. Finally, geometrical and topological evaluations are performed to create and display a grid of points with their normal on those cells.

This use case also illustrates how a command can add and manage temporary representation in the main 3D viewer. 

[Top]

The CAATpiAccessGeometry Use Case

CAATpiAccessGeometry is a use case of the CAATPSInterfaces.edu framework that illustrates CATTPSInterfaces and MecModInterfaces framework capabilities.

[Top]

What Does CAATpiAccessGeometry Do

The use case is an interactive command that prompt the user to select a 3D annotation to retrieve and analyse the geometry referenced. The result of the analysis is displayed in a panel. It shows the TTRS, RGE and topological cell composition of  the referenced geometry. When the topological cell is a face, a grid of point with their normals is displayed in the 3D viewer. The geometry referenced by the selected annotation is highlighted.

[Top]

How to Launch CAATpiAccessGeometry

The use case command is available in the toolbar "CAA Sample" of the workbench Product Functionnal & Tolerancing & Annotation.

To launch CAATpiAccessGeometry, you will need to set up the build time environment, then compile CAATPSInterfaces.edu framework along with its prerequisites, set up the run time environment, and then execute the use case [2].

Do not type the module name on the command line, but type CNEXT instead. When the application is ready, do the following:

Notice that the toolbar CAA Sample is also available in other workbenches :

[Top]

Where to Find the CAATpiAccessGeometry Code

The CAATpiAccessGeometry use case is located in the CAATpiAccessGeometry.m module of the CAATPSInterfaces.edu framework:

Windows InstallRootDirectory\CAATPSInterfaces.edu\CAATpiAccessGeometry.m\
Unix InstallRootDirectory/CAATPSInterfaces.edu/CAATpiAccessGeometry.m/

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

[Top]

Step-by-Step

There are seven logical steps in CAATpiAccessGeometry:

  1. Prolog
  2. Retrieving Annotations from Selection
  3. Iterating on the Annotations List to Retrieve Their Names
  4. Retrieving and Initializing Highlight Set of Object (HSO)
  5. Building CATPathElement for Each Annotation and Place it in HSO
  6. Highlighting HSO
  7. Epilog

We will now comment each of these sections by looking at the code.

[Top]

Prolog

The use case is the class CAATpiAccessGeometryCmd which is a CATStateCommand that implement the following statechart diagram.

The Buildgraph method of the command implements this statechart diagram. There are 2 agents associated to the state SelectState. SelectionAgent is a CATPathElementAgent that accept only 3D annotation, when valuated the transition method OnAnnotationSelected is called. ClosePanelAgent is a CATDialogAgent that listen the Close button of the panel to terminate the command.

[Top]

Retrieving TTRSs From Selected Annotation

boolean CAATpiAccessGeometryCmd::OnAnnotationSelected (void * ipData)
{
if ( !_pSelectionAgent || !_pPanel ) return (TRUE);

  HRESULT rc = E_FAIL;

  int TTRSNodeCount = 0;
  int TTRSSupportCount = 0;
  int RGECount = 0;
  int FaceCount = 0;
  int EdgeCount = 0;
  int VertexCount = 0;

  // Read display parameters from panel
  _pPanel -> GetRequiredDisplay (&_bDisplay3DGrid, &_bDisplayTTRSRep);

  // Retrieve the path of the selected annotation
  CATPathElement * pPathTPS = _pSelectionAgent -> GetValue ();
  if ( pPathTPS )
  {
    // Retrieve HSO from editor and empty it
    CATFrmEditor * pEdt = GetEditor();
    if ( pEdt ) 
    {
      CATHSO * pHSO = pEdt -> GetHSO();
      if ( pHSO ) 
      {
        pHSO -> Empty();
        // Add selected PathElement in the HSO, it will be highlighted
        pHSO -> AddElements (pPathTPS);

        CATISO * pISO = pEdt -> GetISO();
        if ( pISO ) 
        {
          // Clean existing element in ISO
          pISO -> RemoveElement (_pModelObjectForAdditionalRep);

          // Retrieve CATITPS interface on selected 3D annotation
          CATITPS * piTPS = NULL;
          rc = pPathTPS -> Search (IID_CATITPS, (void**) &piTPS);
          if ( SUCCEEDED(rc) )
          {
            // Retrieve the list of TTRSs which are directly referenced by
            // the annotation, most often that list contains only 1 element,
            // exeptions are Semantics Targets V5 and Default Annotation
            CATITTRSList * piTTRSList = NULL;
            rc = piTPS -> GetTTRS (&piTTRSList);
            if ( SUCCEEDED(rc) )
            {
              unsigned int TTRSCount = 0;
              piTTRSList -> Count (&TTRSCount);

              CATITTRS * piTTRS = NULL;

              // Allocate representation to display surfaces of TTRSs
              // Points and normals on the TTRSs faces will be
              // added in that Rep by AnalyseTTRS method.
              CAT3DBagRep * pRep = new CAT3DBagRep();

              // Iterate on the list TTRS
              for ( unsigned int Idx = 0 ; Idx < TTRSCount ; Idx ++)
              {
                rc = piTTRSList -> Item (Idx, &piTTRS);
                if ( SUCCEEDED(rc) )
                {
                  // Analyse TTRS Composition
                  AnalyseTTRS (piTTRS, pHSO, pPathTPS,
                               TTRSNodeCount, TTRSSupportCount, RGECount,
                               FaceCount, EdgeCount, VertexCount, pRep);

                  // Construct a Rep to visualize TTRS and add it to ISO
                  AddTTRSGeometryOnRepresentation (piTTRS, pPathTPS, pRep);

                  piTTRS -> Release();
                  piTTRS = NULL;
                }
              }
              // Add new Rep in ISO
              _pModelObjectForAdditionalRep -> SetRep (pRep);

              pISO -> AddElement (_pModelObjectForAdditionalRep);
              pRep = NULL;

              piTTRSList -> Release();
              piTTRSList = NULL;
            }
            piTPS -> Release();
            piTPS = NULL;
          }
          pISO = NULL;
        }
        // No more elements to Add in the HSO, notification is send
        // and HSO content can be highlighted.
        pHSO -> EndAddElements ();
        pHSO = NULL;
      }
      pEdt = NULL;
    }
    pPathTPS = NULL;
  }
  ...
}

When selection agent is valuated the transition method OnAnnotationSelected is called. The CATPathElement selected pPathTPS is retrieved by calling GetValue on the selection agent.  The selected 3D annotation piTPS is retrieved as a CATITPS interface pointer by using the Search method of CATPathElement . The method CATITPS::GetTTRS retrieves the list of TTRS directly referenced by the 3D annotation  as a CATITTRSList interface pointer. CATITTRSList::Count and CATITTRSList::Item methods allow to iterate on the list. Each element of the list is retrieved as a CATITTRS interface pointer and provided to the method AnalyseTTRS to obtain some informations on its composition. 

[Top]

Analyse TTRS Composition

HRESULT CAATpiAccessGeometryCmd::AnalyseTTRS (CATITTRS * ipiTTRS,
                                              CATHSO * ipHSO, 
                                              CATPathElement * ipPathTPS,
                                              int & oTTRSNodeCount,
                                              int & oTTRSSupportCount,
                                              int & oRGECount,
                                              int & oFaceCount,
                                              int & oEdgeCount,
                                              int & oVertexCount,
                                              CAT3DBagRep * iopRep)
{
  if ( ! ipiTTRS || !ipHSO || !ipPathTPS ) return (E_FAIL);

  HRESULT oRc = E_FAIL;

  // Retrieve TTRS nature: support or node.
  CATMmrTTRSType TTRSType = ipiTTRS -> GetNature ();

  // Retrieve the components of the TTRS
  CATLISTV(CATBaseUnknown_var) CompList;
  HRESULT rc = ipiTTRS -> GetComponents (CompList);
  if ( SUCCEEDED(rc) )
  {
    int ComponentCount = CompList.Size();
    int AnalyseSuccessCount = 0;

    CATBaseUnknown_var spBaseComp;

    // If TTRS is a node, components are TTRS
    if ( TTRSType == CATMmrNodeTTRS )
    {
      oTTRSNodeCount ++; // Increment node count

      // Iterate on TTRS components and analyse them
      CATITTRS * piTTRSComp = NULL;
      for ( int i = 1 ; i <= ComponentCount ; i++ )
      {
        spBaseComp = CompList[i];
        if ( NULL_var != spBaseComp )
        {
          rc = spBaseComp -> QueryInterface(IID_CATITTRS, (void**)&piTTRSComp);
          if ( SUCCEEDED(rc) )
          {
            rc = AnalyseTTRS (piTTRSComp, ipHSO, ipPathTPS,
                              oTTRSNodeCount, oTTRSSupportCount, oRGECount,
                              oFaceCount, oEdgeCount, oVertexCount, iopRep);
            if ( SUCCEEDED(rc) )
            {
              AnalyseSuccessCount++;
            }
            piTTRSComp -> Release();
            piTTRSComp = NULL;
          }
          spBaseComp = NULL_var;
        }
      }
    }
    else // If TTRS is a support, components are RGE
    {
      oTTRSSupportCount ++; // Increment support count

      // Iterate on RGE and analyse them
      CATIRGE * piRGE = NULL;
      for ( int i = 1 ; i <= ComponentCount ; i++ )
      {
        spBaseComp = CompList[i];
        if ( NULL_var != spBaseComp )
        {
          rc = spBaseComp -> QueryInterface (IID_CATIRGE, (void**)& piRGE);
          if ( SUCCEEDED(rc) )
          {
            rc = AnalyseRGE (piRGE, ipHSO, ipPathTPS,
                             oRGECount, 
                             oFaceCount, oEdgeCount, oVertexCount, iopRep);
            if ( SUCCEEDED(rc) )
            {
              AnalyseSuccessCount++;
            }
            piRGE -> Release();
            piRGE = NULL;
          }
          spBaseComp = NULL_var;
        }
      }
    }
    // method return S_OK only if each component is analysed successfuly
    if ( ComponentCount == AnalyseSuccessCount )
    {
      oRc = S_OK;
    }
  }
  return (oRc);
}

The AnalyseTTRS purpose is to identify the composition of the input TTRS by scanning recursively the TTRS tree downward. There are 2 kinds of TTRS :  nodes and supports. For a TTRS node its components are other TTRSs, for a support TTRS its components are RGEs. CATITTRS::GetNature method allow to known if the TTRS is a node or a support. According to the nature of the input TTRS the counter oTTRSNodeCount or oTTRSSupportCount is incremented,  CATITTRS::GetComponents is used to retrieved the components of a TTRS. Iteration is performed on the component list to analyse each component by calling AnalyseTTRS or AnalyseRGE method.

[Top]

Analyse RGE Composition 

HRESULT CAATpiAccessGeometryCmd::AnalyseRGE (CATIRGE * ipiRGE,
                                             CATHSO * ipHSO, 
                                             CATPathElement * ipPathTPS,
                                             int & oRGECount,
                                             int & oFaceCount,
                                             int & oEdgeCount,
                                             int & oVertexCount,
                                             CAT3DBagRep * iopRep)
{
  if ( ! ipiRGE || !ipHSO || !ipPathTPS || !iopRep) return (E_FAIL);

  HRESULT oRc = E_FAIL;

  oRGECount ++; // Increment RGE Count
  
  CATIRGETopology * piRGETopo = NULL;
  HRESULT rc = ipiRGE -> QueryInterface (IID_CATIRGETopology, 
                                         (void**)& piRGETopo);
  if ( SUCCEEDED(rc) )
  {
    CATLISTP (CATCell) * pCellList = NULL;
    rc = piRGETopo -> GetCells (&pCellList);
    if ( SUCCEEDED(rc) )
    {
      int CellCount = pCellList -> Size();
      for (int CellIdx = 1; CellIdx <= CellCount; CellIdx++)
      {
        CATCell * pCell = (*pCellList)[CellIdx];
        if ( pCell ) 
        {
          int CellDim = pCell -> GetDimension();
          switch ( CellDim )
          {
          case 0 : oVertexCount ++ ; break;
          case 1 : oEdgeCount ++ ; break;
          case 2 : // Cell is a Face
            {
              oFaceCount ++;
              CATFace * pFace = (CATFace*) pCell;
              CreatePointAndNormalRepresentationOnFace (pFace, piRGETopo,
                                                        ipPathTPS, iopRep);
              pFace = NULL;
            }
            break;
          }
          pCell -> Release();
          pCell = NULL;
        }
      }
      pCellList -> RemoveAll();
      delete pCellList;
      pCellList = NULL;
    }
    piRGETopo -> Release();
    piRGETopo = NULL;
  }
...

The AnalyseRGE method analyse the topological composition of the geometrical element referenced by the RGE. For that the interface CATIRGETopology is available on the RGE feature. The method GetCells allows to  retrieve a list of topological cell. According to the dimension of each cell given by the GetDimension method the counters oVertexCount, oEdgeCount and oFaceCount are incremented. For each CATFace the method CreatePointAndNormalRepresentationOnFace is called, its behavior is described after.

[Top]

Highlight the Geometry Referenced by the  RGE

  CATIBuildPath * piBuildPath = NULL;
  rc = ipiRGE -> QueryInterface (IID_CATIBuildPath, (void**)&piBuildPath);  
  if ( SUCCEEDED(rc) )
  {
    CATPathElement * pPath = NULL;
    rc = piBuildPath -> ExtractPathElement (ipPathTPS, &pPath);
    if ( SUCCEEDED(rc) )
    {
      ipHSO -> AddElements (pPath);

      SpecialTreatementForPathWithSeveralLeaf (pPath, ipHSO);

      pPath -> Release();
      pPath = NULL;
    }
    piBuildPath -> Release();
    piBuildPath = NULL;
  }

Another action performed by the AnalyseRGE method is the highlight of the referenced geometry. This is possible thank to the CATIBuildPath interface that is available on the RGE feature. The CATIBuildPath::ExtractPathElement method is used to build the CATPathElement pPath on the referenced geometry, the CATPathElement ipPathTPS of the selected  TPS is used as context in ExtractPathElement. pPath is placed in the HSO by using AddElements. 

In some cases the CATPathElement constructed for the referenced geometry contains several leafs. When placed in HSO only the first leaf is highlighted. To solve this problem the method SpecialTreatementForPathWithSeveralLeaf creates and adds to HSO an additionnal CATPathElement for each other leaf of the constructed CATPathElement.

[Top]

Create a Mesh of Point With Their Normals on The Faces Retrieved From a RGE

HRESULT CAATpiAccessGeometryCmd::CreatePointAndNormalRepresentationOnFace (
                                                  CATFace * ipFace,
                                                  CATIRGETopology * ipiRGETopo,
                                                  CATPathElement * ipPathTPS,
                                                  CAT3DBagRep * iopRep)
{
  if ( !ipFace || !ipiRGETopo || !ipPathTPS || !iopRep ) return (E_FAIL);

  // If display of grid is not required
  if ( !_bDisplay3DGrid ) return (S_OK);

  HRESULT oRc = E_FAIL;

  // Retrieve coefficient to direction along outside material side
  int Coefficient = 0;
  ipiRGETopo -> GetOutsideMaterialCoefficientOnNormal(&Coefficient);

  // Compute Transformation to take into account product position

  // First retrieve local transformation to apply on cells
  CATMathTransformation LocalPos;
  CATMathTransformation * pLocalPos = NULL;
  HRESULT rc = ipiRGETopo -> GetTransformation (&pLocalPos);
  if ( SUCCEEDED(rc) )
  {
    LocalPos = (*pLocalPos);

    delete pLocalPos;
    pLocalPos = NULL;
  }

  // Second retrieve transformation from product structure.
  CATMathTransformation AbsolutePos;
  CATIMovable * piMove = NULL;
  rc = ipPathTPS -> Search (IID_CATIMovable, (void**)& piMove);
  if ( SUCCEEDED(rc) )
  {
    piMove -> GetAbsPosition(AbsolutePos);

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

  // Cumulate the two positions
  CATMathTransformation Position =  AbsolutePos * LocalPos;

  // Allocate a new rep for points and normals of that face
  CAT3DCustomRep * pPointsAndNormalsRep = new CAT3DCustomRep();

  CATSurface * pSurface = ipFace -> GetSurface();
  if ( pSurface )
  {
    const CATSurLimits * pSurLimits = ipFace -> Get2DBoundingBox();
    if ( pSurLimits && ! pSurLimits ->IsEmpty() )
    {
      double Umin = 0.0;
      double Umax = 0.0;
      double Vmin = 0.0;
      double Vmax = 0.0;
      pSurLimits -> GetExtremities(Umin, Vmin, Umax, Vmax);

      double Ucurrent = 0.0;
      double Vcurrent = 0.0;

      int GridResolution = 10;

      double FractionU = (Umax - Umin) / GridResolution;
      double FractionV = (Vmax - Vmin) / GridResolution;

      CATMathPoint PointOnSurface;
      CATMathDirection NormalAtPointOnSurface;
      CATSurParam InitialParam;
      CATMathPoint PointOnSurfacePos;
      CATMathDirection NormalAtPointOnSurfacePos;

      CATGeoFactory * pGeoFact = ipFace -> GetContainer();
      if ( pGeoFact )
      {
        // Create topological operator for checking that points are inside face
        CATPositionPtFaceOperator * pPosPtFaceOpe
         = CATCreatePositionPtFaceOperator(pGeoFact, InitialParam, ipFace);
        if ( pPosPtFaceOpe )
        {
          for ( int IdxU = 0 ; IdxU <= GridResolution ; IdxU ++)
          {
            Ucurrent = Umin + FractionU * IdxU; // Increment U parameter

            for ( int IdxV = 0 ; IdxV <= GridResolution ; IdxV ++)
            {
              Vcurrent = Vmin + FractionV * IdxV; // Increment V parameter

              // Evaluate point and normal on surface              
              CATSurParam Param;
              pSurface -> CreateParam (Ucurrent, Vcurrent, Param);

              pSurface -> EvalPoint (Param, PointOnSurface);
              pSurface -> EvalNormal (Param, NormalAtPointOnSurface);

              // Check that point is inside Face Limits
              pPosPtFaceOpe -> SetSurParam (Param);
              pPosPtFaceOpe -> Run ();
              
              // If point is inside face limits, keep it for further treatement
              if ( CATLocationOuter != pPosPtFaceOpe-> GetOneResult() )
              {
                // Orient direction along outside material side
                if ( Coefficient != 0 )
                {
                  NormalAtPointOnSurface *= Coefficient;
                }
                
                // Apply Transformation to take into account product position
                PointOnSurfacePos = Position * PointOnSurface;
                NormalAtPointOnSurfacePos = Position * NormalAtPointOnSurface;

                // Create Representation of Point and normal and add it
                // to the representation
                CreateGraphicalPrimitives (pPointsAndNormalsRep, PointOnSurfacePos,
                                           NormalAtPointOnSurfacePos);
              }
            }
          }
          delete pPosPtFaceOpe;
          pPosPtFaceOpe = NULL;
        }
        pGeoFact = NULL;
      }
      pSurLimits = NULL;
    }
    pSurface = NULL;
  }
  iopRep -> AddChild((*pPointsAndNormalsRep));

  return (oRc);
}


The method CreatePointAndNormalRepresentationOnFace needs as input data : 

The first step is to retrieve the coefficient that will be applied on the normal vectors computed on surface to orient them in the direction of the outside material of the part. This is done with CATIRGETopology::GetOutsideMaterialCoefficientOnNormal method that returns a multiplicative coefficient equal to 1 or -1. In case of problem an error value of 0 is returned.

Secondly the position matrix of the results computed from cell is calculated. The local transformation is retrieved by CATIRGETopology::GetTransformation and the global position is retrieved by calling GetAbsPosition, on the CATIMovable interface pointer retrieved on the CATPathElement of the selected annotation. The local and global transformation are cumulated to obtain the position.

[Top]

Epilog

The use case finishes when the command ended by pressing the close button in the panel. 

[Top]


In Short

This use case has demonstrated how to access and manipulate 3D Annotations geometry.

[Top]


References

[1] Technological Product Specification Overview
[2] Building and Launching a CAA V5 Use Case

[Top]


History
Version: 1 [Feb 2002] Document created

[Top]


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