Generic Attributes

Attributes are general purpose data that can be associated to any entity. Using an #A3DRootBase instance, you can browse all its attributes.

Reading or writing generic attributes involves good knowledge on attributes hierarchy:

This page is a general presentation on how to read attributes from any A3DRootBase instance.

Reading a single attribute instance

A single attribute is an instance of A3DMiscSingleAttributeData, a data-only structure which is described as:

typedef struct
{
A3DUns16 m_usStructSize;
A3DBool m_bTitleIsInt;
A3DUTF8Char* m_pcTitle;
A3DEModellerAttributeType m_eType;
A3DUTF8Char* m_pcData;
A3DUns16 m_usUnit;
} A3DMiscSingleAttributeData;

Any attribute is a Title/Value pair where:

32-bit integer data

If m_eType == kA3DModellerAttributeTypeInt the data is stored as a 32-bit integer data (A3DUns32):

if(in_sAttr.m_eType == kA3DModellerAttributeTypeInt)
{
A3DUns32 uiData;
memcpy(&uiData, in_sAttr.m_pcData, sizeof(A3DUns32));
printf("Value: %d", uiData);
}

32-bit floating point

If m_eType == kA3DModellerAttributeTypeReal the data is stored as a 32-bit floating point data (A3DFloat):

if(in_sAttr.m_eType == kA3DModellerAttributeTypeReal)
{
A3DFloat uiData;
memcpy(&uiData, in_sAttr.m_pcData, sizeof(A3DFloat));
printf("Value: %f", uiData);
}

When the value is a floating-point the field m_usUnit is used to specify a unit for this value. If no unit is provided, m_usUnit is set to A3D_DEFAULT_NO_UNIT.

For more information about generic unit specifiers, see the unit attributes page.

UTF-8 c-string

If m_eType == kA3DModellerAttributeTypeString the data is stored as a null-terminated UTF-8 string (A3DUTF8Char*):

if(in_sAttr.m_eType == kA3DModellerAttributeTypeString)
{
A3DUTF8Char* pcData = in_sAttr.m_pcData;
printf("Value: %s", uiData);
}

Time specifier

If m_eType == kA3DModellerAttributeTypeTime the data is stored as a time specifier as defined by the time_t specifications:

if(in_sAttr.m_eType == kA3DModellerAttributeTypeString)
{
time_t iData;
memcpy(&iData, in_sAttr.m_pcData, sizeof(A3DInt32));
printf("Value: %s", asctime(gmtime(&iData)));
}

Reading an attribute

An attribute is an instance of A3DMiscAttribute. Any attribute has a title and zero or more A3DMiscSingleAttributeData:

void ReadAttribute(const A3DMiscAttribute* in_pAttribute)
{
A3DMiscAttributeData sAttributeData;
A3D_INITIALIZE_DATA(A3DMiscAttributeData, sAttributeData);
A3DMiscAttributeGet(in_pAttribute, &sAttributeData);
// Iterate through the single attributes
const A3DUns32 uiNSingleAttributes = sAttributeData.m_uiSize;
fo(A3DUns32 sa = 0 ; sa < uiNSingleAttributes ; ++sa)
{
const A3DMiscSingleAttributeData* pSingleAttributeData = sAttributeData.m_asSingleAttributesData + sa;
ReadSingleAttribute(pSingleAttributeData);
}
A3DMiscAttributeGet(NULL, &sAttributeData);
}

Getting the list of attributes

Generic attributes of an A3DRootBase instance are available as an array:

void ReadAttributes(const A3DRootBase* in_pBase)
{
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(in_pBase, &sRootBaseData);
// Iterate through the attributes
const A3DUns32 uiNAttributes = sRootBaseData.m_uiSize;
for(A3DUns32 a = 0 ; a < uiNAttributes ; ++a)
{
const A3DMiscAttribute* pAttribute = sRootBaseData.m_ppAttributes[a];
ReadAttribute(pAttribute);
}
A3DRootBaseGet(NULL, &sRootBaseData);
}

All attributes are instances of A3DMiscAttribute.

Attribute's titles

Within A3DMiscAttributeData and A3DMiscSingleAttributeData, the m_pcTitle may contain:

If m_bTitleIsInt is A3D_TRUE, the A3DUTF8Char* value may directly be casted into A3DUns32* and dereferenced.

Here's an example of function which gets the title of an attribute given its format, and prints in into a buffer:

// Reads in_pcTitle and in_bTitleIsInt to print the title into
// The buffer must be long enough to contains the formatted title.
// Returns A3D_FALSE if in_pcTitle is NULL, A3D_TRUE otherwise.
A3DBool SPrintTitle(A3FUTF8Char* in_pcTitle, A3DBool in_bTitleIsInt, A3DUTF8Char* out_pcBuffer)
{
if(in_pcTitle == NULL) {
return A3D_FALSE;
}
if (in_bTitleIsInt == A3D_TRUE) {
sprintf(out_pcBuffer, "%d", *((A3DUns32*)in_pcTitle));
} else {
wprintf(out_pcBuffer, "%s'", in_pcTitle);
}
return A3D_TRUE;
}

The following examples use SPrintTitle() for readability.

A Complete Example

The code below is a complete example which traverses an A3DRootBase instance and print all its attributes in the standard output in the form:

// Displays attributes as follow:
// Attribute Title0:
// SingleAttribute Title00: Value (Type): Value00
// SingleAttribute Title01: Value (Type): Value01
// Attribute Title1:
// SingleAttribute Title10: Value (Type): Value10
// SingleAttribute Title11: Value (Type): Value11
// ...
void PrintGenericAttributes(const A3DRootBase* in_pRootBase)
{
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(in_pRootBase, &sRootBaseData);
A3DUTF8Char pcTitle[64];
// Iterate through the attributes
const A3DUns32 uiNAttributes = sRootBaseData.m_uiSize;
for (A3DUns32 a = 0; a < uiNAttributes; ++a)
{
const A3DMiscAttribute* pAttribute = sRootBaseData.m_ppAttributes[a];
A3DMiscAttributeData sAttributeData;
A3D_INITIALIZE_DATA(A3DMiscAttributeData, sAttributeData);
A3DMiscAttributeGet(pAttribute, &sAttributeData);
// Display the attribute title
if(SPrintTitle(sAttributeData.m_pcTitle, sAttributeData.m_bTitleIsInt, pcTitle) == A3D_TRUE) {
printf("Attribute: %s\n", pcTitle);
}
// Iterate through the single attributes
const A3DUns32 uiNSingleAttributes = sAttributeData.m_uiSize;
for (A3DUns32 sa = 0; sa < uiNSingleAttributes; ++sa)
{
A3DMiscSingleAttributeData* pSingleAttributeData = sAttributeData.m_asSingleAttributesData+sa;
// Display the single attribute title
if(SPrintTitle(pSingleAttributeData.m_pcTitle, pSingleAttributeData.m_bTitleIsInt, pcTitle) == A3D_TRUE) {
printf("Attribute: %s\n", pcTitle);
}
// Display the single attribute value on the same line
switch (pSingleAttributeData->m_eType)
{
case kA3DModellerAttributeTypeInt:
printf("Value (A3DUns32): %d\n", *(A3DUns32*)pSingleAttributeData->m_pcData);
break;
case kA3DModellerAttributeTypeReal:
printf("Value (A3DFloat): %f\n", *(A3DFloat*)pSingleAttributeData->m_pcData);
break;
case kA3DModellerAttributeTypeTime:
printf("Value (Time): %s\n", asctime(gmtime((time_t*)pSingleAttributeData->m_pcData)));
break;
case kA3DModellerAttributeTypeString:
printf("Value (String): %s\n", pSingleAttributeData->m_pcData);
break;
default:
break;
}
printf("\n");
}
A3DMiscAttributeGet(NULL, &sAttributeData);
}
A3DRootBaseGet(NULL, &sRootBaseData);
}

Attributes and categories

Organization of A3DMiscSingleAttribute instances within #A3DMiscAttribute instances is entirely up to the implementation. Yet, upon reading any format to PRC, HOOPS Exchange organizes attributes into categories.

Within a PRC tree, a category is a named A3DMiscAttribute instance grouping named A3DSingleAttributeInstances. This applies only if both A3DMiscAttribute and A3DSingleAttributeInstances instances have a title.

To sum up for any instance of A3DMiscSingleAttribute within an #A3DMiscAttribute:

void ReadAttributesWithCategories(const A3DRootBase* in_pRootBase)
{
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(in_pRootBase, &sRootBaseData);
// Iterate through the attributes
const A3DUns32 uiNAttributes = sRootBaseData.m_uiSize;
for (A3DUns32 a = 0; a < uiNAttributes; ++a)
{
const A3DMiscAttribute* pAttribute = sRootBaseData.m_ppAttributes[a];
A3DMiscAttributeData sAttributeData;
A3D_INITIALIZE_DATA(A3DMiscAttributeData, sAttributeData);
A3DMiscAttributeGet(pAttribute, &sAttributeData);
// Iterate through the single attributes
const A3DUns32 uiNSingleAttributes = sAttributeData.m_uiSize;
for (A3DUns32 sa = 0; sa < uiNSingleAttributes; ++sa)
{
A3DMiscSingleAttributeData* pSingleAttribute = sAttributeData.m_asSingleAttributesData+sa;
A3DUTF8Char pcAttributeTitle[64];
A3DBool bAttributeHasTitle = SPrintTitle(
pAttribute.m_pcTitle,
pAttribute.m_bTitleIsInt,
pcAttributeTitle
);
A3DUTF8Char pcSingleAttributeTitle[64];
A3DBool bSingleAttributeHasTitle = SPrintTitle(
pSingleAttribute.m_pcTitle,
pSingleAttribute.m_bTitleIsInt,
pcSingleAttributeTitle
);
// If both the A3DMiscSingleAttribute and the A3DMiscAttribute have a title
if(bAttributeHasTitle == A3D_TRUE && bSingleAttributeHasTitle == A3D_TRUE)
{
printf("Category: %s, Attribute Name: %s\n", pcAttributeTitle, pcSingleAttributeTitle);
}
else if(bAttributeHasTitle == A3D_TRUE || bSingleAttributeHasTitle == A3D_TRUE)
{
printf("Attribute Name: %s\n", pcAttributeTitle | pcSingleAttributeTitle);
}
else
{
printf("No Attribute or category name\n");
}
printf("\n");
}
A3DMiscAttributeGet(NULL, &sAttributeData);
}
A3DRootBaseGet(NULL, &sRootBaseData);
}



While very unlikely it remains possible that both A3DMiscAttribute and A3DMiscSingleAttribute have a NULL title.

top_level:1 prog_guide:3