########################
Getting the Bounding Box
########################

The bounding box of an entity is a box-shaped volume which geometrically contains the entity and all its sub-entities.

With PRC you can get the axis-aligned bounding box of any visible entity using either :func:`A3DMiscGetBoundingBox` or :func:`A3DMiscComputeBoundingBox`.
The two functions differ in how they do it.

*************************
Axis-Aligned Bounding Box
*************************

An axis-aligned bounding box (AABB) is aligned the with axes of the coordinate system.
Because of that property it is very simple to define the coordinates of a AABB. Only two points forming a diagonal of the box are required.
These points are known as the *min* and *max* coordinates for they respectively represent the minimum and maximum values of the box in each axis.

.. image:: /_assets/images/bounding_box_example.png

With HOOPS Exchange such bounding boxes are described with an :struct:`A3DBoundingBoxData` instance:

.. code-block:: c

   typedef struct
   {
     A3DUns16        m_usStructSize;
     A3DVector3dData m_sMin;
     A3DVector3dData m_sMax;
   } A3DBoundingBoxData;

Where :struct:`A3DVector3dData` is defined as:

.. code-block:: c

   typedef struct
   {
     A3DUns16    m_usStructSize;
     A3DDouble   m_dX;
     A3DDouble   m_dY;
     A3DDouble   m_dZ;
   } A3DVector3dData;

****************************************
Reading the Bounding Box From a PRC Tree
****************************************

To read the bounding box from a PRC tree use :func:`A3DMiscGetBoundingBox`.
This function can be used on an :struct:`A3DAsmModelFile`, an :struct:`A3DAsmProductOccurrence`, an :struct:`A3DAsmPartDefinition` or an :struct:`A3DRiSet`.
If no bounding box is found the function will return an empty one:

.. code-block:: c

   A3DBool IsEmpty(const A3DBoundingBoxData* in_pBoundingBox)
   {
     if(   in_pBoundingBox->m_sMin.m_dX == 0.0
       &&  in_pBoundingBox->m_sMin.m_dY == 0.0
       &&  in_pBoundingBox->m_sMin.m_dZ == 0.0
       &&  in_pBoundingBox->m_sMax.m_dX == 0.0
       &&  in_pBoundingBox->m_sMax.m_dY == 0.0
       &&  in_pBoundingBox->m_sMax.m_dZ == 0.0
     ) return A3D_TRUE;
     return A3D_FALSE;
   }

   void ReadBoundingBox(const A3DEntity* in_pEntity)
   {
     A3DBoundingBoxData sAABB;
     A3D_INITIALIZE_DATA(A3DBoundingBoxData, sAABB);

     A3DStatus iStatus = A3DMiscGetBoundingBox(in_pEntity, &sAABB);

     if(iStatus == A3D_SUCCESS && IsEmpty(&sAABB) == A3D_FALSE)
     {
       // Bounding Box OK
     }
   }

For more information, see :func:`A3DMiscGetBoundingBox`.

********************************************
Computing the Bounding Box From Tessellation
********************************************

If you prefer, you may use :func:`A3DMiscComputeBoundingBox` to make HOOPS Exchange compute the bounding box instead of reading it.
A bounding box will be determined using the tessellation info of the visible entities.

The function returns an invalid bounding box in case of failure:

.. code-block:: c

   A3DBool IsValid(const A3DBoundingBoxData* in_pBoundingBox)
   {
     if(   in_pBoundingBox->m_sMin.m_dX ==  1.0
       &&  in_pBoundingBox->m_sMin.m_dY ==  0.0
       &&  in_pBoundingBox->m_sMin.m_dZ ==  0.0
       &&  in_pBoundingBox->m_sMax.m_dX == -1.0
       &&  in_pBoundingBox->m_sMax.m_dY ==  0.0
       &&  in_pBoundingBox->m_sMax.m_dZ ==  0.0
     ) return A3D_FALSE;
     return A3D_TRUE;
   }

   void ReadBoundingBox(const A3DEntity* in_pEntity)
   {
     A3DBoundingBoxData sAABB;
     A3D_INITIALIZE_DATA(A3DBoundingBoxData, sAABB);

     A3DStatus iStatus = A3DMiscComputeBoundingBox(in_pEntity, 0, &sAABB);

     if(iStatus == A3D_SUCCESS && IsValid(&sAABB) == A3D_TRUE)
     {
       // Bounding Box OK
     }
   }

For more information, see :func:`A3DMiscComputeBoundingBox`.

