##########
Instancing
##########

Instancing is an efficient way to quickly duplicate individual parts or whole hierarchies of a model on the client. Instead of creating new meshes for the instanced entities, the HOOPS Web Viewer allows you to reference existing meshes within the duplicated node hierarchy.

This walkthrough describes code that is very similar to the code in the Multiple Instance example from the Communicator package. For the working sample, see **Multiple Instance** in the source of the *web_viewer/examples* directory.

The full source code is available at the bottom of the page.


Creating multiple instances from a part of a model
==================================================

In the following code snippet, we are retrieving the part of the model that is currently selected by the user and then creating a new instance of the selected part in the WebViewer, offsetting it from the original model with a translation value that we'll specify.

Here's the model that we'll use as the basis for our new instances:

.. image:: images/instance_original_model.png

*Original model*

First let's define our translation offset. This will be applied to each part that we instance:

.. literalinclude:: /../../applications/client/docs/Instancing.ts
	   :start-after: //! [webviewer_instance_translation]
	   :end-before: //! [webviewer_instance_translation]
	
Depending on your model, your units may be significantly higher or lower, so be sure to adjust these values accordingly.

Next, we'll define a function to gather the selected nodes. After performing a selection in the WebViewer, call this function to query the WebViewer's :ref:`selectionManager <api_ref/viewing/classes/Communicator.WebViewer:selectionmanager>`, and iterate through the results:

.. image:: images/instance_selection.png

*Selected parts in the WebViewer*

.. literalinclude:: /../../applications/client/docs/Instancing.ts
	   :start-after: //! [webviewer_instance_select]
	   :end-before: //! [webviewer_instance_select]

For any results returned by the :ref:`selectionManager <api_ref/viewing/classes/Communicator.WebViewer:selectionmanager>`, we'll add those node IDs to an array that we'll use later to create our instances.

In the function above, there's a call to ``gatherChildLeafNodes()``. This function, which is displayed below, is necessary because nodes returned from the ``selectionManager`` can contain nodes with child nodes that themselves contain geometry. In order to retrieve the correct nodes for our new instances, we need to traverse down to the leaf nodes and gather those child node IDs.

Instead of using a recursive function, we'll create a queue of ``nodes` that we'll query to see if they contain any child nodes. If they don't have any children, then they are a leaf node and will be added to our ``leaves`` array, otherwise, we'll add the ``node`` to our traversal queue and continue down the tree:

.. literalinclude:: /../../applications/client/docs/Instancing.ts
	   :start-after: //! [webviewer_instance_child_leaf_nodes]
	   :end-before: //! [webviewer_instance_child_leaf_nodes]
	
When we call the function to gather the nodes for instancing, we'll also need to gather all of the meshes within each node, since the mesh data 
is what we'll actually be instancing (including color attributes). To do so, we'll call the `map() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map>`_  javascript function to create an array of arrays. Each element will contain an array with a model key as well as an index of the mesh id within the model:

.. literalinclude:: /../../applications/client/docs/Instancing.ts
	   :start-after: //! [webviewer_instance_get_mesh_ids]
	   :end-before: //! [webviewer_instance_get_mesh_ids]
	
We'll pass this data to build the properties for our new instances:

.. literalinclude:: /../../applications/client/docs/Instancing.ts
	   :start-after: //! [webviewer_instance_create_mesh]
	   :end-before: //! [webviewer_instance_create_mesh]

In this snippet, we've chained three promises together. This instructs the program to wait until all the necessary data has been returned before moving on to the next instruction. If we were to call these functions without waiting for the promises to resolve, then we would be subject to a race condition in which our new mesh instances may be created with incorrect values; chaining the promises together prevents that.

The first promise ``Promise.all(meshIdPromises)`` will -- before continuing to the next instruction --  execute all of the promises that call ``getMeshIds()`` for each leaf node; this will create the array of arrays containing the mesh ids for each node.

The functions :ref:`getNodesEffectiveFaceColor <api_ref/viewing/classes/Communicator.Model:getnodeseffectivefacecolor>` and :ref:`getNodesEffectiveLineColor <api_ref/viewing/classes/communicator.model:getnodeseffectivelinecolor>` are used here instead of their plain-vanilla counterparts (i.e, :ref:`getNodesFaceColor <api_ref/viewing/classes/Communicator.Model:getnodesfacecolor>` and :ref:`getNodesLineColor <api_ref/viewing/classes/Communicator.Model:getnodeslinecolor>`) because we need to retrieve the effective color attributes that are being displayed rather than the color set on a particular node, since in many cases color attributes may be inherited from a parent node.

Another important piece of this example code is the call to :ref:`hwv.model.getNodeNetMatrix(myNodeID) <api_ref/viewing/classes/Communicator.Model:getnodenetmatrix>`. Here we are retrieving the net matrix of our original prototype so that when multiple pieces are instanced they still fit together properly. Skipping this step would result in the newly instanced pieces having unpredictable translation and rotation.

Now that we have our net matrix, we can modify the new instance's translation matrix manually by adding our previously defined translation values to the existing net translation matrix. We'll pass the results as a parameter to the constructor of :doc:`MeshInstanceData </api_ref/viewing/classes/Communicator.MeshInstanceData>`, at which point we'll be ready to call :ref:`createMeshInstance() <api_ref/viewing/classes/Communicator.Model:createmeshinstance>` for our new instance.

.. image:: images/instanced_parts.png

*Instanced parts in the WebViewer*


Full instancing source code
===========================

.. literalinclude:: /../../applications/client/docs/Instancing.ts
	   :start-after: //! [webviewer_instance_full_source]
	   :end-before: //! [webviewer_instance_full_source]
