An Example of OpenHaptics Application
This is an example in the Sample Source Code Guide.
Description:
This example demonstrates dragging 3D objects with constraints.
It displays a group of objects. When the user touches one and
holds the stylus button down, the user can move it around the screen.
While the button is down, constraint axes are drawn to allow more
precise control over dragging.
Shows using constraints to allow precise manipulation of objects with the haptic device.
This example also shows
(1)how to track the changes in position and orientation of the haptic device
/*******************************************************************************
Use the current OpenGL viewing transforms to initialize a transform for the
haptic device workspace so that it's properly mapped to world coordinates.
*******************************************************************************/
void updateHapticMapping(void)
{
GLdouble modelview[16];
GLdouble projection[16];
GLint viewport[4];
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
hlMatrixMode(HL_TOUCHWORKSPACE);
hlLoadIdentity();
// Fit haptic workspace to view volume.
hluFitWorkspace(projection);
// Compute cursor scale.
gCursorScale = hluScreenToModelScale(modelview, projection, viewport);
gCursorScale *= CURSOR_SIZE_PIXELS;
}
/******************************************************************************
Displays a cursor using the current haptic device proxy transform and the
mapping between the workspace and world coordinates
******************************************************************************/
void redrawCursor()
{
static const double kCursorRadius = 0.5;
static const int kCursorTess = 15;
HLdouble proxytransform[16];
GLUquadricObj *qobj = 0;
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT);
glPushMatrix();
if (!gCursorDisplayList)
{
gCursorDisplayList = glGenLists(1);
glNewList(gCursorDisplayList, GL_COMPILE);
qobj = gluNewQuadric();
gluSphere(qobj, kCursorRadius, kCursorTess, kCursorTess);
gluDeleteQuadric(qobj);
glEndList();
}
// Apply the local position/rotation transform of the haptic device proxy.
hlGetDoublev(HL_PROXY_TRANSFORM, proxytransform);
glMultMatrixd(proxytransform);
// Apply the local cursor scale factor.
glScaled(gCursorScale, gCursorScale, gCursorScale);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.0, 0.5, 1.0);
glCallList(gCursorDisplayList);
glPopMatrix();
glPopAttrib();
}
(2)how to apply those changes to an object in the scene.
/******************************************************************************
Calculates updated object transform for drag object based on changes to
proxy transform.
******************************************************************************/
void updateDragObjectTransform()
{
assert(gCurrentDragObj >= 0 &&
gCurrentDragObj < draggableObjects.size());
// Calculated delta between current proxy pos and proxy pos at start
// of drag.
hduVector3Dd proxyPos;
hlGetDoublev(HL_PROXY_POSITION, proxyPos);
hduVector3Dd dragDeltaTransl = proxyPos - gStartDragProxyPos;
// Same for rotation.
hduMatrix deltaRotMat;
if (gRotate)
{
hduQuaternion proxyRotq;
hlGetDoublev(HL_PROXY_ROTATION, proxyRotq);
hduQuaternion dragDeltaRot = gStartDragProxyRot.inverse() * proxyRotq;
dragDeltaRot.normalize();
dragDeltaRot.toRotationMatrix(deltaRotMat);
// Want to rotate about the proxy position, not the origin,
// so need to translate to/from proxy pos.
hduMatrix toProxy = hduMatrix::createTranslation(-gStartDragProxyPos);
hduMatrix fromProxy = hduMatrix::createTranslation(gStartDragProxyPos);
deltaRotMat = toProxy * deltaRotMat * fromProxy;
}
// Compose rotation and translation deltas.
hduMatrix deltaMat = deltaRotMat * hduMatrix::createTranslation(dragDeltaTransl);
// Apply these deltas to the drag object transform.
draggableObjects[gCurrentDragObj].transform = gStartDragObjTransform * deltaMat;
}
/*******************************************************************************
Draws the objects that can be seen, felt and dragged around.
*******************************************************************************/
void drawDraggableObjects()
{
hlTouchModel(HL_CONTACT);
hlTouchableFace(HL_FRONT);
for (int i = 0; i < draggableObjects.size(); ++i)
{
const DraggableObject& obj = draggableObjects[i];
// Position and orient the object.
glPushMatrix();
glMultMatrixd(obj.transform);
// Draw the object graphically.
glCallList(obj.displayList);
// Draw the object haptically (but not if it is being dragged).
if (i != gCurrentDragObj)
{
hlBeginShape(HL_SHAPE_FEEDBACK_BUFFER, obj.shapeId);
glCallList(obj.displayList);
hlEndShape();
}
glPopMatrix();
}
}
It also shows
(1)how to use collision thread events to disable proxy rendering in order to avoid a haptic "kick" when
setting constraints on stylus switch clicks.