Using Pick Objects
A pick object contains all the information necessary to calculate geometric intersections between the pick geometry and the objects in a model. To create a pick object, you need to fill out data structures with the appropriate information, including
The following sections illustrate how to perform these tasks.
- how the hits are to be sorted
- how many hits to return
- what information should be returned about any hits
- whether to pick whole objects or parts of objects
- how much tolerance to allow when calculating hits
- the pick geometry
Handling Object Picking
Listing 15-1 illustrates how to create, use, and dispose of pick objects. It defines a function,MyHandleClickInWindow
, that takes a window pointer and an event record and handles mouse clicks in that window.
TQ3Status MyHandleClickInWindow (CGrafPtr myWindow, EventRec myEvent) { TQ3WindowPointPickData myWPPickData; TQ3PickObject myPickObject; TQ3HitData myHitData; unsigned long myNumHits; unsigned long myIndex; Point myPoint; TQ3Point2D my2DPoint; TQ3ViewObject myView; /*Get the window coordinates of a mouse click.*/ SetPort(myWindow); myPoint = myEvent.where; /*get location of mouse click*/ GlobalToLocal(&myPoint); /*convert to window coordinates*/ my2DPoint.x = myPoint.h; /*configure a 2D point*/ my2DPoint.y = myPoint.v; /*Set up picking data structures.*/ /*Set sorting type: objects nearer to pick origin are returned first.*/ myWPPickData.data.sort = kQ3PickSortNearToFar; myWPPickData.data.mask = kQ3PickDetailMaskPickID | kQ3PickDetailMaskXYZ | kQ3PickDetailMaskObject; myWPPickData.data.numHitsToReturn = kQ3ReturnAllHits; myWPPickData.point = my2DPoint; myWPPickData.vertexTolerance = 2.0; myWPPickData.edgeTolerance = 2.0; /*Create a new window-point pick object.*/ myPickObject = Q3WindowPointPick_New(&myWPPickData); myView = MyGetViewFromWindow(myWindow);/*increments reference count*/ /*Pick a group object.*/ Q3View_StartPicking(myView, myPickObject); do { Q3DisplayGroup_Submit(gGroup, myPickObject, myView); } while (Q3View_EndPicking(myView) == kQ3ViewStatusRetraverse); /*See whether any hits occurred.*/ if (!Q3Pick_GetNumHits(myPickObject, &myNumHits) || !(myNumHits == 0)) { Q3Object_Dispose(myPickObject); return; } /*Process each hit.*/ for (myIndex = 0; myIndex < myNumHits; myIndex++) { Q3Pick_GetHitData(myPickObject, myIndex, &myHitData); /*operate on myHitData, then...*/ ... Q3Hit_EmptyData(&myHitData); /*dispose of hit data*/ } /*Dispose of all hits in the hit list.*/ Q3Pick_EmptyHitList(myPickObject); /*Dispose of the pick object.*/ Q3Object_Dispose(myPickObject); /*Dispose of the view object.*/ Q3Object_Dispose(myView); }Note that the call toQ3Pick_EmptyHitList
is redundant, because disposing
of a pick object (by callingQ3Object_Dispose
) also disposes of its associated hit list. The call is included in Listing 15-1 simply to illustrate how to
callQ3Pick_EmptyHitList
. You would, however, need to call toQ3Pick_EmptyHitList
if you wanted to reuse the associated pick object in another pick operation.Handling Mesh Part Picking
When a model includes a mesh, you can decide whether the entire mesh only or parts of the mesh also are eligible for picking. You do this by specifying an appropriate hit information mask. For example, to allow mesh parts to be selected, you can set up the hit information mask like this:
myPickData.mask = kQ3PickDetailMaskShapePart | kQ3PickDetailMaskObject | kQ3PickDetailMaskDistance;This line of code indicates that you want QuickDraw 3D to return information about objects and any distinguishable parts of objects, as well as the distances from the objects to the pick origin. (To prevent mesh parts from being selected, you simply omit adding in thekQ3PickDetailMaskShapePart
mask.)You can determine whether a hit data structure returned by
Q3Pick_GetHitData
applies to a shape part by inspecting theshapePart
field of that structure. If the value in the field is non-NULL
, the structure contains information about a shape part. Currently the only available shape parts are mesh parts. Listing 15-2 illustrates how to use theshapePart
field to determine the type of mesh part selected and to perform some operation on the selected mesh part.Listing 15-2 Picking mesh parts
Q3Pick_GetHitData(myPickObject, myIndex, &myHitData); if (myHitData.shapePart != NULL) { switch(Q3Object_GetLeafType(myHitData.shapePart)) { case kQ3MeshPartTypeMeshFacePart: Q3MeshFacePart_GetFace(myHitData.shapePart, &myFace); MyDoPickFace(myHitData.object, myFace); break; case kQ3MeshPartTypeMeshEdgePart: Q3MeshEdgePart_GetEdge(myHitData.shapePart, &myEdge); MyDoPickEdge(myHitData.object, myEdge); break; case kQ3MeshPartTypeMeshVertexPart: Q3MeshVertexPart_GetVertex(myHitData.shapePart, &myVertex); MyDoPickVertex(myHitData.object, myVertex); break; } }This code branches on the type of the mesh part indicated by theshapePart
field. For each defined type of mesh part, the code calls a QuickDraw 3D routine to retrieve the corresponding mesh face, edge, or vertex. Then it calls an application-defined routine (for example,MyDoPickFace
) to handle the mesh part selection.Picking in Immediate Mode
Picking IDs are particularly useful when picking in immediate mode. Listing 15-3 shows how to create a triangle, attach a picking ID to it, and
then process hits.Listing 15-3 Picking in immediate mode
void MyImmediateModePickID (TQ3ViewObject view, WindowPtr window) { TQ3WindowRectPickData myPickData; TQ3TriangleData myTriangleData; TQ3PickObject myPick; TQ3ViewStatus myViewStatus; TQ3HitData myHitData; Rect myPortRect; Point myCenter; unsigned long myNumHits; /*Set up a triangle.*/ Q3Point3D_Set(&myTriangleData.vertices[0].point, -1.0, -0.5, 0.0); Q3Point3D_Set(&myTriangleData.vertices[1].point, 1.0, 0.0, 0.0); Q3Point3D_Set(&myTriangleData.vertices[2].point, -0.5, 1.5, 0.0); myTriangleData.vertices[0].attributeSet = NULL; myTriangleData.vertices[1].attributeSet = NULL; myTriangleData.vertices[2].attributeSet = NULL; myTriangleData.triangleAttributeSet = NULL; /*Set up TQ3WindowPointPickData structure.*/ myPickData.data.sort = kQ3PickSortNone; myPickData.data.mask = kQ3PickDetailMaskPickID | kQ3PickDetailMaskObject; myPickData.data.numHitsToReturn = kQ3ReturnAllHits; myPortRect = ((GrafPtr) window)->myPortRect; myCenter.h = (myPortRect.right - myPortRect.left)/2.0; myCenter.v = (myPortRect.bottom - myPortRect.top) /2.0; Q3Point2D_Set(&myPickData.rect.min, myCenter.h - 5, myCenter.v - 5); Q3Point2D_Set(&myPickData.rect.max, myCenter.h + 5, myCenter.v + 5); /*Create the window rectangle window pick.*/ myPick = Q3WindowRectPick_New(&myPickData); /*Submit the pick ID and triangle in immediate mode.*/ Q3View_StartPicking(view, myPick); do { Q3PickIDStyle_Submit(kPickID, view); Q3Triangle_Submit(&myTriangleData, view); myViewStatus = Q3View_EndPicking(view); } while (myViewStatus == kQ3ViewStatusRetraverse); Q3Pick_GetNumHits(myPick, &myNumHits); if (numHits == 1) { /*Get the hit data and check its pick ID.*/ Q3Pick_GetHitData(myPick, 0, &myHitData); if (myHitData.pickID == kPickID) { /*picked on triangle with pick ID*/ } } Q3Object_Dispose(myPick); }
Main | Top of Section | What's New | Apple Computer, Inc. | Find It | Feedback | Help