Picking

Picking allows users to select and interact with objects in the 3D scene. Picks are usually executed in response to a mouse click, mouse move, key press, or any combination of these. For picking on screen overlays, see the Screen Overlays Overview.

Topic Description
Pick Regardless of the triggering event, a pick is always executed with Scene.Pick.
Normal Picking Commonly used to zoom to a primitive or bring up a context menu.
Roll-over Picking Used to select objects or display the cursor's cartographic position over a globe as the mouse moves across the window.
Drill Picking Used when the same location is clicked or double clicked a second time so that the object under the top object can be acted upon.

Pick

The Scene.Pick method returns information about objects in the scene that are at a specified pixel. The input is an x and y coordinate. The origin is the top, left corner of the 3D control. In most cases, the input to Pick will be the location of the mouse cursor to pick objects under the cursor. This section explains the collection returned by Pick; the following sections describe how to use Pick to implement different types of picking.

Pick returns a collection of pick results, PickResults. Each pick result, PickResult, represents one occurrence of a pick. This includes the object(s) involved in the pick and their position. This is shown in the image below.

If multiple objects are at a pixel, the collection will contain multiple pick results. The first item in the collection will be the top most object. Subsequent items will be "under" the previous item. For example, if the camera is looking straight down at a primitive on the ground and Pick is called with coordinates that match the primitive, both the primitive and central body will be returned as shown below.

[C#] Copy Code
IAgStkGraphicsPickResultCollection collection = scene.Pick(x, y);

if (collection.Count == 2)
{
     IAgStkGraphicsPrimitive primitive = collection[0].Objects[0] as IAgStkGraphicsPrimitive;

     if (primitive != null)
     {
          // primitive was picked
     }
}

In other cases, the collection will only contain a single pick result. For example, if a model primitive representing a satellite is picked, the central body may not be returned as shown below.

[C#] Copy Code
IAgStkGraphicsPickResultCollection collection = scene.Pick(x, y);

if (collection.Count == 1)
{
     IAgStkGraphicsModelPrimitive model = collection[0].Objects[0] as IAgStkGraphicsModelPrimitive;

     if (model != null)
     {
          // Just a model primitive was picked
     }
}

As shown in the code examples, a pick result contains a collection of objects. In most cases, this collection will only contain one object. One exception is when a picked primitive is in a composite. In this case, both the primitive and its composite will be in the objects collection as shown in the following image and code example.

[C#] Copy Code
IAgStkGraphicsPickResultCollection collection = scene.Pick(x, y);

if (collection.Count == 2)
{
     IAgStkGraphicsObjectCollection objects = collection[0].Objects;

     if (objects.Count == 2)
     {
          IAgStkGraphicsCompositePrimitive composite = objects[0] as IAgStkGraphicsCompositePrimitive;
          IAgStkGraphicsPrimitive primitive = objects[1] as IAgStkGraphicsPrimitive;

          if (composite != null &&
          primitive != null)
          {
               // A primitive in a composite was picked
          }
     }
}

For primitives that contain multiple items, like the MarkerBatchPrimitive, TextBatchPrimitive, PointBatchPrimitive, and PolylinePrimitive, it is often useful to know what particular item was picked. Per item picking can be enabled for these primitives by setting the PerItemPickingEnabled property on the primitive to true. When enabled, the object collection will also contain the index of the item in the primitive that was picked, as shown in the following image and code example.

[C#] Copy Code
IAgStkGraphicsPickResultCollection collection = scene.Pick(x, y);

if (collection.Count == 2)
{
     IAgStkGraphicsObjectCollection objects = collection[0].Objects;

     if (objects.Count == 3)
     {
          IAgStkGraphicsCompositePrimitive composite = objects[0] as IAgStkGraphicsCompositePrimitive;
          IAgStkGraphicsPrimitive primitive = objects[1] as IAgStkGraphicsPrimitive;
          IAgStkGraphicsBatchPrimitiveIndex index = objects[2] as IAgStkGraphicsBatchPrimitiveIndex;

          if (composite != null &&
          primitive != null &&
          index != null)
          {
               // An item in a primitive in a composite was picked
          }
     }
}

Normal Picking

In normal picking, Pick is called as the result of an event, such as a mouse click in the 3D control, to perform an action, such as zooming to a primitive. This is demonstrated by the following example from the GraphicsHowTo:

[C#] Copy Code
//
// Get a collection of picked objects under the mouse location.
// The collection is sorted with the closest object at index zero.
//
IAgStkGraphicsPickResultCollection collection = scene.Pick(mouseX, mouseY);
if (collection.Count != 0)
{
     IAgStkGraphicsObjectCollection objects = collection[0].Objects;
     IAgStkGraphicsCompositePrimitive composite = objects[0] as IAgStkGraphicsCompositePrimitive;

     //
     // Was a model in our composite picked?
     //
     if (composite == m_Models)
     {
          IAgStkGraphicsModelPrimitive model = objects[1] as IAgStkGraphicsModelPrimitive;
          ViewHelper.ViewBoundingSphere(scene, root, "Earth", ((IAgStkGraphicsPrimitive)model).BoundingSphere, -90, 15);
          scene.Render();
     }
}

This code snippet is called in response to a double click event in the 3D control. A pick is executed using the current position of the mouse cursor. If the collection returned is empty, nothing was picked. Otherwise, since we only want to zoom to a model if it is in our composite, the topmost picked object is checked to see if it is the instance we expect. If the topmost picked object was something else, perhaps because only the central body was picked, the zoom will not occur.

Roll-over Picking

In roll-over picking, Pick is called in response to the mouse moving across the 3D control. The results of the pick may be used to display the mouse cursor's cartographic position over a globe or to highlight the primitive under the cursor, as shown in the following example from the GraphicsHowTo:

[C#] Copy Code
//
// Get a collection of picked objects under the mouse location.
// The collection is sorted with the closest object at index zero.
//
IAgStkGraphicsPickResultCollection collection = scene.Pick(mouseX, mouseY);
if (collection.Count != 0)
{
     IAgStkGraphicsObjectCollection objects = collection[0].Objects;
     IAgStkGraphicsCompositePrimitive composite = objects[0] as IAgStkGraphicsCompositePrimitive;

     //
     // Was a model in our composite picked?
     //
     if (composite == m_Models)
     {
          IAgStkGraphicsModelPrimitive model = objects[1] as IAgStkGraphicsModelPrimitive;

          //
          // Selected Model
          //
          ((IAgStkGraphicsPrimitive)model).Color = Color.Cyan;

          if (model != selectedModel)
          {
               //
               // Unselect previous model
               //
               if (selectedModel != null)
               {
                    selectedModel.Color = Color.Red;
               }
               selectedModel = model;
               scene.Render();
          }
          return;
     }
}

//
// Unselect previous model
//
if (selectedModel != null)
{
     selectedModel.Color = Color.Red;
     selectedModel = null;
     scene.Render();
}

m_SelectedModel is a reference to the currently highlighted model, that is, the model currently under the cursor. Initially, it is null. Pick is called with the mouse cursor's position in response to a mouse move event.

The model under the cursor is highlighted by setting its color to cyan. The previously selected model is set to red. Note that a model may be unhighlighted because either another model is now under the cursor or no model in the composite in under the mouse cursor. Since redrawing the scene every time the mouse moves may affect performance, the scene is only redrawn (via scene.Render) if a model is highlighted or unhighlighted.

Drill Picking

Drill picking is used to "drill down" to objects underneath the top object. For example, the first time a user double clicks, the top object is picked. If the mouse doesn't move and the scene doesn't change (e.g. primitives aren't added or removed), the second time the user double clicks, the object underneath the top object is picked. And so on.

This is implemented using the Pick method. The collection from the first call is saved and the closest object, the object at index 0 in the collection, is the picked object. The next time a pick occurs (e.g. next double click), if the mouse position and scene did not change, the picked object is now at index 1 in the collection. Typically, the index will roll back to 0 once it goes all the way through the collection.

Rectangular Picking

Rectangular, or rubber band picking, is used to pick objects within a rectangular region. For example, when a 100 by 100 rectangle is picked, all the objects within that rectangle will be returned.

Rectangular picking is provided by the Scene.PickRectangular method. The below code snippet executes a rectangular pick, and then iterates through all of the objects that were contained within that rectangle.

[C#] Copy Code
IAgStkGraphicsPickResultCollection collection = scene.PickRectangular(mouseX - 50, mouseY + 50, mouseX + 50, mouseY - 50);
foreach (IAgStkGraphicsPickResult pickResult in collection)
{
     IAgStkGraphicsObjectCollection objects = pickResult.Objects;
     IAgStkGraphicsCompositePrimitive composite = objects[0] as IAgStkGraphicsCompositePrimitive;

     if (composite == modelsComposite)
     {
          //
          // A model in our composite was among the items that were picked
          //
          IAgStkGraphicsModelPrimitive model = objects[1] as IAgStkGraphicsModelPrimitive;
     }
}

STK Programming Interface 11.0.1