Converting Code that Traverses Facets in an INDEXED_MESH into Code that Traverses Facets in a LINKED_MESH


The following examples illustrate reading facet data from an INDEXED_MESH, and taking advantage of a higher performance faceter class. The newer class LINKED_MESH is a super-set of data that is contained in the older class INDEXED_MESH. When api_facet_entity uses LINKED_MESH_MANAGER instead of INDEXED_MESH_MANAGER, it performs significantly faster but results in a slightly larger memory footprint. A base class, SEQUENTIAL_MESH, was created to provide a common access to both classes. These examples are not only for those who wish to convert data using the faster LINKED_MESH class, but also serves as examples for those unfamiliar with the LINKED_MESH and the INDEXED_MESH classes.

This section contains snippets of C++ code to illustrate how to traverse facets in an INDEXED_MESH. These snippets are designed to be very simple starting points for developing your own code - they are not complete, compiling and runtime programs.

INDEXED_MESH code converted to LINKED_MESH code Example -1

The following function is an example of one of the ways to traverse facets in an INDEXED_MESH. This shows how to traverse only the polygons.

Note: To see how to traverse the vertices first, then the polygons, see Linked Mesh Example - 2.

void writeINDEXED_MESH(ENTITY * inEntity, FILE* fp)

{

  // Get the transform on the body, if any.
  SPAtransf xform;
  ENTITY * owner;
  api_get_owner( inEntity, owner );
  if ( is_BODY( owner ) )
  {
    BODY * body;
    body = (BODY *)owner;
    if ( body->transform() )
      xform = body->transform()->transform();
  }
  ENTITY_LIST faceList;
  api_get_faces( inEntity, faceList );
  
  // Loop through each face and print facet data
  for ( int faceIndex = 0; faceIndex < faceList.count(); faceIndex++ )
  {
    FACE * face = (FACE*)faceList[faceIndex];
 
    // Find the attribute for facets attached to the face. This is the mesh.
    MESH * face_mesh = NULL;
    af_query( (ENTITY*)face, IDX_MESH_APP, IDX_MESH_ID, face_mesh );
    INDEXED_MESH *mesh = (INDEXED_MESH*)face_mesh;
    if (mesh && mesh->get_type_of_mesh() != INDEXED_MESH_TYPE)
      mesh = 0;
    if ( mesh == NULL )
    {
      printf( "No indexed mesh available for face\n" );
      continue;
    }
   
    // Loop through each facet and print its data
    int polygonCount = mesh->get_num_polygon();
    for ( int polygonIndex = 0; polygonIndex < polygonCount; polygonIndex++ )
    {
      // Get the facet's data as a mesh_polygon
      mesh_polygon* poly = mesh->get_polygon( polygonIndex );
      if ( !poly )
        continue;
      int nodeCount = poly->num_vertex();
      if ( nodeCount <= 0)
        continue;
      fprintf( fp, "Face %d. Polygon %d\n", faceIndex, polygonIndex );
      
      // Loop through each node of this facet, printing its data
      for ( int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++ )
      {
        // Get the node's data as a polygon_vertex and print it
        polygon_vertex* vert = poly->get_vertex( nodeIndex );
        if ( vert )
        {
          SPAposition pos = vert->get_position();
          SPAunit_vector vec = vert->get_normal();
          SPApar_pos uv = vert->get_uv();
          pos *= xform;
          vec *= xform;
          fprintf( fp, "position=(%f %f %f) normal=(%f %f %f) uv=(%f %f)\n",
            pos.x(), pos.y(), pos.z(), vec.x(), vec.y(), vec.z(), uv.u, uv.v );
        }
      } // End braces for Loop through each node of this polygon
    } // End braces for Loop through each polygon
  } // End braces for Loop through each face
} 

The following example performs the same operation as the one above, but uses a SEQUENTIAL_MESH. This is the base class for both INDEXED_MESH and LINKED_MESH. Using a LINKED_MESH will improve faceting performance. The differences is the code used to call af_query and three extra lines of code to call get_seq_polygon.

void writeSEQUENTIAL_MESH_METHOD1 ( ENTITY * inEntity, FILE* fp )

{

  // Get the transform on the body, if any.
  SPAtransf xform;
  ENTITY * owner;
  api_get_owner( inEntity, owner );
  if ( is_BODY( owner ) ) {
    BODY * body;
    body = (BODY *)owner;
    if ( body->transform() )
      xform = body->transform()->transform();
  }
  ENTITY_LIST faceList;
  api_get_faces( inEntity, faceList );
  
  // Loop through each face and print facet data
  for (int faceIndex = 0; faceIndex < faceList.count(); faceIndex++)
  {
    FACE * face = (FACE*)faceList[faceIndex];
    
    // Find the attribute for facets attached to the face. This is the mesh.
    MESH * face_mesh = NULL;
    af_query( (ENTITY*)face, IDX_MESH_APP, IDX_MESH_ID, face_mesh );
    if ( face_mesh == NULL )
    {
      printf( "No indexed mesh or linked mesh available for a face\n" );
      continue;
    }
    SEQUENTIAL_MESH *mesh = (SEQUENTIAL_MESH*)face_mesh;
    
    // Loop through each facet and print its data
    int polygonCount = mesh->get_num_polygon();
    for ( int polygonIndex = 0; polygonIndex < polygonCount; polygonIndex++ )
    {
      // Get the facet's data as a seq_polygon
      seq_polygon polygon;
      logical okay = mesh->get_seq_polygon( polygonIndex, polygon );
      mesh_polygon* poly = &polygon;
      if ( !okay )
        continue;
 
      // Is this a valid facet? If so, print the number of nodes.
      int nodeCount = poly->num_vertex();
      if ( nodeCount <= 0 )
        continue;
      fprintf( fp, "Face %d. Polygon %d\n", faceIndex, polygonIndex );
      
      // Loop through each node of this facet, printing its data
      for ( int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++ )
      {
        // Get the node's data as a polygon_vertex and print it
        polygon_vertex* vert = poly->get_vertex( nodeIndex );
        if ( vert )
        {
          SPAposition pos = vert->get_position();
          SPAunit_vector vec = vert->get_normal();
          SPApar_pos uv = vert->get_uv();
          pos *= xform;
          vec *= xform;
          fprintf( fp, "position=(%f %f %f) normal=(%f %f %f) uv=(%f %f)\n",
            pos.x(), pos.y(), pos.z(), vec.x(), vec.y(), vec.z(), uv.u, uv.v );
        }
      } // End braces for Loop through each node of this polygon
    } // End braces for Loop through each polygon
  } // End braces for Loop through each face
}

The call to get_seq_polygon is slower if the mesh is a LINKED_MESH (rather than an INDEXED_MESH). The improvement in faceting time should make up for this increase in time. With a little more work, we can avoid this increase in time as illustrated in the following example.

The extra code is in adding calls to the functions get_first_polygon, get_first_polynode, get_next_polygon, and get_next_polynode. Also, the calls to num_vertex are replaced by the call to get_num_polynode, and the calls to get_position, get_normal, and get_uv are slightly different. It is best to see the differences using any programmer's source code difference tool.

void writeSEQUENTIAL_MESH( ENTITY * inEntity, FILE* fp )
{
  // Get the transform on the body, if any.
  SPAtransf xform;
  ENTITY * owner;
  api_get_owner( inEntity, owner );
  if ( is_BODY( owner ) )
  {
    BODY * body;
    body = (BODY *)owner;
    if ( body->transform() )
      xform = body->transform()->transform();
  }
  ENTITY_LIST faceList;
  api_get_faces( inEntity, faceList );
  
  // Loop through each face and print facet data
  for ( int faceIndex = 0; faceIndex < faceList.count(); faceIndex++ )
  {
    FACE * face = (FACE*)faceList[faceIndex];
 
    // Find the attribute for facets attached to the face. This is the mesh.
    MESH * face_mesh = NULL;
    af_query( (ENTITY*)face, IDX_MESH_APP, IDX_MESH_ID, face_mesh );
    if ( face_mesh == NULL )
    {
      printf( "No indexed mesh or linked mesh available for a face\n" );
      continue;
    }
    SEQUENTIAL_MESH *mesh = (SEQUENTIAL_MESH*)face_mesh;
    
    // Loop through each facet and print its data
    int polygonCount = mesh->get_num_polygon();
    // Get the handle of the first facet
    MESH_POLYGON meshPolygon;
    mesh->get_first_polygon( meshPolygon );
    for ( int polygonIndex = 0; polygonIndex < polygonCount; polygonIndex++ )
    {
      // Get the handle of the first node of the facet
      MESH_POLYNODE meshPolynode;
      if ( !mesh->get_first_polynode(meshPolygon, meshPolynode) )
        continue;
 
      // Is this a valid facet? If so, print the number of nodes.
      int nodeCount = mesh->get_num_polynode(meshPolygon);
      if ( nodeCount <= 0 )
        continue;
      fprintf( fp, "Face %d. Polygon %d\n", faceIndex, polygonIndex );
      
      // Loop through each node of this facet, printing its data
      for ( int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++ )
      {
        SPAposition pos = mesh->get_position( meshPolynode );
        SPAunit_vector vec = mesh->get_normal( meshPolynode );
        SPApar_pos uv = mesh->get_par_pos( meshPolynode );
        pos *= xform;
        vec *= xform;
        fprintf( fp, "position=(%f %f %f) normal=(%f %f %f) uv=(%f %f)\n",
          pos.x(), pos.y(), pos.z(), vec.x(), vec.y(), vec.z(), uv.u, uv.v );
 
        // Setup for the next loop by getting the next node of the facet
        mesh->get_next_polynode( meshPolynode );
      } // End braces for Loop through each node of this polygon
 
      // Setup for the next loop by getting the next facet
      mesh->get_next_polygon( meshPolygon );
    } // End braces for Loop through each polygon
  } // End braces for Loop through each face
}

Related topics:

Refinements
Mesh Managers
Step-by-Step Faceting
Discarding or Keeping Facet Data
Faceting Functions and Classes
Faceting Using Scheme

[Top]