#####################
Selection and picking
#####################

One of the most common methods to interact with the 3D model in the Web Viewer is the process of selection. In short, selection is the process of highlighting one or more entities in the 3D window generally based on some form of user interaction. Often this will involve clicking on a specific entity or dragging a selection rectangle across the 3D Window but a selection can also originate from highlighting a node in the model tree UI or other events external to the Web Viewer.


Picking
=======

When selecting entities in the 3D window it is important to distinguish the process of "picking" from the actual selection of the object. The Web Viewer supports multiple ways to "pick" which essentially means analytically calculating which objects are under a given cursor location or within a certain 2D and 3D area. The results of this computation can then be used to perform the actual selection, which involves grouping and visually highlighting the entities that have been picked. However, the result of a picking operation does not have to lead to a selection. In our measurement operators, for example, we pick on an object to identify the 3d pick location on the mesh and then use that to define the start- and endpoints to measure between.


Pick from point selection
=========================

The simplest form of picking is to pick a specific 2D location in the 3D window.

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

In this snippet, we initialize and populate a :ref:`PickConfig  <api_ref/viewing/classes/Communicator.PickConfig>` object to store a variety of options that will be passed to the pick function. Those options influence the result of the picking operation and determine which entities and subentities will be considered.

In the above call to :ref:`pickFromPoint()  <api_ref/viewing/classes/Communicator.View:pickfrompoint>`, we've passed an arbitrary 2D coordinate in pixel space as a parameter. Using this canvas location, the function will heuristically determine which mesh node and subelements within that mesh node (point, face, or line) to pick. Generally, it will return the entity and subentity closest to the camera within the 2D tolerance defined in the :doc:`PickConfig  </api_ref/viewing/classes/Communicator.PickConfig>` object.

The function :ref:`pickFromPoint() <api_ref/viewing/classes/Communicator.View:pickfrompoint>`, as well as all other picking functions, are asynchronous, meaning that they return a promise which usually returns one or more selected entities as :doc:`SelectionItem  </api_ref/viewing/classes/Communicator.Selection.SelectionItem>` objects. In the above example, we are passing the return :doc:`SelectionItem  </api_ref/viewing/classes/Communicator.Selection.SelectionItem>` object directly to the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` to highlight the selected entity by adding it to the selection list.

See below for all the picking related functions in the Web Viewer:

* :ref:`beginScreenSelectByArea <api_ref/viewing/classes/Communicator.View:beginscreenselectbyarea>`
* :ref:`beginSphereSelection <api_ref/viewing/classes/Communicator.View:beginsphereselection>`
* :ref:`pickAllFromPoint <api_ref/viewing/classes/Communicator.View:pickallfrompoint>`
* :ref:`pickAllFromRay <api_ref/viewing/classes/Communicator.View:pickallfromray>`
* :ref:`pickFromPoint <api_ref/viewing/classes/Communicator.View:pickfrompoint>`
* :ref:`pickFromRay <api_ref/viewing/classes/Communicator.View:pickfromray>`

All those functions have equivalent functions that also perform a selection of the returned entities. We will discuss those functions in the following sections but keep in mind that you can perform these functions independently of a selection as well.


Selection
=========

The :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` class is responsible for handling selection in the Web Viewer. It primarily manages a list of "selected" entities and ensure that those are visually distinguished in the 3D window. There are various methods on the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` that define the visual appearance of the highlighted entities but in general, they will be "tinted" with a specified color and drawn with an outline that is visible even if the geometry is hidden.

A selected entity can either be a node in the model tree that has children and is not directly associated with any geometry or a leaf node in the tree containing mesh geometry. If it’s the former, then all geometry that is part of the descendants of that node will be highlighted. If it’s a leaf node then the :doc:`SelectionItem  </api_ref/viewing/classes/Communicator.Selection.SelectionItem>` can also contain a reference to the closest face, edge or point of the associated mesh. If a non-leaf node is already selected it is not possible to add any of its descendants to the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>`.

In the code below we are setting the color of the selected mesh to blue and the color of the selected element within that mesh (either face or edge) to red.

.. code-block:: js

	hwv.SelectionManager.setNodeSelectionColor(Communicator.Color.createFromFloat(0.0, 0.0, 0.5));
	hwv.SelectionManager.setNodeElementSelectionColor(Communicator.Color.createFromFloat(1, 0, 0));

.. image:: images/selection-picking-to-blue.png


Select single node
==================

The following snippet shows how to use the :doc:`SelectionManager  </api_ref/viewing/classes/Communicator.SelectionManager>` class to select a specific node in the model:

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

After specifying a few properties about our selection appearance, we can use the :ref:`SelectionManager <api_ref/viewing/classes/Communicator.SelectionManager:selectnode>` function of the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` to specify a :ref:`NodeId <api_ref/viewing/modules/Communicator:nodeid>` from our model, which will be highlighted when the function is executed.

The :ref:`selectNode() <api_ref/viewing/classes/Communicator.SelectionManager:selectnode>` function can either add the node to the selection list, toggle its selection state or replace an existing selection based on the :doc:`SelectionMode </api_ref/viewing/enum/Communicator.SelectionMode>` parameter of the function.

The :ref:`selectNode() <api_ref/viewing/classes/Communicator.SelectionMode:selectnode>` function is a convenient way to select based on a single :ref:`NodeId <api_ref/viewing/modules/Communicator:nodeid>` but in a lot of cases you want to select based on a :doc:`SelectionItem </api_ref/viewing/classes/Communicator.Selection.SelectionItem>` returned from one of the pick functions. In general, the :doc:`SelectionItem  </api_ref/viewing/classes/Communicator.Selection.SelectionItem>` not only contains a :ref:`NodeId <api_ref/viewing/modules/Communicator:nodeid>` but also the face and edge of the model that should be selected.


Events
======

Each type of selection generates a :ref:`SelectionArray  <api_ref/viewing/interfaces/Communicator.callbackmap:selectionarray>` event that gets passed a list of :doc:`NodeSelectionEvent </api_ref/viewing/classes/Communicator.Event.nodeselectionevent>` objects.

In the function below we register the :ref:`selectionArray() <api_ref/viewing/interfaces/Communicator.Communicator.CallbackMap:selectionarray>` callback with a function that iterates over all selected entities and retrieves their :ref:`NodeId <api_ref/viewing/modules/Communicator:nodeid>`.

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


Selection operator
==================

A common way to implement selection in the Web Viewer is to simply use the :doc:`SelectionOperator </api_ref/viewing/classes/Communicator.Operator.SelectionOperator>`. By default, the :doc:`SelectionOperator </api_ref/viewing/classes/Communicator.Operator.SelectionOperator>` is enabled in the Web Viewer's operator stack. The operator stack also includes any other currently active operators and is accessible via the :doc:`OperatorManager </api_ref/viewing/classes/Communicator.OperatorManager>` object.

The default behavior of the :doc:`SelectionOperator </api_ref/viewing/classes/Communicator.Operator.SelectionOperator>` is to highlight the part associated with a selection. CTRL+clicking will select multiple parts. To cancel the selection, click on an empty part of the scene. Alternatively, you can enable single-entity toggle mode in this way:

.. code-block:: js

	hwv.selectionManager.setSingleEntityToggleModeEnabled(true)
	
This setting will enable you to CTRL+click on a selected part to deselect it.

A :ref:`PartId <api_ref/viewing/modules/Communicator:partid>` can be retrieved from the selection event data using the :ref:`getNodeId() <api_ref/viewing/classes/Communicator.Selection.SelectionItem:getnodeid>` function.

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

It is important to note that in each of these selection event data objects, the :ref:`PartId <api_ref/viewing/modules/Communicator:partid>` is retrieved by calling the :ref:`getNodeId() <api_ref/viewing/classes/Communicator.Selection.SelectionItem:getnodeid>` function (a :ref:`PartId <api_ref/viewing/modules/Communicator:partid>` is a type of :ref:`NodeId <api_ref/viewing/modules/Communicator:nodeid>` – see the FAQs for more info).

There are a handful of different types of selection events, each with their own data objects (e.g., line, face, point, and part selection objects). To find out more about each, please see the API Reference for the :doc:`Selection  </api_ref/viewing/modules/Communicator.Selection>` class and the :doc:`SelectionType </api_ref/viewing/enum/Communicator.SelectionType>` class.


Area and volume selection
=========================

Select by area
--------------

The :ref:`beginScreenSelectByArea() <api_ref/viewing/classes/Communicator.SelectionManager:beginscreenselectbyarea>` method in the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` class offers an easy way to select objects within a two-dimensional area of the screen. Simply define the bounds of your selection with two points on the screen, and pass that information along with a configuration object to the function:

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

In this snippet, we initialize and populate an object for :doc:`IncrementalPickConfig </api_ref/viewing/classes/Communicator.IncrementalPickConfig>` to store selection options that will be passed to the selection function. This configuration is simply the default settings, except the setting :js:attr:`mustBeFullyContained <Communicator.IncrementalPickConfig:mustBeFullyContained>`, which we've set to true to specify that no objects that are partially outside of the selection area should be contained within our selection results.

The function :ref:`beginScreenSelectByArea() <api_ref/viewing/classes/Communicator.SelectionManager:beginscreenselectbyarea>` returns a promise, which resolves into another function that recursively iterates through the model's entities by calling :ref:`advanceIncrementalSelection() <api_ref/viewing/classes/Communicator.SelectionManager:advanceincrementalselection>` until there are no more parts to select, at which point it returns false to stop the iteration.

The result of this process is that our :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` instance now contains an array of :doc:`NodeSelectionItems </api_ref/viewing/interfaces/Communicator.Selection.NodeSelectionItem>` that can be accessed via methods in the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` class, such as :ref:`getResults() <api_ref/viewing/classes/Communicator.SelectionManager:getresults>`.


Ray drill selection
-------------------

Also, part of the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` class, the :ref:`beginRayDrillSelection() <api_ref/viewing/classes/Communicator.SelectionManager:beginraydrillselection>` function uses a ray origin and box radius to create a frustum that will drill deep into the model (as opposed to selecting the first non-occluded item, as in :ref:`pickFromPoint() <api_ref/viewing/classes/Communicator.View:pickfrompoint>`).

Like :ref:`beginScreenSelectByArea() <api_ref/viewing/classes/Communicator.SelectionManager:beginscreenselectbyarea>`, :ref:`beginRayDrillSelection() <api_ref/viewing/classes/Communicator.SelectionManager:beginraydrillselection>` uses an incremental process, iterating through the model's instances and aggregating the results:

.. literalinclude:: /../../applications/client/docs/PG_Viewing_Selection_and_Picking.ts
   :start-after: //! [webviewer_raydrillselection]
   :end-before: //! [webviewer_raydrillselection]
   
In this example, we're setting our ray in the middle of the canvas and passing that 2D point to the :ref:`beginRayDrillSelection() <api_ref/viewing/classes/Communicator.SelectionManager:beginraydrillselection>` along with a handful of configuration settings in the :doc:`PickConfig </api_ref/viewing/classes/Communicator.PickConfig>` object.

The result of this process is that our :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` instance now contains an array of ``NodeSelectionItems`` that can be accessed via methods in the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` class, such as :ref:`getResults() <api_ref/viewing/classes/Communicator.SelectionManager:getresults>`.

The ``pixelBoxRadius`` setting specifies the proximity around the ray for selecting parts (the higher the value, the more inclusive the selection).

The recursive pattern used to aggregate the selection items is effectively the same as discussed in the section above for the :ref:`beginScreenSelectByArea() <api_ref/viewing/classes/Communicator.SelectionManager:beginscreenselectbyarea>` function.

Note that ray drill selection is actually selection by volume since the ray origin and the box radius you provide are used to create a frustum which is then intersected with the model to determine the selection results. This has the consequence that the :doc:`NodeSelectionItems </api_ref/viewing/interfaces/Communicator.Selection.NodeSelectionItem>` returned by :ref:`advanceIncrementalSelection() <api_ref/viewing/classes/Communicator.SelectionManager:advanceincrementalselection>` will not have selection positions attached to them, since they were not selected at a single point. This is also the case for all other volume selections.


Polyhedron selection
--------------------

Below is a sample of volume selection using the :ref:`beginConvexPolyhedronSelection() <api_ref/viewing/classes/Communicator.SelectionManager:beginconvexpolyhedronselection>` function from the :doc:`SelectionManager </api_ref/viewing/classes/Communicator.SelectionManager>` class. Here we're defining a volume by creating a box with six planes:

.. literalinclude:: /../../applications/client/docs/PG_Viewing_Selection_and_Picking.ts
   :start-after: //! [webviewer_polyhedronselection]
   :end-before: //! [webviewer_polyhedronselection]
   
Our first step is to define a function to create our planes. In this case, we're using :ref:`createFromPointAndNormal() <api_ref/viewing/classes/Communicator.Plane:createfrompointandnormal>` to create our planes, threrfore, it's only required that we provide a single point and a normal.

Once the planes have been defined, we simply need to pass them to :ref:`beginConvexPolyhedronSelection() <api_ref/viewing/classes/Communicator.SelectionManager:beginconvexpolyhedronselection>` along with the ``heuristicOrigin`` for calculating distances for ordering our results. Often, this will be the center of the volume you've defined, and in this case, we're using the origin, although other values may be preferred.

The recursive pattern used to aggregate the selection items is effectively the same as discussed in the section above for the :ref:`beginScreenSelectByArea() <api_ref/viewing/classes/Communicator.SelectionManager:beginscreenselectbyarea>` function.

