SensAble.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This program is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU General Public License as published by the Free  *
00007 * Software Foundation; either version 2 of the License, or (at your option)   *
00008 * any later version.                                                          *
00009 *                                                                             *
00010 * This program is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
00013 * more details.                                                               *
00014 *                                                                             *
00015 * You should have received a copy of the GNU General Public License along     *
00016 * with this program; if not, write to the Free Software Foundation, Inc., 51  *
00017 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
00018 *******************************************************************************
00019 *                            SOFA :: Applications                             *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 #include <stdio.h>
00028 #include <assert.h>
00029 
00030 #include <sofa/helper/system/gl.h>
00031 #include <sofa/helper/system/glut.h>
00032 
00033 
00034 #include <HD/hd.h>
00035 #include <HDU/hduVector.h>
00036 #include <HDU/hduError.h>
00037 
00038 #include "SensAble.h"
00039 
00040 #include <sofa/simulation/tree/GNode.h> 
00041 #include <sofa/simulation/common/MechanicalVisitor.h>
00042 #include <sofa/simulation/common/UpdateMappingVisitor.h>
00043 #include <sofa/simulation/common/MechanicalVisitor.h>
00044 #include <sofa/core/objectmodel/KeypressedEvent.h>
00045 #include <sofa/core/objectmodel/KeyreleasedEvent.h>
00046 #include <sofa/core/ObjectFactory.h>
00047 
00048 using namespace sofa::defaulttype;
00049 using namespace sofa::simulation::tree;
00050 using namespace sofa::simulation;
00051 
00052 SOFA_DECL_CLASS(SensAble)
00053 
00054 int SensAbleClass = sofa::core::RegisterObject("Phantom device")
00055 .add< SensAble >();
00056 
00058 typedef struct {
00059     int nupdates;
00060     HDboolean m_buttonState1;       /* Has the device button has been pressed. */
00061     HDboolean m_buttonState2;       /* Has the device button has been pressed. */
00062     hduVector3Dd m_devicePosition; /* Current device coordinates. */
00063     HDErrorInfo m_error;
00064     HDdouble transform[16];
00065     Quat quat;
00066 } DeviceData;
00067 
00068 static DeviceData gServoDeviceData;
00069 static DeviceData deviceData;
00070 static HDSchedulerHandle hUpdateHandle = 0;
00071 static HDSchedulerHandle hCallbackHandle = 0;
00072 static HHD hHD;
00073 
00074 
00075 HDCallbackCode HDCALLBACK SetForceCallback(void *pUserData);
00076 HDErrorInfo error;
00077 static volatile HDboolean bRenderForce = false;
00078 static hduVector3Dd force;
00079 static volatile HDboolean bRenderPivot = false;
00080 static Vec3d devicePivot;
00081 
00082 
00083 HDCallbackCode HDCALLBACK applyForceCallback(void *pUserData);
00084 
00085 
00089 HDCallbackCode HDCALLBACK updateDeviceCallback(void * /* pUserData */) {   
00090     int nButtons = 0;
00091     hdBeginFrame(hdGetCurrentDevice());
00092     // Retrieve the current button(s). 
00093     hdGetIntegerv(HD_CURRENT_BUTTONS, &nButtons);
00094     // In order to get the specific button 1 state, we use a bitmask to
00095     // test for the HD_DEVICE_BUTTON_1 bit. 
00096     gServoDeviceData.m_buttonState1 = (nButtons & HD_DEVICE_BUTTON_1) ? true : false;
00097     gServoDeviceData.m_buttonState2 = (nButtons & HD_DEVICE_BUTTON_2) ? true : false;
00098     // Get the current location of the device (HD_GET_CURRENT_POSITION)
00099     // We declare a vector of three doubles since hdGetDoublev returns 
00100     // the information in a vector of size 3.
00101     hdGetDoublev(HD_CURRENT_POSITION, gServoDeviceData.m_devicePosition);
00102     // Get the column major transform...
00103     hdGetDoublev(HD_CURRENT_TRANSFORM, gServoDeviceData.transform);
00104     // Also check the error state of HDAPI.
00105     gServoDeviceData.m_error = hdGetError();
00106     // Copy the position into our device_data tructure.
00107     hdEndFrame(hdGetCurrentDevice());
00108     return HD_CALLBACK_CONTINUE;
00109 }
00110 
00114 HDCallbackCode HDCALLBACK copyDeviceDataCallback(void *pUserData) {
00115     DeviceData *pDeviceData = (DeviceData *) pUserData;
00116     if (gServoDeviceData.nupdates > 0)
00117     {
00118         memcpy(pDeviceData, &gServoDeviceData, sizeof(DeviceData));
00119         pDeviceData->quat.normalize();
00120         gServoDeviceData.quat = Quat(0,0,0,0);
00121         gServoDeviceData.nupdates = 0;
00122     }
00123     return HD_CALLBACK_DONE;
00124 }
00125 
00126 bool isInitialized = false;
00127 
00131 int initDevice() {
00132     if (isInitialized) return 0;
00133     isInitialized = true;
00134     deviceData.transform[0*4+0] = 1;
00135     deviceData.transform[1*4+1] = 1;
00136     deviceData.transform[2*4+2] = 1;
00137     deviceData.transform[3*4+3] = 1;
00138     deviceData.quat[3] = 1;
00139 
00140     HDErrorInfo error;
00141     // Initialize the device, must be done before attempting to call any hd functions.
00142     hHD = hdInitDevice(HD_DEFAULT_DEVICE);
00143     if (HD_DEVICE_ERROR(error = hdGetError())) {
00144         hduPrintError(stderr, &error, "Failed to initialize the device");
00145         return -1;
00146     }
00147     // Schedule the main scheduler callback that updates the device state.
00148     //hUpdateHandle = hdScheduleAsynchronous( updateDeviceCallback, 0, HD_MAX_SCHEDULER_PRIORITY );
00149 
00150     // Schedule the haptic callback function for generating forces
00151     // we could do something smart in here, but lets try something stupid instead!
00152      hCallbackHandle = hdScheduleAsynchronous( applyForceCallback, 0, HD_MAX_SCHEDULER_PRIORITY);
00153 
00154     hdEnable(HD_FORCE_OUTPUT);
00155 
00156     // Start the servo loop scheduler. 
00157     hdStartScheduler();
00158     if (HD_DEVICE_ERROR(error = hdGetError())) {
00159         hduPrintError(stderr, &error, "Failed to start the scheduler");        
00160         return -1;           
00161     }
00162     return 0;
00163 }
00164 
00168 int uninitDevice() {    
00169     hdStopScheduler();
00170     //hdUnschedule(hUpdateHandle);
00171     hdUnschedule(hCallbackHandle);
00172     hdDisableDevice(hHD);
00173     return 0;
00174 }
00175 
00179 void getData() {        
00180     // Perform a synchronous call to copy the most current device state. 
00181     hdScheduleSynchronous(copyDeviceDataCallback, &deviceData, HD_MIN_SCHEDULER_PRIORITY);  
00182 }
00183 
00184 SensAble::SensAble()
00185 : scale(initData(&scale, 0.1, "scale","Default scale applied to the Phantom Coordinates. "))
00186 , tipOffset(initData(&tipOffset, -10.0, "tipOffset","tipOffset. [needs information]"))
00187 , xform(initData(&xform, sofa::defaulttype::RigidTypes::Coord(), "xform","Transformation applied to the Phantom coordinates."))
00188 , xform2(initData(&xform2, sofa::defaulttype::RigidTypes::Coord(), "xform2","Additional rotation."))
00189 , pivot(initData(&pivot, sofa::defaulttype::Vec3d(1.75, 4.0, -3.75), "pivot","Constrained point where the tool is pivoting."))
00190 , flip(initData(&flip, true, "flip","Rotate the instrument by 180�"))
00191   , bDraw(initData(&bDraw, true, "draw","Enable drawing of Sensable force state"))
00192 , key1(initData(&key1, '0', "key1","Key event generated when the first button is pressed")), button1State(false)
00193 , key2(initData(&key2, '1', "key2","Key event generated when the second button is pressed")), button2State(false)
00194 {
00195     this->f_listening.setValue(true);
00196 
00197     sofa::defaulttype::Quat _rotation;
00198     _rotation = xform.getValue().getOrientation();
00199 
00200     _rotation.normalize();
00201     _rotation.toMatrix(mrotation);
00202     std::cout << "Device post transform: scale = " << scale.getValue() <<" rotation = "<<xform.getValue().getOrientation()<<" translation = "<<xform.getValue().getCenter()<<" mrotation = "<<mrotation<<std::endl;
00203     devicePivot = mrotation.multTranspose(pivot.getValue() - xform.getValue().getCenter()) / scale.getValue();
00204     initDevice();
00205 
00206     sphereModel = new sofa::component::collision::SphereModel();
00207     double r = 1;
00208     sphereModel->addSphere(Vec3d(0,0,0),r);
00209 }
00210 
00211 void SensAble::handleEvent(sofa::core::objectmodel::Event* event)
00212 {
00213     if (sofa::core::objectmodel::KeypressedEvent* ev = dynamic_cast<sofa::core::objectmodel::KeypressedEvent*>(event))
00214     {
00215         switch(ev->getKey())
00216         {
00217     case '7':
00218     case 'f':
00219         bRenderForce = !bRenderForce;
00220         std::cout << "HAPTICS FORCE "<<(bRenderForce?"ENABLED":"DISABLED")<<std::endl;
00221             break;
00222     case '8':
00223     case 'p':
00224         bRenderPivot = !bRenderPivot;
00225         std::cout << "HAPTICS PIVOT "<<(bRenderPivot?"ENABLED":"DISABLED")<<std::endl;
00226             break;
00227         }
00228     }
00229 }
00230 
00231 SensAble::~SensAble() 
00232 {
00233     //uninitDevice();
00234 }
00235 
00236 
00237 void SensAble::init()
00238 {
00239     cout << "init called";
00240     rigidModel = dynamic_cast<sofa::component::MechanicalObject<RigidTypes>*>(getContext()->getMechanicalState());
00241     reinit();
00242 }
00243 
00244 
00245 void SensAble::reinit()
00246 {
00247     sofa::defaulttype::Quat _rotation;
00248     _rotation = xform.getValue().getOrientation();
00249     sofa::defaulttype::Quat _rotation2;
00250     _rotation2 = xform2.getValue().getOrientation();
00251 
00252     _rotation.normalize();
00253     _rotation2.normalize();
00254     if (_rotation2[3] != 1)
00255     {
00256         _rotation = _rotation2 * _rotation;
00257         xform.beginEdit()->getOrientation() = _rotation;
00258         xform.endEdit();
00259         xform2.beginEdit()->getOrientation() = sofa::defaulttype::Quat(0,0,0,1);
00260         xform2.endEdit();
00261     }
00262     _rotation.toMatrix(mrotation);
00263     std::cout << "Device post transform: scale = " << scale.getValue() <<" rotation = "<<xform.getValue().getOrientation()<<" translation = "<<xform.getValue().getCenter()<<" mrotation = "<<mrotation<<std::endl;
00264     devicePivot = mrotation.multTranspose(pivot.getValue() - xform.getValue().getCenter()) / scale.getValue();
00265 }
00266 
00267 void SensAble::updatePosition(double /* dt */) {
00268     // perhaps update the sphereModel position here...
00269     Mat3x3d mrot;
00270     deviceData.quat.toMatrix(mrot);
00271 
00272     double x = deviceData.transform[12] + mrot[0][2]*tipOffset.getValue();
00273     double y = deviceData.transform[13] + mrot[1][2]*tipOffset.getValue();
00274     double z = deviceData.transform[14] + mrot[2][2]*tipOffset.getValue();
00275     Vec3d pos(x,y,z);
00276     pos *= scale.getValue();
00277     pos = mrotation*pos;
00278     pos += xform.getValue().getCenter();
00279     Quat rot;
00280     //Mat3x3d mrot;
00281     //for (int i=0; i<3; i++)
00282     //  for (int j=0; j<3; j++)
00283     //      mrot[i][j] = deviceData.transform[j*4+i];
00284     mrot = mrotation * mrot;
00285     //std::cout << "mrot="<<mrot<<std::endl;
00286     if (flip.getValue())
00287     {
00288     //sofa::defaulttype::Quat r2(0,1,0,0);
00289     Mat3x3d mrot2;
00290     mrot2[0][0]=1;
00291     mrot2[1][1]=-1;
00292     mrot2[2][2]=-1;
00293     //r2.toMatrix(mrot2);
00294     mrot = mrot * mrot2;
00295     }
00296     rot.fromMatrix(mrot);
00297     Mat3x3d finalrot;
00298     rot.toMatrix(finalrot);
00299     //std::cout << "frot="<<finalrot<<std::endl;
00300 
00301     //sphereModel->setSphere( 0, Vec3d((z-x)*0.5, y, (-x-z)*0.5)*0.5, 0.5 );
00302     sphereModel->setSphere( 0, pos, 0.5*scale.getValue() );
00303 
00304     
00305     typedef sofa::core::componentmodel::behavior::BaseMechanicalState::VecId VecId;
00306 
00307     //if (deviceData.m_buttonState1)
00308     if (bRenderForce)
00309     {
00310 
00311         Vec3d f = (*sphereModel->getF())[0];
00312     if (rigidModel != NULL)
00313     {
00314         MechanicalComputeForceVisitor(VecId::force()).execute( rigidModel->getContext() );
00315         f += (*rigidModel->getF())[0].getVCenter();
00316     }
00317         //currentForce = Vec3d((-f[2]-f[0])*0.5, f[1], (f[0]-f[2])*0.5);
00318         currentForce = f * 1.0e-10;
00319         //if (currentForce.norm()>0.0001)
00320             cout << currentForce[0] << " " << currentForce[1] << " " << currentForce[2] << "\n";
00321     }
00322     else
00323     {
00324         currentForce = Vec3d(0,0,0);
00325     }
00326     {
00327         //if (!bRenderForce)
00328         //{
00329         //  std::cerr << "FORCE ERROR!!!"  << std::endl;
00330         //  bRenderForce = true;
00331         //}
00332         if (bRenderForce)
00333         hdScheduleSynchronous(SetForceCallback, &currentForce, HD_DEFAULT_SCHEDULER_PRIORITY);
00334     }
00335 
00336     (*sphereModel->getF())[0] = Vec3d(0,0,0);
00337     if (rigidModel != NULL)
00338     {
00339         MechanicalResetForceVisitor(VecId::force()).execute( rigidModel->getContext() );
00340     }
00341 
00342     if (rigidModel != NULL)
00343     {
00344         RigidTypes::VecCoord& x = *rigidModel->getX();
00345         x[0].getCenter() = pos;
00346         x[0].getOrientation() = rot;
00347     }
00348 
00349     //hduPrintError(stderr, &error, "status!@");
00350     sofa::simulation::tree::GNode* node = static_cast<sofa::simulation::tree::GNode*>(this->getContext());
00351     node->execute<sofa::simulation::MechanicalPropagatePositionAndVelocityVisitor>();
00352     node->execute<sofa::simulation::UpdateMappingVisitor>();
00353     
00354     while (node->getParent() != NULL)
00355         node = static_cast<sofa::simulation::tree::GNode*>(node->getParent());
00356     
00357     bool button1NewState = (deviceData.m_buttonState1!=0);
00358     if (button1NewState != button1State)
00359     {
00360         button1State = button1NewState;
00361         if (button1NewState)
00362         {
00363             sofa::core::objectmodel::KeypressedEvent ev(key1.getValue());
00364             node->propagateEvent(&ev);
00365         }
00366         else
00367         {
00368             sofa::core::objectmodel::KeyreleasedEvent ev(key1.getValue());
00369             node->propagateEvent(&ev);
00370         }
00371     }
00372     bool button2NewState = (deviceData.m_buttonState2!=0);
00373     if (button2NewState != button2State)
00374     {
00375         button2State = button2NewState;
00376         if (button2NewState)
00377         {
00378             sofa::core::objectmodel::KeypressedEvent ev(key2.getValue());
00379             node->propagateEvent(&ev);
00380         }
00381         else
00382         {
00383             sofa::core::objectmodel::KeyreleasedEvent ev(key2.getValue());
00384             node->propagateEvent(&ev);
00385         }
00386     }
00387     
00388 }
00389 
00390 /*
00391 std::vector<CollisionElement*>& SensAble::getCollisionElements() {
00392     // perhaps update the sphereModel position here...
00393 
00394     double x = deviceData.transform[13];
00395     double y = deviceData.transform[14];
00396     double z = deviceData.transform[15];
00397     sphereModel->setSphere( 0, x, y, z, 1 );
00398     
00399     return sphereModel->getCollisionElements();
00400 }
00401 */
00402 
00403 void SensAble::draw()
00404 {
00405     if (!bDraw.getValue()) return;
00406     getData();
00407     glPushMatrix();
00408     Vec3f c;
00409     if ( deviceData.m_buttonState1 && ! deviceData.m_buttonState2 ) {
00410         c = Vec3f(1,0,1);
00411     } else if ( !deviceData.m_buttonState1 && deviceData.m_buttonState2 ) {
00412         c = Vec3f(0,1,0);
00413     } else if ( deviceData.m_buttonState1 && deviceData.m_buttonState2 ) {
00414         c = Vec3f(1,1,0);
00415     } else {
00416         c = Vec3f(1,1,1);
00417     }
00418     glColor3fv(c.ptr());
00419     //glMultMatrixd(deviceData.transform);  
00420     //glutSolidCube(1);
00421     //glPopMatrix();
00422     double x = deviceData.transform[12]; // + deviceData.transform[8]*tipOffset;
00423     double y = deviceData.transform[13]; // + deviceData.transform[9]*tipOffset;
00424     double z = deviceData.transform[14]; // + deviceData.transform[10]*tipOffset;
00425     Vec3d p = Vec3d(x, y, z);
00426     p *= scale.getValue();
00427     p = mrotation*p;
00428     p += xform.getValue().getCenter();
00429     //Vec3d p = Vec3d((z-x)*0.5, y, (-x-z)*0.5)*0.5;
00430     glEnable(GL_LIGHTING);
00431     glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c.ptr());
00432     glPushMatrix();
00433     //std::cout << "SPH "<<index<<" "<<x()<<" "<<y()<<" "<<z()<<" "<<radius<<"\n";
00434     glTranslated(p[0],p[1],p[2]);
00435 //  glutSolidSphere(0.49*scale.getValue(), 16, 8);
00436     glPopMatrix();
00437     glDisable(GL_LIGHTING);
00438     if (currentForce.norm()>0.0001)
00439     {
00440         Vec3d f = currentForce; //Vec3d((currentForce[2]-currentForce[0])*0.5,currentForce[1],(-currentForce[0]-currentForce[2])*0.5);
00441         Vec3d n = f;
00442         n.normalize();
00443         glLineWidth(5);
00444         Vec3d p1,p2;
00445         p1 = (*sphereModel->getX())[0]+n*0.5*scale.getValue();
00446         p2 = (*sphereModel->getX())[0]+n*0.5*scale.getValue()+f*2;
00447         glBegin(GL_LINES);
00448 //          glVertex3dv(p1.ptr());
00449 //          glVertex3dv(p2.ptr());
00450         glEnd();
00451         glLineWidth(1);
00452     }
00453     if ( bRenderPivot) {
00454         Vec3d p0, dir;
00455         p0 = p;
00456         dir[0] = deviceData.transform[8];
00457         dir[1] = deviceData.transform[9];
00458         dir[2] = deviceData.transform[10];
00459         dir = mrotation*dir;
00460         dir.normalize();
00461         Vec3d dp = p0 - pivot.getValue();
00462         dp -= dir * (dot(dir,dp));
00463         glLineWidth(5);
00464         Vec3d p1,p2;
00465         p1 = pivot.getValue();
00466         p2 = pivot.getValue()+dp;
00467         glBegin(GL_LINES);
00468 //          glVertex3dv(p1.ptr());
00469 //          glVertex3dv(p2.ptr());
00470         glEnd();
00471         glLineWidth(1);
00472     }
00473 }
00474 
00483 /*
00484 void mainLoop(void) {
00485     static const int kTerminateCount = 1000;
00486     int buttonHoldCount = 0;
00487 
00488     // Instantiate the structure used to capture data from the device. 
00489     DeviceData currentData;
00490     DeviceData prevData;
00491 
00492     // Perform a synchronous call to copy the most current device state. 
00493     hdScheduleSynchronous(copyDeviceDataCallback, &currentData, HD_MIN_SCHEDULER_PRIORITY);
00494 
00495     memcpy(&prevData, &currentData, sizeof(DeviceData));
00496 
00497     printHelp();
00498 
00499     // Run the main loop until the gimbal button is held.
00500     while (1) {
00501         // Perform a synchronous call to copy the most current device state.
00502         // This synchronous scheduler call ensures that the device state
00503         // is obtained in a thread-safe manner.
00504         hdScheduleSynchronous(copyDeviceDataCallback, &currentData, HD_MIN_SCHEDULER_PRIORITY);
00505 
00506         // If the user depresses the gimbal button, display the current location information.
00507         if (currentData.m_buttonState && !prevData.m_buttonState)
00508         {           
00509             fprintf(stdout, "Current position: (%g, %g, %g)\n", 
00510                 currentData.m_devicePosition[0], 
00511                 currentData.m_devicePosition[1], 
00512                 currentData.m_devicePosition[2]); 
00513         }
00514         else if (currentData.m_buttonState && prevData.m_buttonState)
00515         {
00516             // Keep track of how long the user has been pressing the button.
00517             // If this exceeds N ticks, then terminate the application.
00518             buttonHoldCount++;
00519 
00520             if (buttonHoldCount > kTerminateCount)
00521             {
00522                 // Quit, since the user held the button longer than
00523                 // the terminate count.
00524                 break;
00525             }
00526         }
00527         else if (!currentData.m_buttonState && prevData.m_buttonState)
00528         {
00529             // Reset the button hold count, since the user stopped holding
00530             // down the stylus button.
00531             buttonHoldCount = 0;
00532         }
00533         
00534         // Check if an error occurred.
00535         if (HD_DEVICE_ERROR(currentData.m_error))
00536         {
00537             hduPrintError(stderr, &currentData.m_error, "Device error detected");
00538 
00539             if (hduIsSchedulerError(&currentData.m_error))
00540             {
00541                 // Quit, since communication with the device was disrupted. 
00542                 fprintf(stderr, "\nPress any key to quit.\n");
00543                 getch();                
00544                 break;
00545             }
00546         }
00547 
00548         // Store off the current data for the next loop. 
00549         memcpy(&prevData, &currentData, sizeof(DeviceData));    
00550     }
00551 }
00552 */
00553 
00554 /******************************************************************************
00555  * Main scheduler callback for rendering the anchored spring force.
00556  *****************************************************************************/
00557 HDCallbackCode HDCALLBACK applyForceCallback(void * /* pUserData */)
00558 {
00559     static int lastButtons = 0;
00560     int nButtons = 0;
00561     hdBeginFrame(hdGetCurrentDevice());
00562     // Retrieve the current button(s). 
00563     hdGetIntegerv(HD_CURRENT_BUTTONS, &nButtons);
00564     // In order to get the specific button 1 state, we use a bitmask to
00565     // test for the HD_DEVICE_BUTTON_1 bit. 
00566     gServoDeviceData.m_buttonState1 = (nButtons & HD_DEVICE_BUTTON_1) ? true : false;
00567 //  gServoDeviceData.m_buttonState2 = (nButtons & HD_DEVICE_BUTTON_2) ? true : false;
00568     gServoDeviceData.m_buttonState2 = (nButtons & ~HD_DEVICE_BUTTON_1) ? true : false;
00569     // Get the current location of the device (HD_GET_CURRENT_POSITION)
00570     // We declare a vector of three doubles since hdGetDoublev returns 
00571     // the information in a vector of size 3.
00572     hdGetDoublev(HD_CURRENT_POSITION, gServoDeviceData.m_devicePosition);
00573     // Get the column major transform...
00574     hdGetDoublev(HD_CURRENT_TRANSFORM, gServoDeviceData.transform);
00575     // Also check the error state of HDAPI.
00576     // Copy the position into our device_data tructure.
00577 
00578     // Swap the X and Z axis
00579     gServoDeviceData.transform[0]  *= -1;
00580     gServoDeviceData.transform[1]  *= -1;
00581     gServoDeviceData.transform[2]  *= -1;
00582     gServoDeviceData.transform[8]  *= -1;
00583     gServoDeviceData.transform[9]  *= -1;
00584     gServoDeviceData.transform[10] *= -1;
00585 
00586 
00587     Quat rot;
00588     Mat3x3d mrot;
00589     for (int i=0; i<3; i++)
00590         for (int j=0; j<3; j++)
00591             mrot[i][j] = gServoDeviceData.transform[j*4+i];
00592     rot.fromMatrix(mrot);
00593     
00594     if ((rot[0]*gServoDeviceData.quat[0]+rot[1]*gServoDeviceData.quat[1]+rot[2]*gServoDeviceData.quat[2]+rot[3]*gServoDeviceData.quat[3]) < 0)
00595     {
00596         for (int i=0;i<4;i++)
00597             rot[i] *= -1;
00598     }   
00599     
00600     gServoDeviceData.quat[0] += rot[0];
00601     gServoDeviceData.quat[1] += rot[1];
00602     gServoDeviceData.quat[2] += rot[2];
00603     gServoDeviceData.quat[3] += rot[3];
00604 
00605     //if ( (nButtons & HD_DEVICE_BUTTON_2) && !(lastButtons & HD_DEVICE_BUTTON_2) ) {
00606     //  bRenderPivot = !bRenderPivot;
00607     //}
00608 
00609     lastButtons = nButtons;
00610 
00611     if ( bRenderForce || bRenderPivot ) {
00612         hduVector3Dd f(0,0,0);
00613         if ( bRenderForce) {
00614             f += force;
00615         }
00616         if ( bRenderPivot ) { //&& (nButtons & HD_DEVICE_BUTTON_1)) {
00617             Vec3d p0, dir;
00618             p0[0] = gServoDeviceData.transform[12];
00619             p0[1] = gServoDeviceData.transform[13];
00620             p0[2] = gServoDeviceData.transform[14];
00621             dir[0] = gServoDeviceData.transform[8];
00622             dir[1] = gServoDeviceData.transform[9];
00623             dir[2] = gServoDeviceData.transform[10];
00624             dir.normalize();
00625             Vec3d dp = p0 - devicePivot;
00626             dp -= dir * (dot(dir,dp));
00627             dp *= -0.5;
00628             if (dp.norm() > 1) dp*= 1/dp.norm();
00629             f[0] += dp[0];
00630             f[1] += dp[1];
00631             f[2] += dp[2];
00632         }
00633         hdSetDoublev(HD_CURRENT_FORCE, f);
00634         // Check if an error occurred while attempting to render the force 
00635         gServoDeviceData.m_error = hdGetError();
00636         if (HD_DEVICE_ERROR(gServoDeviceData.m_error = hdGetError()))
00637         {
00638             if (hduIsForceError(&gServoDeviceData.m_error))
00639             {
00640                 bRenderForce = false;
00641             }
00642             else if (hduIsSchedulerError(&gServoDeviceData.m_error))
00643             {
00644                 return HD_CALLBACK_DONE;
00645             }
00646         }
00647     }
00648     else
00649         gServoDeviceData.m_error = hdGetError();
00650 
00651     ++gServoDeviceData.nupdates;
00652     hdEndFrame(hdGetCurrentDevice());
00653     return HD_CALLBACK_CONTINUE;
00654 }
00655 
00656 /*
00657     static hduVector3Dd anchor;
00658     static HDboolean bRenderForce = false;
00659     HDErrorInfo error;
00660 
00661     HDint nCurrentButtons, nLastButtons;
00662     hduVector3Dd position;
00663 
00664     hduVector3Dd force = { 0, 0, 0 };
00665 
00666     hdBeginFrame(hdGetCurrentDevice());
00667 
00668     hdGetDoublev(HD_CURRENT_POSITION, position);    
00669     hdGetIntegerv(HD_CURRENT_BUTTONS, &nCurrentButtons);
00670     hdGetIntegerv(HD_LAST_BUTTONS, &nLastButtons);
00671 
00672     if ((nCurrentButtons & HD_DEVICE_BUTTON_1) != 0 &&
00673         (nLastButtons & HD_DEVICE_BUTTON_1) == 0)
00674     {
00675         // Detected button down
00676         memcpy(anchor, position, sizeof(hduVector3Dd));
00677         bRenderForce = true;
00678     }
00679     else if ((nCurrentButtons & HD_DEVICE_BUTTON_1) == 0 &&
00680              (nLastButtons & HD_DEVICE_BUTTON_1) != 0)
00681 
00682     {
00683         // Detected button up 
00684         bRenderForce = false;
00685 
00686         // Send zero force to the device, or else it will just continue
00687         // rendering the last force sent
00688         hdSetDoublev(HD_CURRENT_FORCE, force);
00689     }
00690 
00691     if (bRenderForce)
00692     {
00693         // Compute spring force as F = k * (anchor - pos), which will attract
00694         // the device position towards the anchor position 
00695         hduVecSubtract(force, anchor, position);
00696         hduVecScaleInPlace(force, gSpringStiffness);
00697                 
00698         hdSetDoublev(HD_CURRENT_FORCE, force);
00699     }
00700 
00701     hdEndFrame(hdGetCurrentDevice());
00702 
00703     // Check if an error occurred while attempting to render the force 
00704     if (HD_DEVICE_ERROR(error = hdGetError()))
00705     {
00706         if (hduIsForceError(&error))
00707         {
00708             bRenderForce = false;
00709         }
00710         else if (hduIsSchedulerError(&error))
00711         {
00712             return HD_CALLBACK_DONE;
00713         }
00714     }
00715 
00716     return HD_CALLBACK_CONTINUE;
00717 }
00718 */
00719     
00720 /******************************************************************************
00721  * Scheduler callback for synchronously changing the rendered force
00722  *****************************************************************************/
00723 HDCallbackCode HDCALLBACK SetForceCallback(void *pUserData)
00724 {
00725     Vec3d* pForce = (Vec3d*) pUserData;
00726     force[0] = (*pForce)[0];
00727     force[1] = (*pForce)[1];
00728     force[2] = (*pForce)[2];
00729     return HD_CALLBACK_DONE;    
00730 }

Generated on Sun Nov 23 02:28:35 2008 for Sofa by  doxygen 1.5.7.1