# Unit Attributes

All entities can embed an arbitrary number of generic attributes. These attributes can be accessed using the generic attributes.

When a generic attribute is of type A3DFloat, the value can be associated to a complex unit system, such as km/h or m²/sec. This unit system can be expressed using the A3DMiscAttributeUnit structure.

Unit attributes are present in Building Information Modeling (BIM) formats as Metadata. Currently only Revit and IFC model files contain such attributes.

## Example Code

This example shows how a simple “kilometers per hour” (km/h) is expressed using unit attributes. The structures are explained in detail below.

    // Define the 'kilometer'

    A3DMiscAttributeBasicUnitData sKmData = A3D_MAKE_DATA(A3DMiscAttributeBasicUnitData);
    sKmData.m_eUnit     = kA3DUnit_Metre;
    sKmData.m_iExponent = 1;
    sKmData.m_dFactor   = 1000;

    // Define the 'per hour'

    A3DMiscAttributeBasicUnitData sHData = A3D_MAKE_DATA(A3DMiscAttributeBasicUnitData);
    sHData.m_eUnit     = kA3DUnit_Hour;
    sHData.m_iExponent = -1;
    sHData.m_dFactor   = 1;

    // Combining to 'km/h'
    A3DMiscAttributeBasicUnitData* psData[] = {sKmData, sHData};

    A3DMiscAttributeUnitData sKmHData = A3D_MAKE_DATA(A3DMiscAttributeBasicUnitData);
    sKmHData.m_pcName          = "km/h";
    sKmHData.m_uiBasicUnitSize = 2;
    sKmHData.m_uiBasicUnits    = psData;

## The A3DMiscAttributeBasicUnitData Structure

An instance of A3DMiscAttributeBasicUnitData represents an element of a complex unit system (the k or the /h in km/h) it’s structure is:

    typedef struct
    {
      A3DUns16      m_usStructSize;
      A3DEBasicUnit m_eUnit;
      A3DInt32      m_iExponent;
      A3DDouble     m_dFactor;
    } A3DMiscAttributeBasicUnitData;

`A3DMiscAttributeBasicUnitData.m_eUnit` represents the domain of the unit: meters, hours, kelvins, … It can be any value from the A3DEBasicUnit enum. In our example with km/h the two values we use are ref A3DEBasicUnit “kA3DUnit_Metre” and ref A3DEBasicUnit “kA3DUnit_Hour”.

`A3DMiscAttributeBasicUnitData.m_iExponent` is used to represent how the basic unit is used in the whole unit system. It’s value must be non-zero. In km/h the exponent for the kilometers is 1 and the value for hour is -1. Other common values are 2 for square meters and 3 for cubic meters.

`A3DMiscAttributeBasicUnitData.m_dFactor` is a multiplier on the base unit base. A common example is km where the factor is 1000 for “one thousand times a meter”.

## The A3DMiscAttributeUnitData Structure

The A3DMiscAttributeUnitData is a collection of A3DMiscAttributeBasicUnitData and combines them to form a complex unit. In our example, km/h is expressed by combining two ref A3DMiscAttributeBasicUnitData instances: one for the kilometers and one for the hours.

The structure is:

    typedef struct
    {
      A3DUns16                        m_usStructSize;
      A3DUTF8Char*                    m_pcName;
      A3DUns32                        m_uiBasicUnitSize;
      A3DMiscAttributeBasicUnitData** m_ppBasicUnits;
    } A3DMiscAttributeUnitData;

This structure simply aggregates ref A3DMiscAttributeBasicUnitData instances in an ordered array. ref A3DMiscAttributeUnitData::m_pcName “m_pcName” is used to give a name to the unit.

## Getting the Unit From Generic Attributes

When reading generic attributes, the A3DMiscSingleAttributeData instance represents a unit-qualified value if:

- `A3DMiscSingleAttributeData.m_eType` is “kA3DModellerAttributeTypeReal”
- `A3DMiscSingleAttributeData.m_usUnit` is not A3D_DEFAULT_NO_UNIT

`A3DMiscSingleAttributeData.m_usUnit` is an index to the Global data. This index points to an A3DMiscAttributeUnit handle which can be used to retrieve the A3DMiscAttributeUnitData instance.

This example shows how to get the complex unit system from an A3DMiscSingleAttributeData instance:

    void ReadUnit(const A3DMiscSingleAttributeData* psAttrData)
    {
      if(psAttrData->m_usUnit != A3D_DEFAULT_NO_UNIT)
      {
        // Getting the Unit handle from index
        A3DMiscAttributeUnit* pUnit;
        A3DGlobalGetUnit(psAttrData->m_usUnit, &pUnit);

        // Retrieving the Unit data from handle
        A3DMiscAttributeUnitData sUnitData = A3D_MAKE_DATA(A3DMiscAttributeUnitData);
        A3DGlobalGetUnitData(pUnit, &sUnitData);

        // Browsing the basic units:
        for(A3DUns32 u = 0 ; u < sUnitData.m_uiBasicUnitSize ; ++u)
        {
            printf("- Unit %d, Exponent %d, Factor %f\n",
            sUnitData.m_ppBasicUnits[u].m_eUnit;
            sUnitData.m_ppBasicUnits[u].m_iExponent;
            sUnitData.m_ppBasicUnits[u].m_dFactor;
          );
        }

        // Cleaning the data
        A3DGlobalGetUnitData(NULL, &sUnitData);
      }
    }

If this is run with our km/h example, we would get:

    - Unit 21, Exponent 1, Factor 1000
    - Unit 14, Exponent -1, Factor 1

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Exchange in your own language, or choose a sample question below to start a conversation:

What is HOOPS Exchange?
What are the latest release notes for HOOPS Exchange?
How do I start evaluating HOOPS Exchange?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...