next up previous contents
Next: Molecule objects Up: Display objects Previous: Colors.

Picking Items.

The action of picking graphical objects with a pointer, like clicking on an atom with the mouse, is handled by the Display objects as well. Picking objects requires that VMD know where all the points are in space that may be selected, where the pointer is located when a button is pressed, and what to do once an item is picked. This is managed by objects derived from three `picking' base classes: Pickable, PickList, and PickMode, which are discussed below.

Each Displayable object is derived from the Pickable base class; a Pickable is an object which contains a drawing list with special DispCmd tokens which indicate ``this is a point in space which may be selected''. These picking tokens do not result in anything being drawn on the screen; they are used by the Displayable::(void *) routine to determine if a pointer is over a selectable item. Each picking token contains also an integer tag, which is returned by the picking routine when the pointer is found over an item. When a Displayable wants to put picking tokens in its display list, and then wants to be have its display list be checked for pickable points, it must register with a PickList object (described below). This is done by calling the routine Pickable::_with_picklist(PickList *)

in the constructor of the Displayable, using the pointer to the Scene in which the Displayable is registered (this is because Scene is derived from PickList). There are several virtual functions which must be provided by an object derived from Pickable, which will be discussed below.

There are two types of pointers which may be used to pick items, 2D or 3D. 2D pointers (i.e. the mouse) report their position in `relative scaled coordinates', that is, the X and Y position of the mouse is provided to the rest of the program as values in the range 0 ... 1, so that the lower-left corner of the graphics window is (0,0), and the upper-right corner is (1,1). The coordinates of 3D pointers, on the other hand, are given to the rest of the program as just the location of the pointer in 'eye' coordinates, i.e. the 3D position after it has been transformed by any internal transformation matrix of the pointer. Each pointing device (the mouse, 3D spatial trackers, etc) must be in a certain picking mode, which determines what action is done when an item is picked; new modes can be easily added to a central source by any object that wants to extend the usability of the picking mechanism. A picking operation consists of three phases:

  1. Start: when a button is pressed by a pointer, a command is issued which checks to see if something is under the current pointer position. If so, a new picking operation is started, and continues until the button (or whatever the pointer is using) is released.
  2. Moving: As the button is held down, if the start of the picking operation did indeed find something under the pointer, commands are executed as the pointer moves to allow objects to be continually manipulated by the pointer.
  3. End: When the button is released, some final action may be required, and this is signaled by a command to end the current picking session.
The effect on objects during these phases may be dependent on which button was pressed (two buttons, left and middle, are assumed), and what the current mode was when the button was pressed. PickMode objects are used to handle the different actions required for different picking modes.

Each picking mode is embodied by a special derivation of the PickMode abstract base class. An example, PickModeQuery, has been added which does the very simple job of just printing out the name of the Pickable object when the picking is ended (and only if the pointer position does not move much between the start and end). Each PickMode simply contains three virtual functions:

  1. PickMode::_start(DisplayDevice *, Pickable *, int button, int tag, int dim, float *pos)
    When a pick is successfully started (which means the tag of the point which was picked has been determined), this routine is called for the PickMode object corresponding to the current pick mode, to let that object perform some special action based on the selection. The item selected is provided, as is the button pressed, the dimension (2 or 3) and position of the pointer, and the DisplayDevice used to find the selected item (this is necessary to allow access to routines which convert 2D screen positions to 3D world coordinates). Finally, the tag of the point in the Pickable that was actually clicked on is provided (more on this later).
  2. PickMode::_move(same args)
    Again, called only for the PickMode object of the current mode for the pointer used; this is called every time the pointer moves to a new position.
  3. PickMode::_end(same args)
    Same as the others, just called when the pointer button is released.

A PickList object contains a list of all the current picking modes which the mouse may be in; these all have unique id's from 0 ... num_modes - 1. The Mouse object (described in a later section) gets this list and adds a submenu to the graphics window pop-up menu. When the mouse is in a picking mode, the cursor changes to a crosshair. The Scene is derived from PickList; it is the PickList which maintains all the coordinating data to manage all the objects which can be picked, and all the different picking modes. The PickList maintains two lists:

  1. All the Pickable objects which have registered themselves as items which contain points which can be selected with a pointer.
  2. All the PickMode objects which are used to provide different action capabilities to the same pointer, in an extendible fashion.
The pointer objects call routines in PickList to get the current number of names of picking modes, to check if the current pointer position is over a pickable point (and to find out which one), to tell the program that the pointer is moving while an object is being picked, and to tell the program that the button has been released following a picking operation. Thus, PickList is the ``coordinator'' for all picking operations. PickList contains a routine similar to the draw routine, but which instead checks for picked item and executes the proper action if one is found. The algorithm used is:
  1. For each Pickable registered, check if it is interested in the current mode. If so, call Pickable::_start(see later). If not, skip the Pickable and go to the next. 2) Then, call PickMode::_start(f)or the PickMode object corresponding to the current pick mode.

To set up a Displayable to operate properly as a useful Pickable, these things must be added to the Displayable (see Axes.C and Axes.h for a good example of how to do these things).

A key thing that may be needed during the pick_move phase for both Pickable and PickMode objects is the ability to convert a 2D screen coord (the relative scaled coords x and y, valued 0 ... 1) to a 3D world coordinate. The difficult of course is the abiguity in what the Z-axis coordinate should be. The routine DisplayDevice::_3D_from_2D(float *A3D, float *B2D, float *B3D) takes a 3D world coordinate (at point A, A3D), and a 2D relative scaled coordinate (the screen position of point B, B2D), and returns the 3D world coordinate for point B (B3D). This works assuming the eye is looking along the Z axis. The coordinate returned is the point where the line formed by the 2D's projection back into 3D space intersects the plane parallel to the XY plane which contains point A (i.e. the point will have the same Z-coordinate as the given point A).


next up previous contents
Next: Molecule objects Up: Display objects Previous: Colors.

Justin Gullingsrud
Tue Apr 6 09:26:48 CDT 1999