Beispiel #1
0
hduVector3Dd HapticDevice::ForceToImpact(hduVector3Dd* effector,hduVector3Dd* impactpos){
	    // use Yamada and al force model
		hduVector3Dd inbetween = *impactpos - *effector ;
		hduVector3Dd force = hduVector3Dd(0,0.1,0.0);
		HDdouble phi = 2.0;
		HDdouble sigma = 20;//0.091;

		HDdouble div = 1.0;

		HDdouble s2 = pow(sigma, 2);

		HDdouble x = inbetween.magnitude();

		HDdouble f = phi * ( pow(x,2)/ s2 ) * std::exp((s2 - pow(x,2))/s2);		
		
		//HDdouble f = phi * ( pow(x,2)/ s2 ) * std::exp((s2 - pow(x,2))/s2);		

		//HDdouble f = phi * ( pow(x,2)/ s2 ) * std::exp((s2 - pow(x,2))/s2);	
		
		inbetween.normalize();		
		
		
		force +=  f * inbetween;
			
		
	return force ;
}
Beispiel #2
0
hduVector3Dd HapticDevice::trajectoryLine(hduVector3Dd p1,hduVector3Dd p2){
	
	HDdouble a =  (p2[1] - p1[1])/(p2[0] - p1[0]);
	HDdouble b = p1[1] - a * p1[0];
	//std::cout<<"  a"<<a<<" b"<<b<<std::endl;
	return hduVector3Dd(a,b,0);
}
void ParticleSystem::ClearForces(void)
{
    for (unsigned int i = 0; i < particles.size(); i++)
    {
        particles[i]->f = hduVector3Dd(0,0,0);
    }
}
Beispiel #4
0
hduVector3Dd HapticDevice::atomeForce(hduVector3Dd* effector,hduVector3Dd* currentTarget, btTransform* invertCamera){
	
	hduVector3Dd force = hduVector3Dd(0,0.1,0.0);	

	hduVector3Dd direct = hduVector3Dd(0,0.0,0.0);	

	HDdouble someNorme = 0.1;

	for(unsigned int i = 0; i< m_possibleImpact.size(); i++){

		hduVector3Dd impact = invertTransform(m_possibleImpact[i], invertCamera);
		
		hduVector3Dd inbetween = impact - *effector ;			

		HDdouble x = inbetween.magnitude();
				
		if(x <= Quick_Distance_max)
			someNorme += pow(x,2);		
	
	}	

	for(unsigned int i = 0; i< m_possibleImpact.size(); i++){

		hduVector3Dd impact = invertTransform(m_possibleImpact[i], invertCamera);
		
		hduVector3Dd inbetween = impact - *effector ;			

		HDdouble x = inbetween.magnitude();
				
		if(x <= Quick_Distance_max)
			direct += (pow(x,2) / someNorme) * impact;		
	
	}	

	direct -= *effector;

	HDdouble va = direct.magnitude();

		
	force += 0.3 * pow((lamda(Quick_Distance_max,va) / Quick_Distance_max),2) * 
		pow((lamda(max_velocity,m_velocity)/max_velocity),2) * direct;

	//std::cout << m_velocity << std::endl;
	return force;
}
Beispiel #5
0
hduVector3Dd  HapticDevice::invertTransform(btVector3* trans,btTransform* invertCamera){
			
			btTransform camInv =btTransform(*invertCamera);
		       
			btVector3 pos(*trans);
			pos =camInv(pos);
			pos*=SCALE_WORLD_TO_DEVICE;					
			
			return hduVector3Dd(pos.getX(),	pos.getY(),	pos.getZ()+OFFSET_TO_CAMERA) ;
}
Beispiel #6
0
/*******************************************************************************
 hduMapWorkspace

 Determines a mapping for the haptic device's workspace so that it optimally
 fits within the viewing volume provided.

 Parameters:
 projMatrix   A pointer to a 4x4 projection matrix stored in column-major order.
 wsBounds     A pointer to a 6 element vector describing the bounding box of the
              workspace to be fit. xMin, yMin, zMin, xMax, yMax, zMax
 wsMatrix     A pointer to a 4x4 matrix used for storing the resultant 
              column-major order workspace transform.
 The workspace transform will transform coordinates from the haptic device
 coordinates space into eye coordinates of the viewing volume
*******************************************************************************/
void hduMapWorkspace(const HDdouble *projMatrix,
                     const HDdouble *wsBounds,
                     HDdouble zNear, HDdouble zFar,
                     HDdouble *wsMatrix)
{
    hduMatrix eyeTclip(projMatrix);
    hduMatrix clipTeye = eyeTclip;
    bool bNoError = clipTeye.invert();
    assert(bNoError);

    /* Make sure the zNear and zFar values are valid and then convert to clip 
       coordinates. */
    zNear = hduClamp(zNear, 0.0, 1.0);
    HDdouble zClipNear = hduLerp<HDdouble>(-1, 1, zNear);

    zFar = hduClamp(zFar, 0.0, 1.0);
    HDdouble zClipFar = hduLerp<HDdouble>(-1, 1, zFar);

    HDdouble scale = computeWorkspaceToViewVolumeScale(
        projMatrix, wsBounds, zNear, zFar);

    hduVector3Dd wsCenter;
    wsCenter[0] = (wsBounds[0] + wsBounds[3]) / 2.0;
    wsCenter[1] = (wsBounds[1] + wsBounds[4]) / 2.0;
    wsCenter[2] = (wsBounds[2] + wsBounds[5]) / 2.0;

    hduMatrix scaleWorkspace = hduMatrix::createScale(scale, scale, scale);
    hduMatrix toWorkspaceCenter = hduMatrix::createTranslation(-1.0 * wsCenter);
    hduMatrix fromWorkspaceCenter = hduMatrix::createTranslation(wsCenter);
    scaleWorkspace.multLeft(toWorkspaceCenter);
    scaleWorkspace.multRight(fromWorkspaceCenter);

    /* Matchup the center of the front of the workspace with the center of the 
       near plane. */
    hduVector3Dd wsCenterFront(wsCenter[0], wsCenter[1], wsBounds[5]);
    hduVector3Dd wsCenterFrontScaled;
    scaleWorkspace.multVecMatrix(wsCenterFront, wsCenterFrontScaled);
        
    hduVector3Dd vvCenterNearPlane;
    clipTeye.multVecMatrix(hduVector3Dd(0, 0, zClipNear), vvCenterNearPlane);

    /* Translate workspace so that the center of its front plane matches the 
       near plane of the view volume. */
    hduMatrix translateWorkspace = hduMatrix::createTranslation(
        vvCenterNearPlane - wsCenterFrontScaled);

    /* Finally, multiply the scale and translation to arrive at a transform
       from workspace coordinates to eye coordinates. */
    hduMatrix workspaceTeye = scaleWorkspace;
    workspaceTeye.multRight(translateWorkspace);

    /* Copy the result into the destination workspace transform matrix. */
    memcpy(wsMatrix, workspaceTeye, 16 * sizeof(HDdouble));
}
Beispiel #7
0
/******************************************************************************
 hduScreenToWorkspaceScale

 Computes the uniform scale factor that will map screen coordinate scale
 into workspace coordinates. This can be used for determining a visual scale
 for an entity that lives in workspace coordinates, like the 3D cursor.
 *****************************************************************************/
HDdouble hduScreenToWorkspaceScale(const HDdouble *modelMatrix,
                                   const HDdouble *projMatrix,
                                   const HDint *viewport,
                                   const HDdouble *wsViewMatrix)
{
    hduVector3Dd p0, p1;

    hduMatrix worldTeye(modelMatrix);
    hduMatrix eyeTclip(projMatrix);
    hduMatrix worldTclip = worldTeye;
    worldTclip.multRight(eyeTclip);

    hduMatrix clipTworld = worldTclip;
    bool bNoError = clipTworld.invert();
    assert(bNoError);

    static const hduVector3Dd leftBottomNearClip(-1, -1, -1);
    static const hduVector3Dd rightTopNearClip(1, 1, -1);

    /* First compute the uniform scale factor between screen coordinates and
       world coordinates. */
    clipTworld.multVecMatrix(leftBottomNearClip, p0);
    clipTworld.multVecMatrix(rightTopNearClip, p1);  

    HDdouble screenDiagonal = sqrt(double(viewport[2] * viewport[2] + 
                                   viewport[3] * viewport[3]));

    HDdouble screenTworldScale = (p0 - p1).magnitude() / screenDiagonal;

    /* Now determine the scale factor from world to workspace coordinates. */
    hduMatrix workspaceTworld(wsViewMatrix);

    workspaceTworld.multVecMatrix(hduVector3Dd(0, 0, 0), p0);
    workspaceTworld.multVecMatrix(hduVector3Dd(1, 1, 1), p1);

    HDdouble workspaceTworldScale = (p0 - p1).magnitude() / sqrt(3.0);

    HDdouble screenTworkspaceScale = screenTworldScale / workspaceTworldScale;

    return screenTworkspaceScale;
}
Beispiel #8
0
hduQuaternion hduQuaternion::inverse() const
{
    double n = norm();
    if (n == 0)
    {
        return hduQuaternion(0, hduVector3Dd(0,0,0));
    }
    else
    {
        return 1/n * conjugate();
    }
}
Beispiel #9
0
hduVector3Dd HapticDevice::groundForce(bool collide, hduVector3Dd *effector,btTransform* invertCamera){

	hduVector3Dd force = hduVector3Dd(0,2.0,0); 

	if(collide){

		btVector3 p = m_ground->getWorldTransform().getOrigin();

		hduVector3Dd ground_pos = invertTransform(&p,invertCamera);

		
		force[1] += (ground_pos[1] - (*effector)[1]) ;	

		force *= 0.10;
	}

	return force; 
}
Beispiel #10
0
void hduQuaternion::toAxisAngle(hduVector3Dd &axis, double &angle) const
{
    double lenSquared = m_v.dotProduct(m_v);
    
    if (lenSquared > 0.0)
    {
        assert(m_s >= -1.0 && m_s <= 1.0);
        angle = 2.0*acos(hduClamp<double>(m_s, -1.0, 1.0));
        double invlen = 1.0 / sqrt(lenSquared);
        axis = invlen * m_v;
    }
    else
    {
        // If angle is 0 so axis doesn't matter, pick any
        angle = 0;
        axis = hduVector3Dd(1.0, 0.0, 0.0);
    }
}
void CHapticViewerView::getViewVolumeInModelCoord(
    hduVector3Dd* frustum)
{
    GLdouble projection[16];
    GLdouble modelview[16];

    glGetDoublev(GL_PROJECTION_MATRIX, projection);
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview);

    bool bNoError = false;

    hduMatrix modelTeye(modelview);
    hduMatrix eyeTmodel = modelTeye;
    bNoError = eyeTmodel.invert();
    assert(bNoError);

    hduMatrix eyeTclip(projection);
    hduMatrix clipTeye = eyeTclip;
    bNoError = clipTeye.invert();
    assert(bNoError);

    hduMatrix clipTmodel = clipTeye.multRight(eyeTmodel);

    // Compute the edges of the view frustum by transforming canonical
    // coordinates for the corners into eye space.

    hduVector3Dd localFrustum[8];
    localFrustum[LEFTBOTTOMNEAR]  = hduVector3Dd(-1, -1, -1);
    localFrustum[LEFTBOTTOMFAR]   = hduVector3Dd(-1, -1,  1);
    localFrustum[RIGHTBOTTOMNEAR] = hduVector3Dd( 1, -1, -1);
    localFrustum[RIGHTBOTTOMFAR]  = hduVector3Dd( 1, -1,  1); 
    localFrustum[RIGHTTOPNEAR]    = hduVector3Dd( 1,  1, -1);
    localFrustum[RIGHTTOPFAR]     = hduVector3Dd( 1,  1,  1);
    localFrustum[LEFTTOPNEAR]     = hduVector3Dd(-1,  1, -1);
    localFrustum[LEFTTOPFAR]      = hduVector3Dd(-1,  1,  1);
    
    transformFrustum(clipTmodel, localFrustum, frustum);
}
void ParticleSystem::FinishConstructingSystem(void)
{
    // make sure we have a mouse spring
    if (mouseSpring == NULL)
        AddMouseSpringConstraint();
                
        // make sure we have a haptic device constraint
    if (hapticDeviceConstraint == NULL)
        AddHapticDeviceConstraint();
                
    x0.resize(particles.size() * kStateSize);
    xFinal.resize(particles.size() * kStateSize);
        
        // clear any velocities
    for (unsigned int i = 0; i < particles.size(); i++)
    {
        particles[i]->v = hduVector3Dd(0,0,0);
    }

    ParticlesStateToArray(&xFinal[0]);

    odeSolver->setSize(particles.size() * kStateSize);

    typedef ConstraintListT::const_iterator LI; // constant because not modifying list
    LI ci;

    for (ci = constraints.begin(); ci != constraints.end(); ++ci)
    {
        Constraint& c = **ci;
        assert(&c != NULL);
                
        c.FlexToSystem(particles);
    }
        
    design = false;
}
Beispiel #13
0
hduVector3Dd HapticDevice::magneticForce(hduVector3Dd* effector,hduVector3Dd* currentTarget,btTransform* invertCamera){
	
	hduVector3Dd force = hduVector3Dd(0,0.1,0.0);

	HDdouble phi = 0.58;

	HDdouble sigma = 10;

	HDdouble s2 = pow(sigma, 2);

	HDdouble fmax = 0.0;

	HDdouble seuil = 0.5;

	hduVector3Dd target = *currentTarget - *effector ;
	
	HDdouble distanceMin = target.magnitude();
	
	/*
	for(unsigned int i = 0; i< m_possibleImpact.size(); i++){

		hduVector3Dd impact = invertTransform(m_possibleImpact[i], invertCamera);

		hduVector3Dd inbetween = impact - *effector ;			

		HDdouble x = inbetween.magnitude();

		HDdouble f = phi * ( pow(x,2)/ s2 ) * std::exp((s2 - pow(x,2))/s2);				
		
		inbetween.normalize();		

		HDdouble d = 1;// 1 si c'est la sible, < 1 sinon 
		if(x >= 0.1) 
			d = distanceMin / x; 

		force += d * f * inbetween;	
		
	}	
	*/

	
	for(int traj = 0; traj < ThronNumber ; traj++){
		for(unsigned int i = 0; i< m_trajectory[traj].size(); i++){			

			if( i % 6 == 0){
				hduVector3Dd impact = invertTransform((m_trajectory[traj])[i], invertCamera);

				hduVector3Dd inbetween = impact - *effector ;			

				HDdouble x = inbetween.magnitude();
				
				//if(inbetween[1] < 3 && inbetween[1] > -3){
				HDdouble f = phi * ( pow(x,2)/ s2 ) * std::exp((s2 - pow(x,2))/s2);				
		
				inbetween.normalize();		

				HDdouble d = 1;// 1 si c'est la sible, < 1 sinon 
				if(x >= 0.1) 
					d = distanceMin / x; 

				force +=  f * inbetween;		
				//}
			}
			
		}	
	}

	//std::cout << " --> "<< std::endl;

	force *= (lamda(max_velocity,m_velocity)/max_velocity);
	return force;
}
Beispiel #14
0
void  HapticDevice::feedback(btDynamicsWorld &dynamic)
{
	for(unsigned int i=0;i<m_nbDevices;i++)
	{
		bool ground_collide = false;
		// free move
		if((m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_1) != 0 )// (m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_2))
		{
			m_hss[i].m_free.m_done = true;	
			//m_hss[i].m_free.m_force = hduVector3Dd(0,0,0);
		}		
		
		if(m_constraints[i] != NULL)
		{
			btRigidBody * myBody = &m_constraints[i]->getRigidBodyB();
		
			btTransform myTrans = myBody->getWorldTransform();			

			m_effRenderPos = myTrans.getOrigin();
			//Check collision  
			if(m_constraints[i]->getUserConstraintPtr() != NULL)
			{  
				//std::cout<< " se cas la " <<std::endl;
				m_hss[i].m_free.m_nbCollision = 1;
				//if((m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_1) != 0 && (m_oldButtons[i] & HD_DEVICE_BUTTON_1) == 0)
				btCollisionObject * object = static_cast<btCollisionObject *>(m_constraints[i]->getUserConstraintPtr());
				
				if(object->getInternalType()== btCollisionObject::CO_RIGID_BODY)
				{
					btRigidBody * collideBody = static_cast<btRigidBody *>(object);	
					// collide with ground
					if(collideBody == m_ground)
					{
						m_hss[i].m_free.m_nbCollision = 2;
						ground_collide = true;
					}
					// collide with other object
					if(collideBody->getInvMass()!=0 && collideBody != m_ground)
					{
							if(m_itsConstraints[i] == NULL )
							{

								// catch it if colide with it
								if((m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_1) == 0 )
								{						
											//create constraint
											btTransform bodyTrans = collideBody->getWorldTransform();
											m_itsConstraints[i]   = createConstraint(*myBody,*collideBody);
											dynamic.addConstraint(m_itsConstraints[i],true);
											m_newConstraint(m_ptr,collideBody,i);
											m_caught = collideBody;
											m_coll = true;	
											m_devine = false;
											showTarget(collideBody);
											deactivateMove();
								}
							}else
								// realise it when button 1 pressed
								if(m_freeT || (m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_1) != 0)
								{
						
										//remove constraint
										dynamic.removeConstraint(m_itsConstraints[i]);
										delete m_itsConstraints[i];
										m_itsConstraints[i]=NULL;
										m_deleteConstraint(m_ptr,collideBody,i);
										//m_hss[i].setThrown(NULL);								
										m_hss[i].m_free.m_done = true;
										showTarget(collideBody);
										m_variator = 0;
										m_coll = false;										
										deactivateMove();
								}
							
					}
					
				}
				

			}
			else
			{
				m_hss[i].m_free.m_nbCollision = 0;
				//if((m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_1) != 0 && (m_oldButtons[i] & HD_DEVICE_BUTTON_1) == 0)
				if(m_freeT || (m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_1) != 0)
				{
					if(m_itsConstraints[i] != NULL )
					{
						//remove constraint
						m_deleteConstraint(m_ptr,&m_itsConstraints[i]->getRigidBodyB(),i);
						dynamic.removeConstraint(m_itsConstraints[i]);
						delete m_itsConstraints[i];
						m_itsConstraints[i]=NULL;
						m_hss[i].m_free.m_done = true;
						if(m_caught != NULL)
							showTarget(m_caught);	
						m_coll = false;						
						deactivateMove();
					}						
					
				}
				
			}

			if(m_itsConstraints[i]!=NULL )
				m_hss[i].m_free.m_nbCollision = 1;			
			else
				// launch an other target
				if((m_hss[i].m_free.m_buttons & HD_DEVICE_BUTTON_2) != 0 && (m_oldButtons[i] & HD_DEVICE_BUTTON_2) == 0)
				{				
				//m_canLaunch = true;				
				}				

			m_oldButtons[i]=m_hss[i].m_free.m_buttons;

			//put back cursor world position into device referencial                         <<<<< ------------------------------
			btTransform offset(btMatrix3x3::getIdentity(),btVector3(0,0,-0.5));
			m_effectors[i].setOrigin(myTrans.getOrigin());
			m_effectors[i].mult(m_effectors[i],offset);
			btVector3 pos = m_cameraViews[i]->inverse()(myTrans.getOrigin());
			pos*=SCALE_WORLD_TO_DEVICE;
			m_hss[i].m_free.m_realPosition.set(pos.getX(),pos.getY(),pos.getZ()+OFFSET_TO_CAMERA); 			

			}
			
			btTransform camInv = m_cameraViews[i]->inverse();
			// compute feed back for ground
			if(ground_collide)
			{
				m_hss[i].m_free.m_force = groundForce(true,&(m_hss[i].m_free.m_position),&camInv);
			}else
				m_hss[i].m_free.m_force = hduVector3Dd(0,0,0);

			// detecte the direction
			HDdouble deplacement = betweenTwoPoints(m_hss[i].m_free.m_atThrowPos,m_hss[i].m_free.m_position);
			HDdouble distanceMax = Distance_max;
			
			hduVector3Dd move = m_hss[i].m_free.m_oldPosition - m_hss[i].m_free.m_position;
		
			
			HDdouble selectedDistance = 0;
			
			if(  m_devine && m_thrownRigids != NULL && m_thrownRigids->size()>0 && deplacement > distanceMax && m_sible == 0 /* && !m_targetChoosen */){
			
				HDdouble distance = Quick_Distance_max;
				//unsigned int targ = 0;
				for(unsigned int j = 0; j<m_thrownRigids->size(); j++){
					
					HDdouble d = distanceToTrajectory(m_hss[i].m_free.m_position,j,&camInv);
									
						if((d)<distance){
							if(m_Thrown != (*m_thrownRigids)[j]){
								m_hss[i].m_free.m_currentThrown = (*m_thrownRigids)[j];
								distance = d;
								m_Thrown = (*m_thrownRigids)[j];		
								m_impactPos = m_possibleImpact[j];
								m_targetChoosen = true;
								if(m_Feedback){																
									activateMove();
								}
								selectedDistance = d;	
								m_index = j;
								m_sible = Nbr_frame_wait;
							
							}
						}
					
				}
				if(m_targetChoosen){
					//showTarget(m_Thrown);
					addPrevious(m_Thrown);
				}
				else
					m_sible = 0;
				//m_time = Time;
			}
			if(m_canLaunch){
				//m_time = Time;
				m_hss[i].m_free.m_done = true;				
				m_variator = 0.001;	
				m_sible = 0;
				m_devine = true;
				deactivateMove();
				cleanHistory();
				m_hss[i].m_free.m_atThrowPos = m_hss[i].m_free.m_position;
			}
			m_hss[i].m_free.m_oldPosition = m_hss[i].m_free.m_position ;
			if(m_hss[i].m_free.m_currentThrown != NULL && m_posSet && m_Feedback ){
												
					hduVector3Dd impact = invertTransform(m_impactPos, &camInv);
					hduVector3Dd pos(m_hss[i].m_free.m_position); 

					btVector3 balltest = ((*m_thrownRigids)[0])->getWorldTransform().getOrigin();
					hduVector3Dd test = invertTransform(&balltest, &camInv);

					m_velocity = m_hss[i].m_free.m_velocity.magnitude();

					if(pos[2]-5 >= test[2]){
						if(!m_hss[i].m_free.m_done){	
					
							//hduVector3Dd helpForce = ForceToImpact(&pos,&impact);	
							
							hduVector3Dd helpForce = magneticForce(&pos, &impact, &camInv);								

							//hduVector3Dd helpForce = atomeForce(&pos, &impact, &camInv);	
						
							if(!helpForce.isZero(EPSILON)){						 	    
							
								hduVector3Dd force = 1.0 * helpForce;												

								m_hss[i].m_free.m_force = force;
								m_Force = force;	

							}else 
								{
								//m_hss[i].m_free.m_force = m_Force;							
								}
				
						}
					}
				
			}			
			hdScheduleSynchronous(sScheduleIn, &m_hss, HD_DEFAULT_SCHEDULER_PRIORITY);
						
			m_selectedDistance = selectedDistance;
			if(m_sible > 0)
				m_sible--;
	}
		
	
}
int WINAPI WinMain(	HINSTANCE	hInstance,				// Instance
                   HINSTANCE	hPrevInstance,				// Previous Instance
                   LPSTR		lpCmdLine,				// Command Line Parameters
                   int		nCmdShow)				// Window Show State
{

    QHWin32* DisplayObject = new QHWin32;//create a display window
	DeviceSpace* deviceSpace = new DeviceSpace;		//Find a Phantom device named "Default PHANToM"
	DisplayObject->tell(deviceSpace);				//tell Quickhaptics that Omni exists
	DisplayObject->setBackgroundColor(0.0,0.0,0.6);

	DisplayObject->setHapticWorkspace(hduVector3Dd(-40,-40.0,-17.0), hduVector3Dd(95,45.0,17.0));

	// Load gums model
	TriMesh* tm = new TriMesh("models/TeethCavityPickModels/dentures-gums.obj");	
	gDentureGum = tm;

	tm->setName("dentureGum");
	tm->setShapeColor(1.0,0.5,0.65);
	tm->setRotation(hduVector3Dd(1.0,0.0,0.0), 45.0);
	tm->setStiffness(0.5);
	tm->setDamping(0.6);
	tm->setFriction(0.3,0.0);
	DisplayObject->tell( tm );//Tell quickhaptics that gums exists

	// Load teeth model
	tm = new TriMesh("models/TeethCavityPickModels/dentures-teeth.obj");
	gDentureTeeth = tm;

	tm->setName("dentureTeeth");
	tm->setRotation(hduVector3Dd(1.0,0.0,0.0), 45.0);
	tm->setStiffness(1.0);
	tm->setDamping(0.0);
	tm->setFriction(0.0,0.2);
	DisplayObject->tell(tm);


	// Load cavity model
	tm = new TriMesh("models/TeethCavityPickModels/dentures-cavity fill.obj");
	gDentureCavityFill = tm;
	tm->setName("dentureCavityFill");
	tm->setRotation(hduVector3Dd(1.0,0.0,0.0), 45.0);
	tm->setPopthrough(0.5);
	tm->setStiffness(0.6);
	tm->setDamping(0.3);
	tm->setFriction(0.5,0.4);
	DisplayObject->tell(tm);


	// Load cavity "target"
	tm = new TriMesh("models/TeethCavityPickModels/dentures-marker.obj");
	gDentureCavity = tm;

	tm->setName("dentureCavity");
	tm->setUnDraggable();
	tm->setRotation(hduVector3Dd(1.0,0.0,0.0), 45.0);
	tm->setStiffness(0.2);
	tm->setDamping(0.4);
	tm->setFriction(0.0,0.0);
	DisplayObject->tell(tm);

	// SensAble logo
	Plane* logoBox = new Plane(15,9);
	logoBox->setTranslation(53.0,-27.0,30.0);
	logoBox->setHapticVisibility(false);
	logoBox->setTexture("models/TeethCavityPickModels/sensableLogo.jpg");
	DisplayObject->tell(logoBox);

	// START button
	Box* box = gStartButton = new Box(20,10,10);
	gStartButton = box;

	box->setName("startButton");
	box->setUnDraggable();
	box->setTranslation(60.0,20.0,0.0);
	box->setRotation(hduVector3Dd(0.0,1.0,0.0), -15.0);
	box->setTexture("models/TeethCavityPickModels/start.jpg");
	DisplayObject->tell(box);

	// RESET button
	box = new Box(20,10,10);
	gResetButton = box;

	box->setName("resetButton");
	box->setUnDraggable();
	box->setTranslation(60.0,-5.0,0.0);
	box->setRotation(hduVector3Dd(0.0,1.0,0.0), -15.0);
	box->setTexture("models/TeethCavityPickModels/reset.jpg");
	DisplayObject->tell(box);


	// Startup Message
	Text* text = new Text (20.0,"Please touch START & press button 1 to begin", 0.25, 0.9);
	gStartupMsg = text;

	text->setName("startupMsg");
	text->setShapeColor(0.0,0.5,0.75);
	text->setHapticVisibility(false);
	text->setGraphicVisibility(true);
	DisplayObject->tell(text);

	// Reset Message
	text = new Text (20.0,"Please touch RESET and press button 1 to Reset the demo", 0.2, 0.85);
	gResetMsg = text;

	text->setName("resetMsg");
	text->setShapeColor(0.0,0.5,0.75);
	text->setHapticVisibility(false);
	text->setGraphicVisibility(false);
	DisplayObject->tell(text);

	// Instruction Message
	text = new Text (20.0,"Please locate the cavity  by probing the teeth", 0.25, 0.9);
	gInstructionMsg = text;

	text->setName("instructionMsg");
	text->setShapeColor(0.0,0.5,0.75);
	text->setHapticVisibility(false);
	text->setGraphicVisibility(false);
	DisplayObject->tell(text);

	// Success Message
	text = new Text (20.0,"OUCH!!&*! You have successfully located the cavity", 0.25, 0.9);
	gSuccessMsg = text;

	text->setName("successMsg");
	text->setShapeColor(1.0,0.35,0.5);
	text->setHapticVisibility(false);
	text->setGraphicVisibility(false);
	DisplayObject->tell(text);

	Cursor* OmniCursor = new Cursor("models/TeethCavityPickModels/dentalPick.obj");//Load a cursor that looks like a dental pick
    TriMesh* cursorModel = OmniCursor->getTriMeshPointer();
    cursorModel->setShapeColor(0.35,0.35,0.35);
	OmniCursor->scaleCursor(0.007);
	OmniCursor->setRelativeShapeOrientation(0.0,0.0,1.0,-90.0);

	//    OmniCursor->debugCursor(); //Use this function the view the location of the proxy inside the Cursor mesh
	DisplayObject->tell(OmniCursor);//Tell QuickHaptics that the cursor exists

	DisplayObject->preDrawCallback(graphicsCallback);


	deviceSpace->button1DownCallback(button1DownCallback, gResetButton);
	deviceSpace->button1DownCallback(button1DownCallback, gDentureGum);
	deviceSpace->button1DownCallback(button1DownCallback, gDentureTeeth);
	deviceSpace->button1DownCallback(button1DownCallback, gDentureCavityFill);
	deviceSpace->button1DownCallback(button1DownCallback, gStartButton);
	deviceSpace->touchCallback(touchCallback, gDentureCavity);

	deviceSpace->button1UpCallback(button1UpCallback);

	qhStart();//Set everything in motion
}
void ParticleSystem::ActivateHapticDeviceConstraint(void)
{
    assert(hapticDeviceConstraint != NULL);
    hapticDeviceConstraint->SetForce(hduVector3Dd(0,0,0));
    hapticDeviceConstraint->SetState(true);
}