###############
Transformations
###############

A transformation is a rotation, scale, or translation applied to a vertex or group of vertices.
Many models make use of transformations instead of specifying vertices at absolute locations.
PRC files store transforms at the product occurrence level or at the representation item level.

The assembly tree data structure used by PRC facilitates additive matrix operations because transformations accumulate as the tree is traversed depthwise.
If you inspect a transform on a leaf node, it will represent the local transformation of the node.
However, when computing the world space location of the object, you must consider the cumulative transforms of the parent nodes:

.. image:: /_assets/images/computing-cumulative-transforms.png

.. code-block:: c

   worldMatrix = P0Matrix * P1Matrix * RiMatrix;

Three types of transforms exist in HOOPS Exchange - Cartesian, general, and texture.
A Cartesian transformation will include a behavior flag, `m_ucBehavior`, which indicates :doc:`the transform types </api/c/group__a3d__transformationbit>`.
The general transformation is simply a raw matrix.

During parsing, you could do the following to get the transformation from a product occurrence:

.. code-block:: c

   A3DMiscTransformation* transformationNode = prodOccurrence.m_pLocation;

   A3DEEntityType peEntityType;
   A3DEntityGetType(transformationNode, &peEntityType);

   if (peEntityType == kA3DTypeMiscCartesianTransformation)
   {
        A3DMiscCartesianTransformationData transformationData = A3D_MAKE_DATA(A3DMiscCartesianTransformationData);
        A3DMiscCartesianTransformationGet(transformationNode, &transformationData);

        // get transformation origin
        double x = transformationData.m_sOrigin.m_dX;
        double y = transformationData.m_sOrigin.m_dY;
        double z = transformationData.m_sOrigin.m_dZ;

        // transform type (bitwise flag)
        A3DUns8 behavior        = transformationData.m_ucBehavior;
        bool isIdentity         = behavior & kA3DTransformationIdentity;
        bool hasMirroring       = behavior & kA3DTransformationIkA3DTransformationMirror;
        bool hasNonUniformScale = behavior & kA3DTransformationNonUniformScale;
        bool hasRotation        = behavior & kA3DTransformationRotate;
        bool hasScale           = behavior & kA3DTransformationScale;
        bool hasTransformation  = behavior & kA3DTransformationTranslate;
   }
   else if (peEntityType == kA3DTypeMiscGeneralTransformation)
   {
           A3DMiscGeneralTransformationData transformationData = A3D_MAKE_DATA(A3DMiscGeneralTransformationData);
           A3DMiscGeneralTransformationGet(transformationNode, &transformationData);

           // get matrix
           A3DDouble *matrix = transformationData.m_adCoeff;
   }

   // remember to de-initialize transformationData structure when you're done

