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 |
|---|---|---|
|
Boolean descriptor.
Can be |
|
|
Unsigned integer type with width of exactly 8 bits |
|
|
Signed integer type with width of exactly 8 bits |
|
|
Unsigned integer type with width of exactly 16 bits |
|
|
Signed integer type with width of exactly 16 bits |
|
|
Signed integer type with width of exactly 32 bits |
implementation dependent |
|
Unsigned integer type with width of exactly 32 bits |
implementation dependent |
|
IEEE 754 64-bits floating-point number |
|
|
IEEE 754 32-bits floating-point number |
|
|
Void type |
|
|
Void pointer type type |
|
|
|
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
A3DEEntityTypewhich 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 |
|
|
Functions
(
|
|---|---|---|---|---|
___ |
|
|
|
|
Model file |
|
`` kA3DTypeAsm ModelFile`` |
` A3DAsmMode lFileData` |
|
BIM data |
|
|
|
|
NURBS Curve |
|
|
|
``
A3DCrvNurbs
Create()``,
|
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:
A3DFaceUVPointInsideManagerDeleteA3DFileContextDeleteA3DMiscCascadedAttributesDeleteA3DMkpRTFDeleteA3DMkpRTFFieldDeleteA3DProjectPointCloudManagerDelete
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:
A3DMiscUnicodeToUTF8A3DMiscUTF16ToUTF8A3DMiscUTF8ToUnicodeA3DMiscUTF8ToUTF16
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, thenpfor pointer type, thenaccording on data type:
bforA3DBooliforA3DInt8,A3DInt16andA3DInt32uiforA3DUns8,A3DUns16andA3DUns32fanddforA3DFloatandA3DDoublerespectivelycforA3DUTF8Charefor enumerationssfor 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 fileA3DAsmModelFileData: A data structure describing a model fileA3DAsmModelFileLoadFromFile(): A function loading a model file into memory