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
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 |
|
|
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
,
A3DRiRepresentationItemor
A3DRiPart(amongst others), but they are all specializations of
A3DRootBase`.
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, thenp
for pointer type, thenaccording on data type:
b
forA3DBool
i
forA3DInt8
,A3DInt16
andA3DInt32
ui
forA3DUns8
,A3DUns16
andA3DUns32
f
andd
forA3DFloat
andA3DDouble
respectivelyc
forA3DUTF8Char
e
for enumerationss
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 fileA3DAsmModelFileData
: A data structure describing a model fileA3DAsmModelFileLoadFromFile()
: A function loading a model file into memory