=========
Selection
=========

This section reviews the interface for selecting objects in the |HPSNOW| database. The APIs covered here are fairly low-level, so if you need a ready-made solution that takes care of selection details, you are encouraged to use a :doc:`selection operator <0601_standard_operators>`.

The |HPSNOW| selection process involves the following steps:

* Your application receives selection-location information from the GUI, based on user input
* Your application calls |HPSNOW| selection routines whose arguments specify a selection point, ray, rectangle, polyline, polygon, volume or shell. The ``HPS::SelectionControl`` class is available from ``HPS::WindowKey``, and provides the various SelectBy[type] methods.
* |HPSNOW| returns the selection results to you via ``HPS::SelectionResults``
* Your application code operates on the selection results. It may highlight, edit, delete and/or query the selected item(s). Note that in addition to selection operators, :ref:`highlight operators <prog_guide/0604_highlighting:Using a highlight operator>` are also available.


.. _060101:

High-Level Selection Considerations
===================================

|HPSNOW| supports various selection options that allow you to control what should be selected, and to make selection faster and thus more interactive for the user. These are important, as selection can be computationally intensive over large datasets. |HPSNOW| can also return results much faster if you set up filters to exclude geometry that you aren't interested in.

The ``HPS::SelectionOptionsControl`` class is available from a ``HPS::WindowKey``. Alternatively, you can specify the options in a ``HPS::SelectionOptionsKit`` and pass it into the variants of the ``HPS::SelectionControl::SelectBy[type]`` methods that accept a ``HPS::SelectionOptionsKit``.

The ``SelectBy[type]`` methods all perform a selection based on a start segment. The start segment and the contents of all descendant segments will be tested against the selection criteria. This is an optimization you can use if you know your selection should be restricted to a certain subtree. The start segment is set using the ``HPS::SelectionOptionsKit::SetScope`` method. The method also accepts a ``HPS::KeyPath`` object which can be used to initialize a start segment that's not under a window key. It is expected to be a path, from leaf to root, through any number of include segments. The leaf is the start segment and the root is the window key.

**NOTE:** Setting any selection options with the ``HPS::SelectionOptionsKit::SetSelectability()`` method will override any selection options under either the model keys or segments.

Algorithm
---------

``HPS::SelectionOptionsControl::SetAlgorithm`` allows you to choose between two types of selection algorithms: *analytic* and *visual*. 

*Analytic selection*

This is the default selection algorithm, and is based on a projection from the camera position (or other arbitrary position) through a point or points in world coordinates. It does not ignore objects which are obscured by other objects, but will return the list of objects that are intersected by the provided selection information. It also sorts the objects from back to front (relative to viewpoint space) so that the object foremost in the view will be first in the list of selection results.

In some situations, this can give unwanted results. For example, if both faces and edges are visible and selectable, and you select slightly to the side of the front-most visible edge of a cube, it's possible that the 'best' edge returned by |HPSNOW| be the back side edge, even though it is obscured. This is because the application fires a ray through the scene, and the ray may end up directly hitting the backside edge or coming closest to it. To avoid this scenario, you can instruct the system to use the visual selection algorithm described below.

*Visual selection*

If you only want visible objects to be selectable, then the visual selection algorithm can be specified. Visual selection performs a frame-buffer based postprocess of the selected items to remove obscured items from the selection list. It is important to note that visual selection is more algorithmically intensive than analytic selection.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [selection_algorithm]
		   :end-before: //! [selection_algorithm]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [selection_algorithm]
		   :end-before: //! [selection_algorithm]
		   

Selection Level
---------------

Before doing any sort of selection, it is important to configure the selection level because this directly affects the selection results. Selection level is controlled by calling ``HPS::SelectionOptionsControl::SetLevel``, which in turns allows you to chose from three different levels. An example of setting the selection level is shown :ref:`here <060102>`.

**NOTE:** Cylinders and spheres are a special type of primitive geometry. They are dynamically tessellated, and therefore their subentities are not selectable. If you try to do subentity selection on a sphere or cylinder, the entity key will be returned but there will be no subentity information.


Proximity
---------

In addition to the selection level, the proximity also has a large impact on returned results. The selection proximity is a floating point value that augments a point-based selection by also including the area immediately surrounding the selection point (point-based selection is sometimes referred to as 'aperture' selection). The proximity is specified in real-world centimeters. To disable, set the proximity to zero.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [proximity]
		   :end-before: //! [proximity]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [proximity]
		   :end-before: //! [proximity]

**NOTE:** Proximity has no effect in :ref:`area and volume selections <060104>`.


Granularity
-----------

The granularity of a selection determines whether the selection test is performed on the exact shape of certain entity types. One exception is a line segment or polyline. For lines, a ``Detailed`` selection granularity has an effect when the line has a special pattern or heavy weight. For example, in a dashed line, the dashes would be selectable but the space between them would not. For a heavy weight line, the increased line thickness actually becomes part of the selectable region of the line.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [granularity]
		   :end-before: //! [granularity]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [granularity]
		   :end-before: //! [granularity]

Using ``General`` granularity will typically provide the best performance.


.. _060102:

Selection By Point and Ray
==========================

A point selection is one of the simplest types of selection and is performed by calling ``HPS::SelectionControl::SelectByPoint``. It is based on a window-space point, and any objects underneath the projected point are returned as potential selection objects, even if they are obscured by geometry in the foreground. 

For this example, we are using the pixel coordinates of an imaginary mouse click, then converting those pixel coordinates to window space. Note that this example sets up the selection options using the ``HPS::SelectionOptionsControl``.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [selection_by_point_example]
		   :end-before: //! [selection_by_point_example]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [selection_by_point_example]
		   :end-before: //! [selection_by_point_example]

In the code snippet above, the value returned by ``HPS::SelectionControl::SelectByPoint`` is the number of objects found in the selection. An entity-level selection was performed, so a collection of geometric entities would be expected. Likewise, if a segment-level selection was performed, a ``HPS::SegmentKey`` array would be returned. For an expanded example, :download:`click here <code/selection_example.cs>`.

The objects themselves can be accessed through the ``HPS::SelectionResults`` object as shown below:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [selection_results]
		   :end-before: //! [selection_results]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [selection_results]
		   :end-before: //! [selection_results]

**IMPORTANT:** Using the ``Type()`` function has performance implications. Please see our section on :ref:`using keys <prog_guide/0102_api_conventions:Identifying keys>` for details.


Selection By Ray
----------------

A similar type of selection is also available - ``HPS::SelectionControl::SelectByRay``. Selection by ray is similar to selection by point, but can perform a selection based on any arbitrary ray. 

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [selection_by_ray_example]
		   :end-before: //! [selection_by_ray_example]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [selection_by_ray_example]
		   :end-before: //! [selection_by_ray_example]
		   

.. _060104:

Selection By Area and Volume
============================

Two other ways to perform a selection are by area and by volume. An area selection is achieved by specifying a rectangle in window space. The snippet below shows the basic procedure, and in this example, note that the selection options are set up in a ``HPS::SelectionOptionsKit``, which is then passed into a different variant of ``HPS::SelectionControl::SelectByArea`` method:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_select_by_shell.cpp
		   :start-after: //! [selection_by_area_example]
		   :end-before: //! [selection_by_area_example]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_select_by_shell.cs
		   :start-after: //! [selection_by_area_example]
		   :end-before: //! [selection_by_area_example]
		   
We should note that selecting by area will project the selection area through 3D space, and thus forms a selection frustum with infinite near and far planes. Similarly, a volume selection will select entities within a cuboid volume. Specify the two opposite corners of the cuboid to select against:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_select_by_shell.cpp
		   :start-after: //! [selection_by_volume_example]
		   :end-before: //! [selection_by_volume_example]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_select_by_shell.cs
		   :start-after: //! [selection_by_volume_example]
		   :end-before: //! [selection_by_volume_example]
		   
		   
.. _subentity_selection:

Sub-Entity Selection
====================

Subentities are the faces, edges, and vertices that make up geometry. |HPSNOW| supports subentity selection for shells and meshes. Some functionality is also available for lines, text, polygons, and NURBS curves.

The framework for selecting subentities is similar to entity-level selection. The only difference during the selection stage is setting the selection level as ``HPS::Selection::Level::Subentity``. 

However, during the retrieval stage, you also need to explicitly get the subentities. Faces, vertices, and edges are returned in separate arrays. Note that edges are returned in two parallel arrays where the edge is defined by its corresponding endpoints in each array. The point in the first array is considered the closer match to the selection criteria.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_options.cpp
		   :start-after: //! [subentity_selection]
		   :end-before: //! [subentity_selection]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_options.cs
		   :start-after: //! [subentity_selection]
		   :end-before: //! [subentity_selection]
		   
Please note that as with all ``Show()`` functions, if the information is undefined or non-existent, the function will return ``false``. Accordingly, for entities other than shells or meshes, the following conditions apply:

* Polygon: ``ShowEdges()` will return only the nearest single edge, and ``ShowVertices()`` will return only the nearest single vertex. ``ShowFaces()`` is not supported.
* NURBS Curve: Only ``ShowVertices()`` is supported, and it will return the nearest single control point.
* Text: Only ``ShowCharacters()`` is supported, and it will return the nearest character in the text string.
* Lines: Only ``ShowEdges()`` is supported, and it will return all the line segments (defined by pairs of points) that were selected.


.. _060103:

Collision Detection
===================

It may be necessary to determine if a piece of geometry intersects a particular shell. This is commonly referred to as collision or clash detection. Detecting intersections between shells is implemented as another form of selection - *selection by shell*. Selection by shell is always performed as an analytic selection.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_select_by_shell.cpp
		   :start-after: //! [selection_by_shell_example]
		   :end-before: //! [selection_by_shell_example]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_select_by_shell.cs
		   :start-after: //! [selection_by_shell_example]
		   :end-before: //! [selection_by_shell_example]

The user provides a shell kit to ``HPS::Database::SelectByShell``, and |HPSNOW| uses it to calculate a selection on any intersecting faceted items within or below the start segment (faceted items include shells, meshes, NURBS surfaces, circles, ellipses, polygons, and polycylinders). The start segment can be set using ``HPS::SelectionOptionsKit::SetScope``. The selection process is subject, as usual, to selectability attributes. The return value indicates the number of items selected. The selection is always performed in world space, so the method does not need to be called from ``HPS::WindowKey``. If any transform needs to be applied to the points, it must be applied before calling ``SelectByShell``.

.. image:: images/5.1.a.png

*The cube will "select" the sphere using ``Database::SelectByShell``, indicating a collision is detected*

Also related to selection by shell is the :ref:`shell relation <prog_guide/0201_shells:Computing spatial relationships between shells and points>` interface, used to determine spatial relationships between shells and point sets.


.. _proximity_collision:

Proximity Value for Collision Detection
---------------------------------------

When performing a selection by shell, the selection proximity has a slightly different meaning from the proximity value of other selection methods. In this context, a positive proximity value of *x* will cause the selection algorithm to detect a collision when the distance between the two bodies is *x* or less. This means the bodies do not have to be touching in order for |HPSNOW| to detect a collision.

If the proximity value is equal to 0, the bodies must be coincident or penetrating for a collision to be detected. When the proximity value has a negative value, for example, *-10*, the bodies must penetrate each other at least *10* units before a collision is detected.

In the following diagram, the objects are separated by 0.08 units. Normally, this is not a collision. However, it would be detected as such if the selection proximity value was 0.08 or greater.

.. image:: images/collision-detection-1.png

*Illustrating collision detection*

Below, the objects penetrate each other to a depth of 0.16. This is a collision in all cases except for selection proximity values less than -0.16.

.. image:: images/collision-detection-2.png

*Illustrating collision detection*


.. _treecontext:

Using a TreeContext to Improve Performance
------------------------------------------

Use of a ``HPS::TreeContext`` may be beneficial when selecting by shell. If many shell selections are going to be performed without modifying the segment tree, using an ``HPS::TreeContext`` can significantly boost performance if you have many selections to perform between modifying the segment hierarchy. If a tree is not specified, a new one is computed each time a selection is performed. To use the tree context with your selection, simply instantiate a ``HPS::TreeContext`` object and pass it to ``HPS::SelectionOptionsKit::SetTreeContext``.


.. _060105:

Filtering Selection Results
===========================

So far, we've discussed different selection algorithms, as well as different ways to select objects. There are also several ways to limit selection results to a subset of scene geometry.


.. _using_selectability_control:

Selectability
=============

The ``HPS::SelectabilityControl`` allows you to specify which types of geometry (markers, vertices, edges, lines, faces) and what aspects of the scene (windows, lights) are actually selectable by the selection routines. If the selectability of a type of scene-graph item is disabled, then the selection routines will not select on them, thereby filtering results and speeding up the overall selection process.

Let's look at a sample case. Imagine we have a large amount of faceted geometry represented by shells, and the faces, edges, and vertices are all visible - but we only want to select the faces. We would use the ``HPS::SelectabilityControl`` to indicate that all items except for faces are selectable. The easiest way is to first call ``HPS::SelectabilityControl::SetEverything(false)`` to turn everything off, and then turn on selectability just for faces.

If a geometry type is not currently visible (due to the ``HPS::VisibilityControl`` having been used to indicate that its visibility is off), then the selection routines will not select that type. If you want the selection routines to still select items even if their visibility is set to off, you must specify the ``HPS::Selectability::Value::ForcedOn`` value for those types, when calling one of the ``HPS::SelectabilityControl`` 'Set' methods.


.. _related_limit:

Related Limit
-------------

When doing entity-level or segment-level selection, another way to limit results is to use ``HPS::SelectionOptionsKit::SetRelatedLimit``. This directive instructs the selection mechanism to limit the number of objects that are selected and returned. For example, setting the related limit to 2 means that only 2 items will be returned, with preference based on proximity to the selection point (if proximity applies). This can be used in conjunction with the ``HPS::SelectabilityControl``.

.. _internal_limit:

Internal Limit
--------------

This limits the number of subentities for shells and meshes that will be returned if performing subentity selection, and is set via ``SelectionOptionsKit::SetInternalLimit``.

The following code sample demonstrates these three selection options:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_select_by_shell.cpp
		   :start-after: //! [limiting_enhancing]
		   :end-before: //! [limiting_enhancing]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_select_by_shell.cs
		   :start-after: //! [limiting_enhancing]
		   :end-before: //! [limiting_enhancing]
		   

.. _selection_culling:

Selection Culling
-----------------

|HPSNOW| offers various types of :ref:`culling <prog_guide/0703_performance_considerations:Culling optimizations>` to improve rendering performance. You have the ability to control whether culled objects are selectable using the ``HPS::SelectionOptionsKit`` or ``HPS::SelectionOptionsControl``. If selection culling is disabled, |HPSNOW| will consider culled objects when processing a selection event. As a result, the user could end up highlighting culled geometry, suddenly making it appear visually in the scene or as an entry in selection results.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_selection_culling.cpp
		   :start-after: //! [selection_culling]
		   :end-before: //! [selection_culling]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_selection_culling.cs
		   :start-after: //! [selection_culling]
		   :end-before: //! [selection_culling]

Selection culling can be used with deferral extent, extent, frustum, and vector culling.

.. _boolean:

Boolean Operations on Selection Results
---------------------------------------

Selection results may be further refined or augmented by applying Boolean operations to two ``HPS::SelectionResults`` objects. Operations include union, intersection, difference, and symmetric difference. These operations are especially useful during user interaction.

For example, let's say the user has performed an area selection and was returned a set of results. Before applying his operation, he notices there is a single object that does not belong in the selection set. It is common to expect the ability to hold CTRL (or another modifier key) and click a selected object to deselect it.

Programmatically speaking, both the first area selection and the second CTRL-click selection would each be represented by a single ``HPS::SelectionResults`` object. As the developer, you can call ``HPS::SelectionResults::SymmetricDifference`` to remove the second selection set from the first.

You can also expect this behavior to happen automatically when using a selection operator. When control is held, the ``HPS::SelectAreaOperator`` will perform a union with the another results object, and the ``HPS::SelectOperator`` will perform a symmetric difference (exclusive OR). 

The Boolean operations only work for selections that were performed at the same selection level. For example, trying to apply a Boolean operation to an entity-level selection and a segment-level selection will not work.


.. _selection_operator:

Using a Selection Operator
==========================

The purpose of the selection operator is to perform a selection at a particular pixel in the window. This usually means at the mouse cursor or at the location of a touch-screen event. If you have some special selection mechanism that isn't covered by these input events, you are free to perform a manual selection or create your own :doc:`custom operator <0602_custom_operators>`.

When using the ``HPS::SelectOperator`` or ``HPS::SelectAreaOperator``, you push them onto the operator stack just like any other operator. When selection is performed, results are returned to you in a ``HPS::SelectionResults`` object. Once you have the results, you can parse them according to your needs. An example of how to do that is demonstrated :ref:`here <060102>`.

You can control how the selection is performed by configuring a ``HPS::SelectionOptionsKit`` and setting it on the operator. The kit controls things such as internal limit, level, and proximity. The selection process is detailed in following snippet:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_select_operator.cpp
		   :start-after: //! [select_operator]
		   :end-before: //! [select_operator]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_select_operator.cs
		   :start-after: //! [select_operator]
		   :end-before: //! [select_operator]

Note that the ``HPS::SelectOperator`` does not provide visual feedback. If you need visual feedback, see the next section for how to use the ``HPS::HighlightOperator``.
