Creating a Specific Attribute Class


After the organization attribute class (which cannot be instantiated) has been defined, specific attribute classes (which can be instantiated) may be derived from it.

Derived Simple Attribute

The example in this topic shows the new class ATTRIB_COL, which is derived from the organization class ATTRIB_ABC. ATTRIB_COL contains an integer that denotes one of eight colors. The attribute is attached to a body.

Color Attribute Header File

To create a header (color_attrib.hxx) file for ATTRIB_COL:

  1. Include the organization attribute classs header file.
  2. Declare the global, dynamically assigned integer identifier for this attribute class.
  3. Declare the identification level of this data type to be one level removed from the organization attribute class.
  4. Declare that ATTRIB_COL is derived from ATTRIB_ABC.
  5. Declare an integer that defines the color. (This is the only data for the class.)
  6. Enter a constructor to create a color attribute for a given color and attach it to a given entity. A constructor that takes zero arguments must be provided for the save/restore functions. The constructor shown in the following example takes zero arguments because all arguments are defaulted. This is the recommended way of providing both the zero argument and standard constructor, rather than writing multiple constructors.
  7. Create the member access (get) and setting (set) functions.
  8. Prototype merge_owner and replace_owner, as these notification methods are to be implemented directly. (These methods are to be implemented directly because none of the predefined merge or replace actions meet your application needs.)
  9. Call the ATTRIB_FUNCTIONS macro to declare the functions required to complete the declaration of an attribute. The macro includes declarations for all ENTITY virtual functions, including make_copy, identity, type_name, size, and debug_ent. The macro also includes the declarations for the functions to save, restore, and copy the attribute.

This example shows what a color attribute file (color_attrib.hxx) could look like.

C++ Example

#if !defined(ATTRIB_COL_CLASS)
#define ATTRIB_COL_CLASS
#include "at_abc.hxx"
extern int ATTRIB_COL_TYPE;
#define ATTRIB_COL_LEVEL (ATTRIB_ABC_LEVEL + 1)
class ATTRIB_COL: public ATTRIB_ABC {
   int color_data;
public:
   ATTRIB_COL(ENTITY* = NULL, int = 0);
   int color() const {return color_data;}
   void set_color(int);
   ATTRIB_FUNCTIONS(ATTRIB_COL, KERN);
   void merge_owner(ENTITY *, logical);    void replace_owner(ENTITY *, logical); };
#endif

Example. color_attrib.hxx Color Attribute Header File (A)

Color Attribute Implementation File

To create a color attribute implementation (color_attrib.cxx) file:

  1. Include necessary system header files.
  2. Include the header file declaring this specific attribute.
  3. Include the header files necessary to define new entities.
  4. Define THIS, THIS_LIB, PARENT, and PARENT_LIB macros to make subsequent definitions of this attribute and its parent easier.
  5. Define the identifier used externally to identify a particular entity type.
  6. Call macros used to implement the standard attribute methods and data. (These macros are discussed elsewhere in this section.)
  7. Write any additional functions that were declared in the .hxx file.
    1. Define the constructor. The example calls the ATTRIB constructor to set the owning entity pointer then sets the member data. It also sets the copy_owner and split_owner actions as desired.
    2. Define the function to set the member data.
    3. Define the prototypes for the merge_owner and replace_owner methods.

This example shows what a color attribute implementation file (color_attrib.cxx) could look like.

#include <stdio.h>
#include <memory.h>
#include "acis.hxx"
#include "datamsc.hxx"
#include "color_attrib.hxx"

// Implementation of color attribute. This is attached to body,
// face or edge objects, and is used to demonstrate attribute
// migration

// Define macros for this attribute and its parent, to simplify
// later stuff and make it suitable for making into macros.
#define THIS() ATTRIB_COL
#define THIS_LIB NONE
#define PARENT() ATTRIB_ABC
#define PARENT_LIB NONE

// Identifier used externally to identify a particular entity
// type. This is used in the save/restore system for translating
// to/from external file format.
#define ATTRIB_COL_NAME "color"

// Implement the standard attribute functions.
ATTRIB_DEF("color_attribute")

    // Define color names for printout
    static char* col_name[] = {
        "black",
        "red",
        "green",
        "blue",
        "cyan",
        "yellow",
        "magenta",
        "white"
    };
    debug_string("color", col_name [color_data], fp);

SAVE_DEF
    write_int(color_data);   
    // Save specific data

RESTORE_DEF
    set_color(read_int());

COPY_DEF
    set_color(from->color());

SCAN_DEF
    // (no specific pointer data)

FIX_POINTER_DEF
    // (no specific pointer data)

TERMINATE_DEF

// make a color attribute
ATTRIB_COL::ATTRIB_COL(
    ENTITY* owner,
    int col
    ) : ATTRIB_ABC(owner)

{
    // Initialize members.
    color_data = col; }
    // If my owner is split, create a new instance of myself
    // on the copy.
    set_split_owner_action( SplitCopy );

    // If my owner is copied, create a new instance of myself
    // on the copy.
    set_copy_owner_action( CopyCopy );
}
// Set the member data.
void ATTRIB_COL::set_color(
    int new_col
    )
{
    backup();
    color_data = new_col;
}

// Virtual function called when two entities are to be merged.
void ATTRIB_COL::merge_owner(
    ENTITY* other_ent,
    logical delete_owner
    )
{
    // If the owner of this attribute is going to be deleted, and
    // there is no color attached to the other entity, then we
    // transfer to that other entity.
    if (delete_owner) {
        ATTRIB* other_att = find_attrib(
            other_ent,
            ATTRIB_ABC_TYPE,
            ATTRIB_COL_TYPE
        );
        if(other_att == NULL) {
            // No color on other entity, so transfer ourselves
            move(other_ent);
        }
    }
}

// Virtual function called during replacement.
void ATTRIB_COL::replace_owner(
    ENTITY* other_ent,
    logical replace_owner
    )
{
    // If the owner of this attribute is going to be replaced
    // (and hence, deleted), and there is no color attached
    // to the other entity, then we transfer to that other
    // entity.
    if (replace_owner) {
        ATTRIB* other_att = find_attrib(             other_ent,             ATTRIB_ABC_TYPE,             ATTRIB_COL_TYPE         );         if(other_att == NULL) {             // No color on other entity, so transfer ourselves             move(other_ent);         }     } }

Example. color_attrib.cxx Color Attribute Implementation File (B)

This example shows an application program that uses the color attribute. The program initializes ACIS, makes a block, and applies a color attribute to the block. The program then writes out a debug file and a SAT file.

C++ Example

#include <stdio.h>
#include <stdlib.h>
#include "acis.hxx"
#include "logical.h"
#include "api.hxx"
#include "kernapi.hxx"
#include "lists.hxx"
#include "body.hxx"
#include "position.hxx"
#include "cstrapi.hxx"
#include "debug.hxx"
#include "col_attr.hxx"

#include "fileinfo.hxx"

void check_outcome (outcome result, char *string);
logical initialize_acis_components();
logical terminate_acis_components();

void main()
{
    // Initialization of the modeler must be done
    // before any other calls.
    outcome result = api_start_modeller( 0 );
    check_outcome(result, "Error starting modeler");

    // Call the main library initialization routine.
    // This routine is meant to initialize the various ACIS
    // libraries that will be linked in.
    initialize_acis_components();

    // Create positions for geometry elements
    SPAposition pts[2];
    pts[0] = SPAposition( 10, 10, 10);
    pts[1] = SPAposition( 15, 20, 30);

    BODY* my_block;

    // Create a solid block.
    result = api_solid_block( pts[0], pts[1], my_block);
    check_outcome(result, "Error solid block");


    // Apply a color attribute of type 1, "red" to the block.
    ACIS NEW ATTRIB_COL (my_block, 1);
    // Write out the debug data file
    FILE* fp = fopen("ExampleC.dbg", "w");
    debug_entity(my_block, fp);
    fclose(fp);

    // Write out the "SAT" data file
   // Setting the units and product_id
   FileInfo fileinfo;
   fileinfo.set_units (1.0);
   fileinfo.set_product_id ("ACIS (c) SPATIAL");
   result = api_set_file_info(3, fileinfo);
   check_outcome(result, "FileInfo Error"); // Added  

     FILE* save_file = fopen("ExampleA-C.sat", "w");
    ENTITY_LIST slist;
    slist.add(my_block);
    api_save_entity_list(save_file, TRUE, slist);
    fclose(save_file);

   // Clean up
   slist.clear();
   result = api_del_entity(my_block);
   check_outcome(result, "Clean Up Error");

   terminate_acis_components();
    printf("Program ended without error.\n");
}

void check_outcome(outcome result, char* string){
    if (result.ok())
        return;
    printf("Error %s\n", string);
    printf("Error %d - %s\n",result.error_number(),
        find_err_mess( result.error_number() ));
    exit(1);
}

logical initialize_acis_components(){
    logical result = TRUE;
    result &= api_initialize_kernel().ok();
    result &= api_initialize_constructors().ok();
    return result;
}

logical terminate_acis_components(){
    logical result = TRUE;
    result &= api_terminate_kernel().ok();
    result &= api_terminate_constructors().ok();
   result &= api_stop_modeller().ok();
    return result;
}

Example. Sample Application Program (C)

Complex Attribute Boolean Conditions

The various notification functions on ATTRIB serve many needs; however, some modeling situations are troubling for complex attributes.

The following figure assumes that both faces A and B have instances of the same complex attribute. During a unite of the tool body containing face A with the blank body containing face B, the attribute on B is notified of a split. However, face A does not participate in the Boolean because it is neither split nor merged. Therefore, after the Boolean, the face A body pointer is still pointing at the now deleted tool body. This must be repaired after the Boolean.

Figure. Complex Attribute

Because the virtual functions do not solve all of these problems, the programmer must be aware that the application may have to do extra work. The application may have to scan the resulting body to determine whether attributes have been updated, and update them where necessary. For example, assume you have two blocks, and each block uses a simple attribute to identify each FACE. Now subtract one block (the tool), as shown in the figure below. This subtraction creates three new FACEs in the blank.

Figure. bool:subtract

During a Boolean operation, the blank and tool faces are split where they intersect. Each split creates a new face and one or more edges. By default, the new faces have no attributes. Later in the Boolean, containment is determined and the faces which are not part of the result are lost. There is no guarantee which faces will be lost. In some cases it will be the original and in others the faces created by the split. So in this example, if you need to have the attributes which are tagged to the tool FACEs automatically be transferred to the corresponding new FACEs created in the blank, you could either:

[Top]