Sample Code to Demonstrate How to Execute Healing Workflow

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

The code snippet demonstrates the following:

Sample Code

// ************************************************************
// Sample customer function to execute Healing Workflow.
//
// Input:
// Input to this function is ENTITY_LIST bodies_imported_into_ACIS which
// should be a list of non-wire bodies translated into ACIS from external
// file formats. This list should only contain BODYs.
//
// Output:
// The function will return back the output bodies in ENTITY_LIST output_bodies
// which will belong to the caller. The entities inside
// bodies_imported_into_ACIS may be invalid after this function.
// ************************************************************
void user_function_for_healing_workflow(ENTITY_LIST& bodies_imported_into_ACIS,
                                        ENTITY_LIST& output_bodies)
{

     // **************************************************************
     // Step 1 : Tolerant Stitching
     // (call api_stitch with tolerant_stitch_options)
     // **************************************************************

      if (/* stitching is needed*/)
      {

         // Create a default tolerant_stitch_options object.
         tolerant_stitch_options sopts;

         // Set the stitcher coincident face identification routine
         // to SPASTITCH_COIN_SKIP to skip stitching coincident faces.
         STITCH_COIN_MODES mode = SPASTITCH_COIN_SKIP;
         sopts.set_stch_coincident_face_handling_mode(mode);

         // Determine and set max-stitch-tol for stitching.
         const double max_stitch_tol = user_function_to_determine_max_stitch_tol();
         sopts.set_max_stitch_tol(max_stitch_tol);

         // Call User's function to stitch list of entities
         user_function_to_stitch_entities(bodies_imported_into_ACIS, output_bodies, sopts);
      }
      else
      {
         output_bodies = bodies_imported_into_ACIS;
      }

     // **************************************************************
     // Step 2 : Simplification
     // (call api_simplify_entity)
     // **************************************************************

     // Determine the desired gap tightness ("desired_gap_tightness")
     // of the user's downstream application (like manufacturing).
     const double desired_gap_tightness = user_function_to_determine_desired_gap_tightness();
     if (/* simplification is needed*/)
     {
         // A user may want to simplify each stitched BODY in the "output_bodies" list.
         // Create default simplify_options object. A default simplify_options object
         // will do both curve and surface simplification based on the default value of
         // simplification tolerance(SPAresabs).
         simplify_options simp_opts;

         // Choose a simplification tolerance. If the user desires the gaps in the model
         // to be within a certain value, then that value could be the best value
         // to use as simplification tolerance. So user may want to use the desired
         // gap tightness as simplification tolerance. Set the simplification tolerance
         // equal to the desired_gap_tightness value of the downstream application.
         simp_opts.set_simplification_tol(desired_gap_tightness);

         // Call User's function to simplify each stitched body
         ENTITY* entity_to_simplify = NULL;
         output_bodies.init();
         while (NULL != (entity_to_simplify = output_bodies.next()))
         {
             user_function_to_simplify_entity(entity_to_simplify, simp_opts);
         }
      }

      // **************************************************************
      // Step 3 : Tighten Gaps to desired tightness
      // (call api_tighten_gaps)
      // **************************************************************

      if (/* gap tightening is needed*/)
      {
         // A user may want to tighten gaps in each of the stitched and simplified
         // BODY so that the gaps in TEDGEs and TVERTEXs in
         // the BODYs are within a "desired_gap_tightness" of the user's downstream
         // application (like manufacturing).
         BODY* body = NULL;
         output_bodies.init();
         while (NULL != (body = (BODY *)output_bodies.next()))
         {
             user_function_to_tighten_gaps_in_body(body, desired_gap_tightness);
         }
      }
}

// ************************************************************
// User function to get max-stitch-tol
// ************************************************************
double user_function_to_determine_max_stitch_tol(/*const ENTITY_LIST& to_be_stitched*/)
{

      // Initialize max_stitch_tol to -1.0
      double max_stitch_tol = -1.0;

      // A user is recommended to set max-stitch-tol such that it is
      // bigger than the size of expected maximum gap between incoming faces.
      // Further it should be smaller than the minimum feature size in the model.
      // This is important because api_stitch might remove edges smaller than
      // the supplied max-stitch-tol.

      return max_stitch_tol;
}

// ************************************************************
// User function to stitch a list of entities
// ************************************************************
void user_function_to_stitch_entities(
                        ENTITY_LIST& to_be_stitched,
                        ENTITY_LIST& output_bodies,
                        tolerant_stitch_options& sopts)
{
    // ENTITY_LIST& new_bodies will contain all the new bodies resulting
    // from the API api_stitch. This list will be a subset of
    // ENTITY_LIST& output_bodies. This list is provided so that it is
    // convenient to the caller to find out the new bodies that the caller
    // will have to take ownership of (for example, the users may have to register
    // new bodies in their application and/or do memory management for those bodies).
    ENTITY_LIST new_bodies;

    // Make the careful option OFF to enable failsafe behavior.
    // Note:  By default the "careful" option is already OFF
    option_header *careful_opt = find_option("careful");
    if (NULL != careful_opt)
    {
       careful_opt->push(FALSE);
    }
    // Note: To disable the failsafe behavior, set the "careful" option ON (push TRUE)

    // Make a call to api_stitch to stitch the entities in "to be stitched" list
    outcome result_stch = api_stitch(to_be_stitched,
                                     output_bodies,
                                     new_bodies,
                                     &sopts);

    // Restore the original value of careful_opt

    if (NULL != careful_opt)
    {
       careful_opt->pop();
}

    // Check and handle fatal problems reported by api_stitch
    // User code to handle failure and exit.

    if ( TRUE == user_function_to_handle_fatal_problem_reported_by_outcome(result_stch) )
    {

       // User code to handle failure and exit
       ...
       return;
    }

    // Handle all new bodies returned by api_stitch
    BODY *new_body = NULL;
    new_bodies.init();
    while (NULL != (new_body = (BODY *)new_bodies.next()))
    {
       // User code to handle new bodies created by api_stitch. For example,
       // the user may want to register new bodies into their application.
       ...
    }

    // User may want to know of the non fatal problems the API encoutered,
    // and take corrective actions if any, before before proceeding to the next step.
    user_function_to_handle_problems_reported_by_outcome(result_stch);

    // Pointer to an array of ENTITY_LIST pointers to store the coincident face
    // cluster lists to allow list processing.
    ENTITY_LIST* coin_face_list = NULL;

    // Get the number of coincident faces clusters
    int num_clusters = sopts.get_number_of_coincident_face_clusters();

    // Check if coincident faces were detected
    if ( num_clusters > 0 )
    {

         // Allocate memory based on the size of coincident face cluster list
         coin_face_list = ACIS_NEW ENTITY_LIST[num_clusters];

         // Now to go in a loop to collect each coincident face cluster
         ENTITY_LIST* cluster = NULL;
         int cluster_index = 0;
         sopts.init_coincident_face_cluster_list();

         while (NULL != (cluster = sopts.get_next_coincident_face_cluster()))
         {
            // deep copy list
            coin_face_list[cluster_index] = *cluster;
            cluster_index ++;
          }

         // Process each cluster (as an example, just print the size of each cluster).
         // In practice, customers will probably want to exit to a handling routine
         // which deletes items from the to_be_stitched list and recall api_stitch  
         // again. The user may need to keep retrying this step until no coincident
         // faces are detected anymore.
         int i=0;
         for (i = 0; i < num_clusters; i++)
         {
             int num_faces = coin_face_list[i].count();
             printf("Number of faces in cluster %d = %d", i, num_faces);
         }

          // Delete the coincident faces cluster list.
         if ( coin_face_list != NULL )
         {
             ACIS_DELETE [] coin_face_list;
             coin_face_list = NULL;
         }
     } // end braces for "num_clusters > 0"

}
// ************************************************************
// User function to get max-stitch-tol
// ************************************************************
double user_function_to_determine_desired_gap_tightness()
{
     // Initialize to -1.0;
     double desired_gap_tightness = -1.0;

     // Determine the desired gap tightness
     // ("desired_gap_tightness") of the user's downstream
     // application (like manufacturing).

     return desired_gap_tightness;
}

// ************************************************************
// User function to simplify an ENTITY
// ************************************************************
void user_function_to_simplify_entity(ENTITY*& entity_to_simplify,
                                      simplify_options& simp_opts)
{
    // Make the careful option OFF to enable failsafe behavior.
    // Note:  By default the "careful" option is already OFF
    option_header *careful_opt = find_option("careful");
    if (NULL != careful_opt)
    {
        careful_opt->push(FALSE);
    }

    // Call api_simplify_entity to simplify body.
    outcome result_of_simplify = api_simplify_entity(
                                            entity_to_simplify,
                                            &simp_opts);

    // Restore the original value of careful_opt
    if (NULL != careful_opt)
    {
        careful_opt->pop();
    }

    // Check and handle fatal problems reported by api_simplify_entity
    // User code to handle failure and exit.
    if ( TRUE == user_function_to_handle_fatal_problem_reported_by_outcome(result_of_simplify) )
    {
        // User code to handle failure and exit
        ...
        return;
    }

    // User may want to know of the non fatal problems the
    // api encoutered, and take corrective actions if any,
    // before before proceeding to the next step.
    user_function_to_handle_problems_reported_by_outcome(result_of_simplify);

 
    return;
}

// ************************************************************
// User function to tighten gaps in BODY
// ************************************************************
void user_function_to_tighten_gaps_in_body(BODY*& body,
                             const double& desired_gap_tightness)
{
    // Make the careful option OFF to enable failsafe behavior.
    // Note:  By default the "careful" option is already OFF
    option_header *careful_opt = find_option("careful");
    if (NULL != careful_opt)
    {
        careful_opt->push(FALSE);
    }
    // Call api_tighten_gaps on body with desired_gap_tightness.
    outcome result_of_gap_tightening = api_tighten_gaps(
                                            body,
                                            desired_gap_tightness);

    // Restore the original value of careful_opt
    if (NULL != careful_opt)
    {
        careful_opt->pop();
    }

    // Check and handle fatal problems reported by api_tighten_gaps
    // User code to handle failure and exit.
    if ( TRUE == user_function_to_handle_fatal_problem_reported_by_outcome(result_of_gap_tightening) )
    {
        // User code to handle failure and exit
        ...
        return;
    }

    // User may want to know of the non fatal problems the
    // api encoutered, and take corrective actions if any,
    // before before proceeding to the next step.
    user_function_to_handle_problems_reported_by_outcome(result_of_gap_tightening);

    return;
}

logical user_function_to_handle_fatal_problem_reported_by_outcome(const outcome& api_outcome)
{
    logical fatal = FALSE;

    // Handle fatal errors of api
    if ( !api_outcome.ok() )
    {
       // User may want to know about the fatal error due to
       // which the API failed
       error_info* einf = api_outcome.get_error_info();

       // User code to report information on errors. A sample
       // function "display_problems_encountered" for such
       // reporting is given at the bottom of the code
       // snippet
       display_problems_encountered(einf);

       // Reasons for error
       if (einf->has_reasons())
       {
           // User code to mention that the following are
           // reasons for the error, the user may print it as
           // printf("Following are the reasons for the error:\n");

           // error_info_list owns all the error_info
           // objects inside it and cleans them up on
           // destruction. User need not worry about memory
           // cleanup of the error_info objects.
            error_info_list reasons_eil;
            einf->reasons(reasons_eil);
            const error_info* reason_einf = NULL;
            for (reasons_eil.init(); NULL != (reason_einf =
                                             reasons_eil.next());)
           {
               display_problems_encountered(reason_einf);
           }
      }

      fatal = TRUE;
  }
  
   return fatal;
}

void user_function_to_handle_problems_reported_by_outcome(const outcome& api_outcome)
{
   if ( api_outcome.ok() )
   {
      // Problem reporting by API.
      // API succeeded (either partially or fully) if this point
      // is reached
      error_info_list eil;
      api_outcome.get_error_info_list(eil);
      const error_info* einf = NULL;
      for (eil.init(); NULL != (einf = eil.next());)
      {
           // User code to report information on problems. A
           // sample function "display_problems_encountered" for
           // such reporting is given at the bottom of the code
           // snippet.
           display_problems_encountered(einf);

           // Reasons for the problem
           if (einf->has_reasons())
           {
                // User code to mention that the following are
                // reasons for the problem, the user may print it as
                printf("Following are the reasons for the error:\n");

                // error_info_list owns all the error_info
                // objects inside it and cleans them up on
                // destruction. User need not worry about memory
                // cleanup of the error_info objects.
                error_info_list reasons_eil;
                einf->reasons(reasons_eil);
                const error_info* reason_einf = NULL;
                for (reasons_eil.init(); NULL != (reason_einf =
                                                 reasons_eil.next());)
                {
                display_problems_encountered(reason_einf);
               }
            }
         }
      }
}

// ************************************************************
// User function to report information on problems
// ************************************************************
void display_problems_encountered(const error_info *einf)
{
    if ( NULL == einf )
    { return; }
    char const *err_message = einf->error_message();
    spa_outcome_severity_type err_severity = einf->severity();

     // User code to display message and severity
     // for example, the user might do the following

    printf("Problem encountered: %s\n", err_message);
    if (SPA_OUTCOME_FATAL == err_severity)

     // Represents a fatal error

    { printf("Severity: FATAL \n"); }
    else if (SPA_OUTCOME_ERROR == err_severity)

     // Represents an error encountered by a failsafe routine
     // during an atomic operation

    { printf("Severity: ERROR \n"); }
    else if (SPA_OUTCOME_PROBLEM == err_severity)

     // Represents a problem encountered during an operation

    { printf("Severity: PROBLEM \n"); }
    else if (SPA_OUTCOME_INSANITY == err_severity)

     // Represents an insanity in the model

    { printf("Severity: INSANITY \n"); }
    int ent_id_cnt = get_error_info_entity_id_count(einf);

     // If ent_id_cnt returns positive count,
     // then einf has atleast one entity, dead or live

    if ( 0 < ent_id_cnt && einf->type() == entity_error_info::id() )
    {
        const entity_error_info* ent_einf = (const entity_error_info *)einf;
        if ( 0 ) /* the user wants to report problems on dead entities too ) */
        // LIVE and DEAD entities
        {
            for (int i = 0; i < ent_id_cnt; i++)
            {
                tag_id_type ent_id = ent_einf->get_entity_id(i);
                ENTITY *err_entity = NULL;
                outcome res_get_ent = api_get_entity_from_id(ent_id, err_entity);
                if ( !res_get_ent.ok() )
                {
                    // Handle API failure and continue or exit as caller thinks suitable
                    ...
                }
                if (NULL != err_entity) // err_entity is LIVE
                {
                    // User code to report a live entity associated with a problem,
                    // for example the user may want to highlight the entity
                }
                else
                {
                    // Report problem for a dead entity
                }
            }
        }
        else // Only LIVE entities
        {
            ENTITY_LIST live_entities;
            ent_einf->get_entities_alive(live_entities);
            ENTITY *live_err_entity = NULL;
            for (live_entities.init(); NULL != (live_err_entity = live_entities.next()); )
            {
                // User code to report a live entity associated with a problem,
                // for example the user may want to highlight the entity
            }
        }
    }
}
}

[Top]