###############
Unit Attributes
###############

All entities can embed an arbitrary number of generic attributes.
These attributes can be accessed using the :doc:`generic attributes <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 :doc:`Revit </start/format/revit_reader>` and :doc:`IFC </start/format/ifc_reader>` 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.

.. code-block:: c

   // Define the 'kilometer'

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

   // Define the 'per hour'

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

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

   A3DMiscAttributeUnitData sKmHData;
   A3D_INITIALIZE_DATA(A3DMiscAttributeBasicUnitData, sKmHData);
   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:

.. code-block:: c

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

:member:`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"`.

:member:`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`.
An other common value is `3`, such as when expression square meters.

:member:`A3DMiscAttributeBasicUnitData.m_dFactor` is a multiplier on the base unit base.
A common example is `km` where the factor is `1000` for "ten 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:

.. code-block:: c

   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 :doc:`reading generic attributes </guide/metadata/generic_attributes>`, the `A3DMiscSingleAttributeData` instance represents a unit-qualified value if:

- :member:`A3DMiscSingleAttributeData.m_eType` is `"kA3DModellerAttributeTypeReal"`
- :member:`A3DMiscSingleAttributeData.m_usUnit` is not `A3D_DEFAULT_NO_UNIT`

:member:`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:

.. code-block:: c

   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_INITIALIZE_DATA(A3DMiscAttributeUnitData, sUnitData);
       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:

.. code-block:: c

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

