###########
Unit System
###########

.. contents:: How to retrieve and interpret the unit information of your CAD file
   :local:

Getting Model File Unit
=======================

To retrieve the unit used for scaling a model file properly, use :cpp:func:`A3DAsmModelFileGetUnit`.
This function returns the display unit used to scale the whole model file:

.. code-block:: c

   A3DDouble pdUnit = 0.;
   A3DAsmModelFileGetUnit(pModelFile, &pdUnit);

The value stored in ``pdUnit`` represents the :ref:`first valid unit <units_traversal>` found in ``pModelFile`` (``A3DAsmModelFile*``).
It is expressed relative to millimeters, as described in :ref:`prc_units`.

In addition to retrieving direct scale information, you should also consider any scaling applied at the :doc:`entity's individual transformation </guide/metadata/transformations>` level.

.. _prc_units:

Interpreting Units
==================

The **length unit** determines the scale at which a model file should be displayed.

Length units are expressed either using the :cpp:enum:`A3DEUnits` enumerator or as a **double factor** representing a scale relative to millimeters. The latter is used for storing units within a model file.

The following table provides a correspondence between common units and their values in millimeters.
For a complete list, refer to the :cpp:enum:`A3DEUnits reference <A3DEUnits>`.

+----------------------+------------------------------------------+----------------------------------------+
| Unit                 | :cpp:enum:`A3DEUnits`                    | Value in millimeters (``A3DDouble``)   |
+======================+==========================================+========================================+
| Millimeter (mm)      | :cpp:enumerator:`kA3DUnitMillimeter`     | *1.0*                                  |
+----------------------+------------------------------------------+----------------------------------------+
| Inch (in)            | :cpp:enumerator:`kA3DUnitUSSurveyInch`   | *100000./3937.*                        |
+----------------------+------------------------------------------+----------------------------------------+
| Meter (m)            | :cpp:enumerator:`kA3DUnitMeter`          | *1000.0*                               |
+----------------------+------------------------------------------+----------------------------------------+
| Centimeter (cm)      | :cpp:enumerator:`kA3DUnitCentimeter`     | *10.0*                                 |
+----------------------+------------------------------------------+----------------------------------------+
| Foot (ft)            | :cpp:enumerator:`kA3DUnitFoot`           | *(12.0*25.4)*                          |
+----------------------+------------------------------------------+----------------------------------------+
| Micron (µm)          | :cpp:enumerator:`kA3DUnitMicron`         | *1.e-3*                                |
+----------------------+------------------------------------------+----------------------------------------+
| Nanometer (nm)       | :cpp:enumerator:`kA3DUnitNanometer`      | *1.e-6*                                |
+----------------------+------------------------------------------+----------------------------------------+
| :cpp:enum:`See full table... <A3DEUnits>`                                                                |
+----------------------------------------------------------------------------------------------------------+

Two utility functions provide you with converting in-between floating-point decimal representation and :cpp:enum:`A3DEUnits`:

* :cpp:func:`A3DUnitGetFromValue`
* :cpp:func:`A3DUnitGetFromEnum`

.. _units_traversal:

Unit in PRC Tree
================

Unit length information can be found in multiple locations within a PRC tree, starting from the model file.

Both model files and product occurrences contain unit-related fields:

* ``m_bUnitFromCAD`` indicates whether the entity's unit information comes from the original CAD file.
* If ``m_bUnitFromCAD`` is ``A3D_TRUE``, ``m_dUnit`` holds the unit scale (encoded as described in :ref:`prc_units`).

When the unit is set at the model file level, it is referred to as the **global unit scale**. Retrieving this information can be complex, but :cpp:func:`A3DAsmModelFileGetUnit` simplifies the process:

The function first checks :cpp:member:`A3DAsmModelFileData::m_bUnitFromCAD`.

If ``A3D_TRUE``, it returns :cpp:member:`~A3DAsmModelFileData::m_dUnit` as the unit for the entire model.
If ``A3D_FALSE``, it traverses the model file until it finds a product occurrence where :cpp:member:`~A3DAsmProductOccurrenceData::m_bUnitFromCAD` is ``A3D_TRUE``.
It then returns the corresponding :cpp:member:`~A3DAsmProductOccurrenceData::m_dUnit`.

The traversal is *pre-order* and *depth-first*. Once all child product occurrences have been visited, prototypes and external data are traversed in that order.

For example, in the following scenario, :cpp:func:`A3DAsmModelFileGetUnit` would return the unit from *Product Occurrence 3*.

.. image:: units_retrieval.svg
   :align: center

Format-Specific Behaviors
-------------------------

Not all CAD formats handle units the same way.
A usual scenario is cases where an assembly is made of parts that do not encode the same unit.

Since HOOPS Exchange needs to handle an entire model file consistently, it determines a single unit for the whole file using :cpp:func:`A3DAsmModelFileGetUnit`.  
In this situation, the unit information attached to individual parts or sub-assemblies is purely informative and does not influence the actual geometry.  

In most cases, this process is straightforward.  
Formats like SolidWorks always store geometry using a single and uniform unit.
Thus, no special adjustments are needed.  

Other formats, such as Inventor, handle things differently.  
Each part or sub-assembly can be stored in its own unit, meaning an assembly might contain a mix of millimeters, inches, and feet.  
To resolve this, a scale factor must be applied to ensure that all components align with the model’s primary unit, allowing everything to be displayed correctly.  
This operation is automatically performed by Exchange.

Like Inventor, JT allows different parts and sub-assemblies to have their own units.  
However, JT handles scaling internally by applying the necessary adjustments at the instance level.  
As a result, when reading JT files, HOOPS Exchange does not need to perform any additional unit conversion.  
The format itself takes care of it.  

Unit with B-rep Data
====================

In B-rep structures, unit information is stored in the :cpp:struct:`A3DTopoContextData` structure.
The ``m_dScale`` value defines the unit as a scale factor relative to millimeters and applies to all geometric elements under the same topological context.

For more details, see :ref:`brep_units`.

Unit with PMI Data
==================

Semantic PMI may store unit information only relevant to the involved PMI.

For more details, see :ref:`pmi_units`

Unit with Feature Trees
=======================

In feature trees, units are defined using :cpp:struct:`A3DFRMFeatureData` entries of type ``kA3DFRMDoubleUnit``.
These units describe the measurement context (e.g., diameter, angle) of sibling features and are stored in the associated :cpp:struct:`A3DFRMDoubleData` structure 

For more details, see :ref:`feature_units`.

