##################
Tree Traversal API
##################

The underlying structure of HOOPS Exchange model files, namely the PRC, can be rather complex for most use cases.
Most of the time, a thorough knowledge of each entity type is needed to efficiently navigate through a model file.

To facilitate their traversal, the API provides a set of abstraction functions that allow you to manipulate the model file like a simple tree-like structure.

Terminology
===========

An `A3DTree` is a hierarchical arrangement of `A3DTreeNode` entities.
The topmost `A3DTreeNode` is called the root and serves as the starting point for the tree.
Each node can have child nodes, and all non-root nodes have a single parent.

Getting The Tree Entity
=======================

The entire `A3DAsmModelFile` entity is abstracted into a tree-like structure by using :cpp:func:`A3DTreeCompute`.
This function returns an `A3DTree` entity:

.. code:: c

   A3DTree* tree = 0;
   A3DTreeCompute(model_file, &tree, 0);

   // "tree" can be used

Once you're done using the tree structure, release the underlying memory by calling the function again, setting the model file to *0*:

.. code:: c

   A3DTreeCompute(0, &tree, 0);

In between those calls, query the tree nodes starting from the root node, which you can get using :cpp:func:`A3DTreeGetRootNode`:

.. code:: c

   A3DTreeNode* root_node = 0;
   A3DTreeGetRootNode(tree, &root_node);

Node memory is held in the `A3DTree` entity.
Once the latter is released using :cpp:func:`A3DTreeCompute`, all associated nodes are dropped.

Navigating the Tree
===================

To traverse the PRC tree, navigate top to bottom by iteratively calling :cpp:func:`A3DTreeNodeGetChildren`.
The function returns an array whose memory needs to be released once done.

.. code:: c

   A3DUns32 n_child_nodes    = 0;
   A3DTreeNode** child_nodes = 0;

   A3DTreeNodeGetChildren(tree, node, &n_child_nodes, &child_nodes);

   for (A3DUns32 n = 0 ; n < n_child_nodes ; ++n) {
       A3DNode* child_node = child_nodes[n];
       // ...
   }

   // Release array memory
   A3DTreeNodeGetChildren(0, 0, &n_child_nodes, &child_nodes);

.. sidebar:: Check the Tutorials

   Complete examples of tree traversal using :cpp:func:`A3DTreeNodeGetChildren` are available in the following C tutorials:

   * :doc:`/tutorials/c/print-assembly-structure`
   * :doc:`/tutorials/c/mesh-viewer-sample`

.. rubric:: Tree Traversal Example

The following recursive function provides a depth-first traversal of an entire tree:

.. code:: c

   void traverse_tree(A3DTree* const tree, A3DTreeNode* const node)
   {
      printf("Entering node %x\n", node);

      A3DUns32 n_child_nodes    = 0;
      A3DTreeNode** child_nodes = 0;

      A3DTreeNodeGetChildren(tree, node, &n_child_nodes, &child_nodes);

      for (A3DUns32 n = 0 ; n < n_child_nodes ; ++n) {
          traverse_tree(tree, child_nodes[n]);
      }

      A3DTreeNodeGetChildren(0, 0, &n_child_nodes, &child_nodes);

      printf("Leaving node %x\n", node);
   }

The function can be first called from a root `A3DTreeNode`:

.. code:: c

   A3DTreeNode* root_node = 0;
   A3DTreeGetRootNode(tree, &root_node);

   traverse_tree(tree, root_node);

It is also possible to retrieve the parent of an `A3DTreeNode`:

.. code:: c

   A3DTreeNode* parent_node = 0;
   A3DTreeNodeGetParent(tree, node, &parent_node);

Retrieving a Node's Entity and Attributes
=========================================

At any moment, retrieve the underlying entity of a tree node using :cpp:func:`A3DTreeNodeGetEntity`.

.. code:: c

   A3DEntity entity = 0;
   A3DTreeNodeGetEntity(node, &entity);

Name
----

A common operation for entities is to get their name.
The tree traversal API provides a shortcut function that allows you to query it directly from an `A3DTreeNode`:

.. code:: c

   A3DUTF8Char* name = 0;
   if (A3D_SUCCESS == A3DTreeNodeGetName(node, &name) && name) {
       printf("Node: '%s'\n", name);
   }

   // Release memory
   A3DTreeNodeGetName(0, &name);

Transformation
--------------

.. sidebar:: Converting to a 4x4 Matrix

   `A3DTreeNodeGetTransformation` is an abstraction of a general transformation made on an entity.
   A common operation done with it is to convert its underlying data to a 4x4 transform matrix.
   The `mesh viewer sample <https://github.com/techsoft3d/he_basic_viewer/blob/main/main.cpp>`__ provides you with a concrete example of such a function.

Query the underlying `A3DMiscTransformation` entity of an `A3DTreeNode` with :cpp:func:`A3DTreeNodeGetTransformation`:

.. code:: c

   A3DMiscTransformation* transform = 0;
   A3DTreeNodeGetTransformation(node, &transform);

The function computes the transform of the node relative to its parent node.
To retrieve the global (or net) transform, use :cpp:func:`A3DTreeNodeGetNetTransformation` instead.

Visibility and Style
--------------------

To get the effective visibility of an `A3DTreeNode`, use :cpp:func:`A3DTreeNodeGetNetVisibility`:

.. code:: c

   A3DBool visible = A3D_FALSE;
   A3DTreeNodeGetNetVisibility(node, &visible);

   if (visible == A3D_TRUE) {
       printf("Entity is visible.\n");
   } else {
       printf("Entity is not visible.\n");
   }

Conversely, the net style of the node is retrieved using :cpp:func:`A3DTreeNodeGetNetStyle`.
The function directly returns an :cpp:struct:`A3DGraphStyleData` structure.

Getting Node Underlying Geometry
================================

When the underlying entity of a node contains geometrical data, it is possible to compute a resulting mesh into an :cpp:struct:`A3DMeshData` structure:

.. code:: c

   A3DMeshData mesh_data;
   A3D_INITIALIZE_DATA(A3DMeshData, mesh_data);
   A3DTreeNodeGetGeometry(tree, node, A3D_TRUE, &mesh_data, 0);

The function is the equivalent of :cpp:func:`A3DRiComputeMesh` (see :doc:`/guide/geometry/using_a3d_mesh_data`), except that it applies to an ``A3DTreeNode`` instead of an ``A3DRiRepresentationItem`` entity.

