######
Basics
######

General method for setting and getting attributes
=================================================

In older versions of HOOPS Visualize Web, material properties were set using individual functions specialized for the purpose. Now, most properties are set and retrieved using the ``IMaterial`` interface. This means there is only one function that is used to set a property value, and another to retrieve it. 

For example, to set the ambient color of a selected item, we send the "ambientColor" attribute to ``setNodesMaterial``:

.. code-block:: js

    // First select an element on screen, then execute this
    let id = hwv.selectionManager.getFirst()
    let mat = hwv.model.getNodesMaterial([id._nodeId])

    // mat is an object that contains properties of the node
    // first, you may retrieve the color:
    let color = mat.ambientColor
    
    // updating the face color:
    hwv.model.setNodesMaterial([id._nodeId], 
        { ...mat, ["ambientColor"]: new Communicator.Color(1, 1, 1) })

    mat = hwv.model.getNodesMaterial([id._nodeId])
    // mat now contains updated values
    
The code is similar for many (but not all) properties. See the :js:class:`~wv.IMaterial` API entry for a list of properties that can be set this way, and their descriptions.
    

Set/unset face colors
=====================

To set the face color of one or more nodes you can use the :ref:`setNodesMaterial <api_ref/viewing/classes/Communicator.Model:setnodesmaterial>` function. Provide ``setNodesMaterial()`` with a ``NodeId`` array and a color to set all the array element faces to that color.

The following code gets nodeIds from the selection in WebViewer and sets the color of the nodes' faces to red. Multiple nodes can be selected by holding *Ctrl* while left clicking.

.. code-block:: js

    var partIds = [];
    
    // Add selected parts to partIds
    hwv.selectionManager.each(function (selectionItem) {
        partIds.push(selectionItem.getNodeId());
    });
    
    let mat = hwv.model.getNodesMaterial(partIds);
    
    // Color nodes red  
    hwv.model.setNodesMaterial(partIds, 
        { ...mat, ["faceColor"]: new Communicator.Color(255, 0, 0) });

.. image:: images/node-face-color.png

*Several nodes' faces in the model on the right have been colored red*

To unset the face color of nodes you can call :ref:`unsetNodesFaceColor <api_ref/viewing/classes/Communicator.Model:unsetnodesfacecolor>` and provide it the array of NodeIds whose color you want to unset.

.. code-block:: js
    
    // Unset the color of the selected nodes
    hwv.model.resetNodesMaterial(partIds, ["faceColor"]);

You can get nodes' face color with :ref:`getNodesFaceColor <api_ref/viewing/classes/Communicator.Model:getnodesfacecolor>` or :ref:`getNodesEffectiveFaceColor() <api_ref/viewing/classes/Communicator.Model:getnodeseffectivefacecolor>`. Both functions take an array of ``NodeIds`` and return a promise containing a color array. :ref:`getNodesFaceColor <api_ref/viewing/classes/Communicator.Model:getnodesfacecolor>` will return colors set using :ref:`setNodesFaceColor <api_ref/viewing/classes/Communicator.Model:setnodesfacecolor>`, but if a node's color hasn't been set this function will return ``null`` at that index in the array. :ref:`getNodesEffectiveFaceColor() <api_ref/viewing/classes/Communicator.Model:getnodeseffectivefacecolor>` will return the set color, but if not color has been set it will return the color specified  when the model was authored.

.. code-block:: js

    // Print the face color for the selected nodes only if they have been set
    hwv.model.getNodesMaterial(partIds).then(function (result) {
        console.log(result[0].faceColor);
    });
    // Print the face color for the selected nodes
    hwv.model.getNodesEffectiveFaceColor(partIds).then(function (result) {
        console.log(result);
    });

You can also retrieve the color of a specific face on a node with :ref:`getNodeEffectiveFaceColor() <api_ref/viewing/classes/Communicator.Model:getnodeeffectivefacecolor>`. This function takes a :ref:`partId <api_ref/viewing/modules/Communicator:partid>` and a ``faceIndex`` then returns a ``Promise`` containing the color of the specified face.

.. code-block:: js

    // Use the node id of the selected item and its face at the 0th index
    var promiseColor = hwv.model.getNodeEffectiveFaceColor(selectionItem.getNodeId(), 0);
    // Print the color of the face to the console
    promiseColor.then(function (result) {
        console.log(result);
    });


Set/unset line colors
=====================

To set the line color of a one or more nodes the :ref:`setNodesLineColor <api_ref/viewing/classes/Communicator.Model:setnodeslinecolor>` function can be used. Provide :ref:`setNodesLineColor() <api_ref/viewing/classes/Communicator.Model:setnodeslinecolor>` with a ``nodeId`` array and a color to set all the listed nodes' lines to that color.

The following code gets nodeIds from the selection in webviewer and sets their line color to red. Multiple nodes can be selected by holding CTRL while left clicking.

.. code-block:: js

    partIds = [];
    hwv.selectionManager.each(function (selectionItem) {
        partIds.push(selectionItem.getNodeId());
    });
    
    mat = hwv.model.getNodesMaterial(partIds);
    
    hwv.model.setNodesMaterial(partIds, 
        { ...mat, ["lineColor"]: new Communicator.Color(1, 0, 0) });

.. image:: images/node-lines-color.png

*Several nodes' lines in the model on the right have been colored red*

To unset the nodes line color call the :ref:`unsetNodesLineColor() <api_ref/viewing/classes/Communicator.Model:unsetnodeslinecolor>` function and pass it an array of node ids whose color you wish to unset.

.. code-block:: js

    hwv.model.resetNodesMaterial(partIds, ["lineColor"]);

You can retrieve the current color of several nodes' lines with :ref:`getNodesLineColor() <api_ref/viewing/classes/Communicator.Model:getnodeslinecolor>` or :ref:`getNodesEffectiveLineColor() <api_ref/viewing/classes/Communicator.Model:getnodeseffectivelinecolor>`. For ``getNodesLineColor()`` pass in a NodeId array and the function will return a promise containing a color array for the nodes' lines, note that it will return null for nodes that have not had their line color set. The ``getNodesEffectiveLineColor()`` function takes a NodeId array and returns a promise containing a color array with an element for each node in the argument array. For this function, if no line color has been set it will return the color of the line that was specified when the model was authored.

.. code-block:: js

    // Make a NodeId array from the selected nodes
    partIds = [];
    hwv.selectionManager.each(function (selectionItem) {
        partIds.push(selectionItem.getNodeId());
    });
    // Print the color of the input nodes' lines only if they have been set
    hwv.model.getNodesMaterial(partIds).then(function (result) {
        console.log(result[0].lineColor);
    });
    // Print the color of input nodes' lines
    hwv.model.getNodesEffectiveLineColor(partIds).then(function (result) {
        console.log(result);
    });

To get the color from a specific line element of a node call ``getNodesEffectiveLineColor()`` and pass it a ``PartId`` and a lineIndex. The function will return a promise containing the color of the line element at the input index.

.. code-block:: js

    // For each selected item print off the color of the 0th line element
    hwv.selectionManager.each(function (selectionItem) {
        hwv.model.getNodeEffectiveLineColor(selectionItem.getNodeId(), 0).then(function (result) {
            console.log(result);
        });
    });


Reset node face and line color
==============================

To reset all nodes' faces and lines back to their default color call :ref:`resetNodesColor() <api_ref/viewing/classes/Communicator.Model:resetnodescolor>`. This will also reset colors set using a color map as described in the next section.

.. code-block:: js

    hwv.model.resetNodesColor();


Color map
=========

|HCNOW| gives users the ability to color many nodes at once with the :ref:`setNodesColors() <api_ref/viewing/classes/Communicator.Model:setnodescolors>`. By providing the function with a map (from :ref:`NodeId <api_ref/viewing/modules/Communicator:nodeid>` to :doc:`Color </api_ref/viewing/classes/Communicator.Color>`) it will color nodes in the model with a specific color. ``setNodesColors()`` also takes an optional third argument, in the form of a Boolean, that will also apply the color from the map to the models lines.

The code below creates a map from node ID to color and uses it with ``setNodesColors()``:

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

.. image:: images/colormap.png

*Several nodes on the right have been colored using a color map*

Color maps can be obtained from models with the :ref:`getNodeColorMap() <api_ref/viewing/classes/Communicator.Model:getnodecolormap>` function. The first argument to the function is the ``startNodeId``. This is the starting node to walk from to build the color map. The second argument is an :doc:`ElementType </api_ref/viewing/enums/Communicator.ElementType>` (faces, lines or points). The function will return a color map for the specified ``ElementType``. Note that the array will only contain entries for nodes colored using ``setNodesColors()``.

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


Point color
===========

When creating a mesh instance composed of points several properties can be set. The function below generates data that can be used to create a cube mesh instance made of many points.

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

Using the function from above we create a mesh and obtain a :ref:`MeshId <api_ref/viewing/modules/Communicator:meshid>`.

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

With the ``MeshId``, we can create a ``meshInstanceData`` object, before doing this we can specify the color and other properties of the points.

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

In the code above the color of the points is set to red. The opacity, shape and size of the points are also specified. The images below demonstrate the effect these settings can have on meshes composed of points.

.. image:: images/cube-blue-points.png

*Cube made of blue sphere points*

.. image:: images/cube-red-points.png

*Cube made of red square points*


Opacity
=======

The transparency of several nodes can be set at once using :ref:`setNodesOpacity() <api_ref/viewing/classes/Communicator.Model:setnodesopacity>`. The first argument to ``setNodesOpacity()`` is a ``NodeId`` array and the second argument is the opacity to set the nodes to. The value of the second argument should be in the range 0.0 to 1.0, with values near 0.0 being more transparent and values nearing 1.0 being more opaque.

.. code-block:: js

    var partIds = [];
    hwv.selectionManager.each(function (selectionItem) {
        partIds.push(selectionItem.getNodeId());
    });
    
    mat = hwv.model.getNodesMaterial(partIds);
    
    // set nodes opacity to 0.3
    hwv.model.setNodesMaterial(partIds, 
        { ...mat, ["opacity"]: 0.3 });

.. image:: images/node-opacity.png

*Several nodes on the right have had their opacity set to 0.3*

To get the opacity of several nodes use either :ref:`getNodesOpacity() <api_ref/viewing/classes/Communicator.Model:getnodesopacity>` or :ref:`getNodesEffectiveOpacity() <api_ref/viewing/classes/Communicator.Model:getnodeseffectiveopacity>`. ``getNodesOpacity()`` requires a ``NodeId`` array as input and will return a Promise containing an array of opacities for each node. The value will only be returned for nodes whose opacities have been set. ``getNodesEffectiveOpacity()`` takes a ``NodeId`` array and an ``ElementType`` as input and returns the opacity for the specified elements of the input nodes. If the nodes opacity has not been set this function will return the opacity for the node as it specified when it was authored.

.. literalinclude:: /../../applications/client/docs/PG_MaterialBasics.ts
	   :start-after: //! [get_node_opacity]
	   :end-before: //! [get_node_opacity]
	   
To reset the opacity of specific nodes use :ref:`resetNodesOpacity <api_ref/viewing/classes/Communicator.Model:resetnodesopacity>`. The opacity of all nodes in a model can be reset with :ref:`resetModelOpacity() <api_ref/viewing/classes/Communicator.Model:resetmodelopacity>`.

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


Visibility
==========

The visibility of nodes can be disabled or enabled by using :ref:`setNodesVisibility() <api_ref/viewing/classes/Communicator.Model:setnodesvisibility>`. The first argument to the function is a ``NodeId`` array. The second argument is a boolean that determines if nodes will be visible or hidden. The third argument is a boolean and is optional it will control if initially hidden geometries will stay hidden.

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

.. image:: images/node-visibility.png

*Several nodes on the right have been hidden*

You can get the visibility setting of a node using :ref:`getNodeVisibility() <api_ref/viewing/classes/Communicator.Model:getnodevisibility>`.

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

The visibility of all nodes can be reset with :ref:`resetNodesVisibility() <api_ref/viewing/classes/Communicator.Model:resetnodesvisibility>`.

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


Visibility map
==============

Node visibilities can also be set using a map (from node ID to Boolean) using :ref:`setNodesVisibilities() <api_ref/viewing/classes/Communicator.Model:setnodesvisibilities>`.

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

.. image:: images/node-visibility-map.png

*Several nodes on the right have been hidden using a visibility map*
