API Conventions

Type Definitions

A3DSDKTypes.h provides the most common fixed-size numeric types. They are used within the whole API:

Type

Description

C Type

A3DBool

Boolean descriptor. Can be A3D_TRUE or A3D_FALSE

char

A3DUns8

Unsigned integer type with width of exactly 8 bits

unsigned char

A3DInt8

Signed integer type with width of exactly 8 bits

char

A3DUns16

Unsigned integer type with width of exactly 16 bits

unsigned short

A3DInt16

Signed integer type with width of exactly 16 bits

short

A3DInt32

Signed integer type with width of exactly 32 bits

implementation dependent

A3DUns32

Unsigned integer type with width of exactly 32 bits

implementation dependent

A3DDouble

IEEE 754 64-bits floating-point number

double

A3DFloat

IEEE 754 32-bits floating-point number

float

A3DVoid

Void type

void

A3DPtr

Void pointer type type

void*

A3DUTF8Char

UTF-8 character type

char*

Architecture

HOOPS Exchange architecture is tightly coupled with its naming design. Most data of your HOOPS application are manipulated through entities, may they be PRC, features, BIM or any other entity type. An entity type consists in:

  • an enumerator value within A3DEEntityType which is used to identify it as an entity.

  • a handle type which uniquely identifies the entity within the entire HOOPS application

  • optionaly a data structure that is used to retrieve or edit the state of an entity.

On top of that, the API may provide each entity type with a set of CRUD-like functions which are used to manipulate the entity or its content. Not every entity types provide all of these functions. This is either because it would be irrelevant or because the operation is indirectly performed by another function.

The following table illustrates the strict naming convention used for an entity type with some examples:

Name

Handle type

A3DEE ntityType

struct

Functions ( Create, Get, Set, Delete)

___

A3D___

kA 3DType___

A 3D___Data

A3D___ Create(), A3D ___Get(), A3D ___Set(), A3D__ _Delete()

Model file

A3DAsm ModelFile

`` kA3DTypeAsm ModelFile``

` A3DAsmMode lFileData`

A3DA smModelFile Create(), A 3DAsmModelF ileGet(), A3D AsmModelFil eDelete()

BIM data

A 3DBIMData

kA3DTy peBIMData

A3DBI MDataData

A3DBIM DataGet()

NURBS Curve

A3 DCrvNurbs

kA3DTyp eCrvNurbs

A3DCrv NurbsData

`` A3DCrvNurbs Create()``, A3DCrvN urbsGet()

Querying the Entity Type of a Handle

When you hold an entity handle you don’t know the underlying type, you can use A3DEntityGetType and match its result to any value of A3DEEntityType. The following example checks if pHandle is a model file:

A3DEEntityType eType = kA3DTypeUnknown;
A3DEntityGetType(pHandle, &eType);
assert(eType == kA3DTypeAsmModelFile);

Retrieving the Data of an Entity

The most common operation performed on an entity is retrieving its data for reading. This is a 3-steps operation: initializing the data structure, retrieving the entity data, then disposing the data structure once not needed anymore. The following function retrieves the data of a product occurrence and prints the number of children product occurrences it contains:

void PrintChildrenPO(const A3DAsmProductOccurrence* pHandle)
{
  A3DAsmProductOccurrenceData sData;
  A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sData);
  A3DAsmProductOccurrenceGet(pHandle, &sData);

  printf("Number of children: %d\n", pData->m_uiPOccurrencesSize);

  A3DAsmProductOccurrenceGet(0, &sData);
}

Let’s detail this code line by line. To initialize a data structure, declare it as a non-const variable use the A3D_INITIALIZE_DATA macro:

A3DAsmProductOccurrenceData sData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sData); // don't use &

Once the structure is initialized, use the Get function to retrieve the data. In the following line, pHandle is of type const A3DAsmProductOccurrence*.

A3DAsmProductOccurrenceGet(pHandle, &sData);

Then, when the data is not needed anymore, give the data back to the API by calling the same function. Set the handle paremeter to 0.

A3DAsmProductOccurrenceGet(0, &sData);

\note Why disposing the data structure? HOOPS Exchange structures may contains heap allocated data such as arrays and strings. It is essentials to remain memory consistent by letting the API releasing it. See the section about memory management for more.

Arrays as struct Fields

Various data fields are made available through lists, such as the product occurrences within a model file or the representation items making and A3DRiSet. HOOPS Exchange provides lists using standard C sequential array types As such, arrays are represented by two fields: an A3DUns32 for the size of the array and a pointer for the array itself:

\code{.c} typedef struct { // … A3DUns32 m_uiPOccurrencesSize; A3DAsmProductOccurrences** m_ppOccurrences; // … } A3DAsmModelFile \endcode

Some array size specifiers may be used to describe two or more arrays. It illustrates the tight coupling between the respective arrays.

Entity Hierarchy

HOOPS architecture provides an abstraction/specialization mechanism for its entities. For example, all entities can be abstracted into an A3DEntity type, while most entities are specializations of A3DRootBase.

In practical, it means that when an entity can be abstracted into another, it can then be safely manipulated as the abstract type. Some of these abstract types have their own data structure. For example, any product occurrence (A3DAsmProductOccurrence) is also a root base entity (A3DRootBase). Thus this code is valid event if pHandle is an A3DAsmProductOccurrence*:

A3DRootBaseData sData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sData);
A3DRootBaseGet(pHandle, &sData);

Conversely, it is possible to give a handle of type A3DRootBase* to a function expecting an A3DAsmProductOccurrence*. In that case, it is up to the caller to ensure the entity has the correct type. This example checks on pHandle before sending it to PrintChildrenPO from the above example:

A3DEEntityType eType = kA3DTypeUnknown;
A3DEntityGetType(pHandle, &eType);

if (eType == kA3DTypeAsmProductOccurrence) {
  PrintChildrenPO(pHandle);
}

Any API call using an unexpected entity type will return A3D_INVALID_ENTITY_TYPE.

\note The hierarchical point of view of entities can be confusing to some readers. Another way to express the relation between entity types is to view HOOPS Exchange as a database. In this example, the key pHandle would exist both in the ProductOccurrence and the A3DRootBase tables.

Structural Hierarchy

A lot of complex structures within Exchange are organiszed as trees. For example, the PRC tree contains all the entities that makes a model file. And the Feature tree organizes all steps performed by a CAD application to obtain the final part. Within such structures, an entity instance may be parent to one or more children entities.

While there is no direct relation between structural and types hierarchies, it’s worth being mentionned that all entities of a same tree are usually specializations of a same entity type. For example, entities making a PRC tree can be A3DAsmProductOccurrence, A3DRiRepresentationItemorA3DRiPart(amongst others), but they are all specializations ofA3DRootBase`.

Memory Management

As a C API, any runtime allocated memory must be explicitely freed after use. A lot of functions and data structure provide you with such memory. Even if it is HOOPS Exchange’s responsibility to actually free it, it is the user application’s to decide when.

The most common use case of memory disposal is with entity data retrieval. If its Get function allocates memory blocks, they are specific to this call. In the following example, sData0.m_pcName and sData1.m_pcName don’t point to the same address space although the entity is the same. This is because internally, the Name of a root base is copied into the A3DRootBaseData parameter.

A3DRootBaseData sData0, sData1;

A3D_INITIALIZE_DATA(sData0);
A3DRootBaseGet(pHandle, &sData0);

A3D_INITIALIZE_DATA(sData1);
A3DRootBaseGet(pHandle, &sData1);
assert(sData0.m_pcName != sData1.m_pcName);

At the end of such code, sData0 and sData1 must be returned to the library so it can clean the memory properly. This is done by calling again A3DRootBaseGet with 0 as the handle:

A3DRootBaseGet(0, &sData1);
A3DRootBaseGet(0, &sData0);

\attention Even if a data structure does not contain heap allocated memory, it may not be the case for future versions of the API. Hence, to ensure robustness against code change and avoid difficult to track memory leaks, you should always dispose your data structure whatever its type is.

Some functions also provide heap-allocated memory through “out parameters”. In this case, the documentation of the fonction provides the information about how to release it.

Providing the Memory Functions

If you want to control how memory is allocated within HOOPS API functions, you can set your own allocation and deallocation functions:

A3DPtr CustomAlloc(size_t uiSize)
{
  return malloc(uiSize);
}

A3DVoid CustomFree(A3DPtr pBlock) {
  free(pBlock);
}

A3DDllSetCallbacksMemory(CustomAlloc, CustomFree);

A3DDllSetCallbacksMemory must be called before A3DDllInitialize.

Deleting Entities

Deleting an entity itself is not a common operation within HOOPS Exchange, but some types provide a deletion operation nevertheless.

When A3DModelFileDelete() is called on a model file enitty, it is entirely dropped. That includes all A3DRootBase that makes the PRC. Most of the time, this is the only deletion function to call.

The more general purpose A3DEntityDelete() function can be called on a specific entity. It drops the entity itself as well as any child entities in the case of an A3DRootBase. This function does not perform any check on the presence of the given entity somewhere in the PRC tree.

Some specific entities provide their own Delete() function:

  • A3DFaceUVPointInsideManagerDelete

  • A3DFileContextDelete

  • A3DMiscCascadedAttributesDelete

  • A3DMkpRTFDelete

  • A3DMkpRTFFieldDelete

  • A3DProjectPointCloudManagerDelete

Garbage Collection

When the library is terminated, the deletion of the HOOPS context releases any remaining memory block. That includes internal buffers and unlinked entities.

Error Management

HOOPS provides error management through a status code return by all the functions. A value of A3D_SUCCESS (0) means the function performed with no error. Otherwise, a non-zero value indicates an error. The list of all error codes can be found in A3DSDKErrorCodes.h as the A3DStatus enumeration.

The same error code may have a different signfication according to the function returning it. For more information about a value returned by a specific call, check out the documentation of the function.

A3DMiscGetErrorMsg() can be used to obtain a description of the error code:

// ...
A3DStatus iStatus = A3DAsmModelFileLoadFromFile(pcPath, &sLoadData, &pHandle);

if (iStatus) {
  fprintf(stderr, "Cannot load model file: '%s'\n", A3DMiscGetErrorMsg(iStatus));
}

String Encoding

HOOPS uses standard C-String for character manipulation: in-memory sequential arrays with a null-termination character (\0).

When storing and manipulating character data, HOOPS Exchange uses UTF-8 encoding. As such, any function and structure requiring string as input should ensure it is converted correctly before being used. The API provides conversion utility functions:

  • A3DMiscUnicodeToUTF8

  • A3DMiscUTF16ToUTF8

  • A3DMiscUTF8ToUnicode

  • A3DMiscUTF8ToUTF16

Code Conventions

HOOPS Exchange is a C API. Any source code including our headers are guaranteed compile using a C or C++ compliant compiler. For more information about compiler requirements, check out the platform requirements page.

Header Files

All headers are located directly under the include/ folder of your HOOPS installation. Files are named using PascalCase, they all contain one of the following prefixes:

  • A3DSDK for most of our SDK

  • A3DPDF for file specific to HOOPS Publish SDK

  • A3DCommon any code common to both APIs

The only exception is hoops_license.h. This file must be replaced with the one usually obtained from the license file generator.

All our header files contain only the declarations and inclusions they need to compile. They are also guaranteed self-sufficient, which mean they don’t rely on the inclusion context to work properly, as long as the #include directive is at global scope.

To compile a source file using HOOPS declaration, you only need to include the header file where the declaration is. For example, you just have to include A3DSDKStructure.h to compile a source using only the A3DAsmModelFileData structure.

If you want to include all API header files at once, use the convenience header A3DSDKIncludes.h. This file is also included within A3DSDKLoader.h to make sure all functions are loaded properly upon initialization.

Naming Conventions

The API uses PascalCase for symbol naming with the exception of macro definitions and A3DStatus values which use CAPITAL_CASE. Variables, formal parameters and struct members follow a Systems Hungarian Notation for naming:

  • m_ for struct members, then

  • p for pointer type, then

  • according on data type:

    • b for A3DBool

    • i for A3DInt8, A3DInt16 and A3DInt32

    • ui for A3DUns8, A3DUns16 and A3DUns32

    • f and d for A3DFloat and A3DDouble respectively

    • c for A3DUTF8Char

    • e for enumerations

    • s for structures

Namespacing

All data types and functions are namespaced using a list of concatenated prefixes. The leftmost prefix is A3D and is always present. Then, successives prefixes are used to sub-namespace each functions. For example, A3DTess3DCreate() and A3DTessMarkupCreate() both have the same base name, but they are within the Tess3D and TessMarkup namespaces respectively.

Associated symbols use the same namespacing:

  • A3DAsmModelFile: An entity handle representing an assembly model file

  • A3DAsmModelFileData: A data structure describing a model file

  • A3DAsmModelFileLoadFromFile(): A function loading a model file into memory