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:
- An
#A3DMiscSingleAttributeData
instance can hold any value of the following types:
- 32-bit integer.
- 32-bit floating-point (IEEE 754).
- time_t.
- UTF-8 C-Style string.
- An
#A3DMiscAttribute
instance groups any number of #A3DMiscSingleAttributeData
together.
- An
#A3DRootBase
instance can hold any number of #A3DMiscAttribute
.
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:
m_pcTitle
is either a C-string or a 32 bit unsigned integer.
m_pcData
is of any of the above mentioned type.
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);
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);
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:
- A 32 bits unsigned integer if
m_bTitleIsInt
is A3D_TRUE
- A traditional nul-terminated string otherwise
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:
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:
void PrintGenericAttributes(const A3DRootBase* in_pRootBase)
{
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(in_pRootBase, &sRootBaseData);
A3DUTF8Char pcTitle[64];
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);
if(SPrintTitle(sAttributeData.m_pcTitle, sAttributeData.m_bTitleIsInt, pcTitle) == A3D_TRUE) {
printf("Attribute: %s\n", pcTitle);
}
const A3DUns32 uiNSingleAttributes = sAttributeData.m_uiSize;
for (A3DUns32 sa = 0; sa < uiNSingleAttributes; ++sa)
{
A3DMiscSingleAttributeData* pSingleAttributeData = sAttributeData.m_asSingleAttributesData+sa;
if(SPrintTitle(pSingleAttributeData.m_pcTitle, pSingleAttributeData.m_bTitleIsInt, pcTitle) == A3D_TRUE) {
printf("Attribute: %s\n", pcTitle);
}
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
:
- If both the
A3DMiscSingleAttribute
and the #A3DMiscAttribute
have a title, then:
A3DMiscAttribute::m_pcTitle
is the name of the category.
A3DMiscSingleAttribute::m_pcTitle
is the name of the attribute.
- If only one of the instances have a title, there is no category and
m_pcTitle
is the name of the attribute.
void ReadAttributesWithCategories(const A3DRootBase* in_pRootBase)
{
A3DRootBaseData sRootBaseData;
A3D_INITIALIZE_DATA(A3DRootBaseData, sRootBaseData);
A3DRootBaseGet(in_pRootBase, &sRootBaseData);
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);
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(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/05:0