This chapter describes the cxPick data type and how to use it in the Explorer environment. It defines the data type and describes how you can use it to write modules that read or write pick data. This is a specialized data type and requires a fairly sophisticated module writer to understand it. In general, you should be able to use the standard Explorer modules that accept and manipulate the cxPick data type for most of your needs. They include Render, QueryLat, Displayimg, and MoleculeBuilder.
The API (Application Programming Interface) routines are listed and there are examples of user function code for writing modules that manipulate pick data.
The data type described here, cxPick, can be used in two kinds of modules: those that read cxPick data objects on their input ports, and those that write cxPick data objects through their output ports.
The purpose of the cxPick data type is to enable the user to pick, or select, a particular location in a module display window and obtain information about it. cxPick is a specialized data type, used only in 2-D and 3-D modules.
You can obtain information about an image in the window of a module that displays images (2-D), or a geometry object in the window of a rendering module (3-D).You do this by using the mouse to select items out of a picture in a module display window. For example, you may want to query part of a picture of an isosurface. You could find the coordinates of a spot on the surface or the temperature at that point. The window in which the isosurface is displayed can be in the Render module, in DisplayImg, or in your own rendering module, all of which have Pick output ports.
You can send the information you have picked in the Render or DisplayImg window to a module with a Pick input port, such as PrintPick.
You can also create an object where one did not previously exist, or position an object in a particular location in a rendering module display window. As you click on the position in the window, the information goes to the upstream module, which creates an object, for example a line or an atom, and sends it to the selected position in the Render window.
There are two points to note about the cxPick data type:
It is considerably easier to write modules that read cxPick data sent downstream by modules such as DisplayImg or Render than it is to write modules that generate pick data.
If you write a pick module which outputs pick data, you need to write your own user interface using X Windows, GL, or a toolkit on top of these. This is because none of the Explorer widgets supply pick information.
You can use cxPick in any module that you want to output information about geometry objects, and in any module that you want to receive this information. In the Explorer module suite, for example, the QueryLat, PrintPick, and MoleculeBuilder modules all have cxPick on their input ports and can therefore read pick data. The Render module can write pick data to its Pick output port and hence feed information back to the QueryLat and MoleculeBuilder modules.
Module users can activate Pick mode in a Render window by selecting “User Pick Mode” from the Viewing Menu and toggling the “eye” icon to turn off viewing mode. To use Pick mode in a DisplayImg window, they simply press the middle mouse button.
The cxPick data type provides a vast amount of data, as you can see from its data type structure in Figure 6-1. It takes some thought to decide exactly what you want cxPick to do for you. There are two ways in which module writers commonly use cxPick; to build modules that read pick data, and to build modules that write pick data. Further, your module could read pick data from either an image (2-D) or from geometry (3-D). Or it could write pick data obtained from an image or a geometry object.
Modules that read pick data need only inspect the components of the cxPick data structure in which the module has an interest. These modules, such as QueryLat and PrintPick, receive the data from a module that writes pick data.
For example, QueryLat reads information about the position of the mouse cursor relative to a lattice in the Render window. It takes the information, generates a text label that contains the information, and sends the label back to the Render window for the user to see. The code is given in “Labeling Items in Scene Graphs” later in this chapter.
The Fortran example in “Reading Pick Data” also reads pick data. It lists the number of hits the user has made on an object, looks at the list, and builds a 1D lattice from the data in the list.
Modules that write pick data include the Render module and DisplayImg in Explorer. These modules tend to be more difficult to write because of the effort it takes to manage the user interface.
The variables in the cxPick data structure let you specify all the information you want to put into or get from the module. You may not need all the variables; for example, if you write a module that displays images, you will not need the variables that pertain to the picking of geometric objects. When you create the cxPick type, you should null out all the unfilled variables.
To make the function of each variable easier to understand, it helps to clarify some terms. A pick is what you do when you select a spot in the display window of a module by clicking the mouse on it. A hit is when you touch on part of an object or image, instead of empty space. A pick object is the object or image you touched on. A pick event is the act of picking the object, and it occurs when you press a mouse button or key, or drag the mouse across the window.
Once you have made a hit, you can gather a great deal of information about the object you hit. This information is laid out in the subtype, cxPickHit.
This is the data type definition:
root typedef struct
{
int eventType “Event Type”;
long eventData “Event Data”;
long eventModifiers “Modifier Keys”;
int position[2] “Position Array”;
int windowSize[2] “Window Size Array”;
float origin[3] “Ray Origin”;
float direction[3] “Ray Direction”;
float projectionMatrix[4, 4] “Projection Matrix”;
int numHits “Num Object Hits”;
cxPickHit hit[numHits] “Hits Array”;
} cxPick;
|
The variables are:
If the user does not hit any object in the module window, or if the window is empty, the variable numhits is zero and hits will contain no data.
If the user actually hits something, then a cxPickhit data structure will be filled in with information about the object or objects.
Figure 6-1 depicts the pick data type structure.
When the user presses a button in Pick mode and hits an object or image, the cxPickHit data structure can provide a lot of information about that object or image.
The data type definition is:
typedef struct
{
long id;
long validInfo;
float point[3];
float normal[3];
float color[3];
string label;
float localTransform[4, 4];
float globalTransform[4, 4];
cxPickObject objectType;
switch (objectType) {
case cx_pick_point:
long index;
case cx_pick_line:
long index[2];
float point[2, 3];
float normal[2, 3];
case cx_pick_face:
long nvertices;
long index[nvertices];
float point[nvertices, 3];
float normal[nvertices, 3];
case cx_pick_cone:
long part;
case cx_pick_cylinder:
long part;
} o;
} cxPickHit;
|
These are the variables:
![]() | Note: Not all fields are applicable to all objects. The bit masks for each field in validInfo are in the cxPickValid enumeration in /usr/explorer/include/cx/Pick.h |
| objectType | Tells you what kind of object sustained the hit. For some objects, including points, lines, faces, cones, and cylinders, you can collect information about indices, normals, vertices, and parts. |
Figure 6-2 shows the structure of the cxPickHit data type.
The QueryLat module is an example of how to label items in a scene graph. QueryLat responds to pick mouse button events by determining the lattice value at the first pick intersection and creating a label, which is text geometry, with that value. The value passes into Render through its annotation port and is displayed at the correct location in the Render window.
Figure 6-3 shows the “pick” map, which contains QueryLat. The map is distributed with Explorer and can be launched from the Module Librarian.
QueryLat takes as input a lattice and the pick data from the Render module. The input port of QueryLat has connections from ReadLat and the Render pick output. Its output port is wired into the Render “Annotations” input port. When you hold down the mouse button (in User Pick mode) on a point in the Render window, the value of the lattice at that point is displayed. If you pick on an empty part of the window, the value is null.
You can collect more information about certain types of hit objects from the Render module:
| xpoints | you can determine the index of the point that was hit | |
| lines | you can collect the indices of end-points and the normals at the end-points (if they exist) | |
| polygons | you can determine the number of sides, and the indices, locations, and normals of the vertices (3-D only) | |
| cones and cylinders |
side = 1 top = 2 bottom = 4 For cones, the part numbers are: side = 1 bottom = 2 |
The cxPick data type, though defined in the Explorer typing language, can be considered as a C structure. Fortran users need to set pointers to the data type structures when they use them. The type declaration resides in the header file /usr/explorer/include/cx/cxPick.h.
typedef enum {
cx_pick_none,
cx_pick_point,
cx_pick_line,
cx_pick_face,
cx_pick_sphere,
cx_pick_cone,
cx_pick_cylinder,
cx_pick_nurb,
cx_pick_splat,
cx_pick_other
} cxPickObject;
typedef struct cxPickHit {
long id;
long validInfo;
float *point;
float *normal;
float *color;
char *label;
float *localTransform;
float *globalTransform;
cxPickObject objectType;
union {
struct {
long index;
} cx_pick_point;
struct {
long *index;
float *point;
float *normal;
} cx_pick_line;
struct {
long nvertices;
long *index;
float *point;
float *normal;
} cx_pick_face;
struct {
long part;
} cx_pick_cone;
struct {
long part;
} cx_pick_cylinder;
} o;
} cxPickHit;
typedef struct cxPick {
cxDataCtlr ctlr;
int eventType;
long eventData;
long eventModifiers;
int *position;
int *windowSize;
float *origin;
float *direction;
float *projectionMatrix;
int numHits;
cxPickHit *hit;
} cxPick;
|
The Fortran type enumerations reside in /usr/explorer/include/cx/cxPick.inc.
INTEGER cx_pick_none INTEGER cx_pick_point INTEGER cx_pick_line INTEGER cx_pick_face INTEGER cx_pick_sphere INTEGER cx_pick_cone INTEGER cx_pick_cylinder INTEGER cx_pick_nurb INTEGER cx_pick_splat INTEGER cx_pick_other PARAMETER (cx_pick_none = 0) PARAMETER (cx_pick_point = 1) PARAMETER (cx_pick_line = 2) PARAMETER (cx_pick_face = 3) PARAMETER (cx_pick_sphere = 4) PARAMETER (cx_pick_cone = 5) PARAMETER (cx_pick_cylinder = 6) PARAMETER (cx_pick_nurb = 7) PARAMETER (cx_pick_splat = 8) PARAMETER (cx_pick_other = 9) |
You can use the API (Application Programming Interface) routines to manipulate the pick data type in Explorer. They are described in detail in the IRIS Explorer Reference Pages. They let you:
extract part of the data collected by the data structure
extract details about a specific object that has been hit
create a new instance of the cxPick data structure
Table 6-1 lists the subroutines and briefly describes the purpose of each one.
Subroutine | Purpose |
|---|---|
cxPickGet | Gets information from a cxPick data structure |
cx PickHitGet | Gets information from a cxPickHit data structure |
cxPickHitConeGet | Gets detailed information about a hit on a cone |
cxPickHitCylinderGet | Gets detailed information about a hit on a cylinder |
cxPickHitFaceGet | Gets detailed information about a hit on a polygon |
cxPickHitLineGet | Gets detailed information about a hit on a line |
cxPickHitPointGet | Gets detailed information about a hit on a point |
cxPickNew | Creates a new cxPick data structure |
This section includes examples of user functions for modules that read pick data. The user function for a module that writes pick data is given in “Writing Pick Data.”
The following function lists the number of hits, looks at the list, and builds a 1D lattice from the data in the list. The code is in the files /usr/explorer/src/MWGcode/Picking/C/ReadPick.c and in /usr/explorer/src/MWGcode/Picking/Fortran/ReadPick.f.
#include<stdio.h>
#include<cx/DataAccess.h>
#include<cx/cxLattice.h>
#include<cx/cxPick.h>
readpick(cxPick*pick,cxLattice**lattice)
{
int i; /*loop variable*/
long dims[1]; /*dimensions vector*/
long id; /*temporary variable for pickid*/
float *p; /*coordinate pointer*/
/*don't output anything if the pick didn't hit anything*/
if ( pick->numHits == 0 )
return;
/* create the output lattice */
/*lattice = cxLatNew(1,dims ,1,cx_prim_float ,3,
cx_coord_curvilinear );
/* set the pointer to the coordinates */
p = (*lattice)->coord->c.cx_coord_curvilinear.values;
/* loop over the hits */
for ( i = 0; i < pick->numHits; i++ )
{
/* get the location and id */
cxPickHitGet(pick,i,
&id, /* pick id */
HULL, /* valid info flags */
p, /* coordinate */
NULL, /* normal */
NULL, /* color */
NULL, /* label */
NULL, /* local transform */
NULL, /* global transform */
NULL); /* object type */
/* set the data value to the pick id */
(*lattice)->data->d.cx_prim_float.values[i] = id;
/* increment the coordinate pointer */
p += 3;
}
}
|
subroutine PickProc(pickPort, numHits, ndim, dims, nDataVar,
* primType, data, nCoordVar, coords, coordType)
integer pickPort
integer numHits
integer ndim, dims(1), nDataVar, nCoordVar, coordType, primType
real data(1)
real coords(3,1)
integer cxPickHitGet
c info from cxPickHitGet
real point(3)
integer id, validInfo, objectType
character*1 label(256)
real localxform(4,4), globalxform(4,4)
real color(4), normal(3)
if(numHits.eq.0) return
c set up the output lattice parameters
ndim = 1
dims(1) = numHits
nDataVar = 1
primType = 3
nCoordVar = 3
coordType = 2
do 100 i=1,numHits
ier = cxPickHitGet(pickPort,i-1,id,validInfo,point,normal,
* color,label,localxform,globalxform,objectType)
coords(1,i) = point(1)
coords(2,i) = point(2)
coords(3,i) = point(3)
data(i) = id
100 continue
return
end
|
Here is the user function for the QueryLat module. Seeing how the cxPick data type is used here may help you in writing your own pick module.
#include <stdio.h>
#include <cx/PortAccess.h>
#include <cx/DataTypes.h>
#include <cx/DataAccess.h>
#include <cx/UserFuncs.h>
#include <cx/Geometry.h>
#include <cx/Lookup.h>
#include <cx/Pick.h>
extern “C” long pick2()
{
static int flag = 1;
if ( flag )
{
flag = 0;
cxGeoInit();
}
/* allocate new geometry object */
cxGeometry *geo = cxGeoNew();
cxGeoBufferSelect(geo);
/* delete everything */
cxGeoRoot();
cxGeoDelete();
/* if this is a new lattice, create the lookup table */
static cxLookup *lut = NULL;
static cxPrimType ltype = cx_prim_byte;
int lport = cxInputPortOpen(“Lattice”);
if ( cxInputDataChanged(lport) )
{
if ( lut )
cxLookupDestroy(lut);
cxLattice *lattice = (cxLattice *)cxInputDataGet(lport);
lut = cxLookupCreate(lattice,cx_lookup_linear);
ltype = lattice->data->primType;
}
/* get the pick information */
cxPick *p = (cxPick *)cxInputDataGet(cxInputPortOpen(“Pick”));
if ( p->eventType == CX_PICK_BTNDOWN || p->eventType == CX_PICK_MOTION )
{
if ( p->numHits > 0 )
{
/* do a lookup */
switch (ltype)
{
#define CASE(ctype,type,format) \
case ctype: { \
type value; \
if ( cxLookupInterp(lut,p->hit[0].point,&value) ) \
cxGeoTextDefine(“domain error”, \
NULL); \
else { \
char str[128]; \
sprintf(str,format,value); \
cxGeoTextDefine(str, \
NULL); \
}\
} \
break;
CASE(cx_prim_byte,char,”%d”)
CASE(cx_prim_short,short,”%d”)
CASE(cx_prim_long,long,”%d”)
CASE(cx_prim_float,float,”%f”)
CASE(cx_prim_double,double,”%f”)
#undef CASE
}
#endif
cxGeoTranslate(p->hit[0].point[0],
p->hit[0].point[1],
p->hit[0].point[2]);
}
}
/* close the buffer and output */
cxGeoBufferClose(geo);
cxOutputDataSet(cxOutputPortOpen(“Annotation”),
(void *)geo);
return 0;
}
|