コード例 #1
0
ファイル: main.cpp プロジェクト: remis/chai3d
// Add a mass to or remove a mass from the end of the chain
void TForm1::add_ball() {

  // Put this ball to the right of the current last ball
  CBall* b = new CBall();
  m_active_balls.push_back(b);

  int ball_index = m_active_balls.size() - 1;

  CBall* neighbor = m_active_balls[ball_index - 1];

  // Create a position for each ball, moving from left to right
  // with increasing i
  cVector3d pos = neighbor->getPos();
  pos.add(INITIAL_BALL_SPACING,0,0);
  b->setPos(pos);
  world->addChild(b);

  CSpring* s = new CSpring();
  m_active_springs.push_back(s);

  s->m_endpoint_1 = m_active_balls[ball_index];
  s->m_endpoint_2 = m_active_balls[ball_index-1];

  s->m_endpoint_1->m_springs.push_back(s);
  s->m_endpoint_2->m_springs.push_back(s);

  // Set the spring's rest length to be the initial distance between
  // the balls
  double d = cDistance(s->m_endpoint_1->getPos(),s->m_endpoint_2->getPos());
  s->m_rest_length = d;
  world->addChild(s);
}
コード例 #2
0
//===========================================================================
bool cEffectStickSlip::computeForce(const cVector3d& a_toolPos,
                                  const cVector3d& a_toolVel,
                                  const unsigned int& a_toolID,
                                  cVector3d& a_reactionForce)
{
    // check if history for this IDN exists
    if (a_toolID < CHAI_EFFECT_MAX_IDN)
    {
        if (m_parent->m_interactionInside)
        {
            // check if a recent valid point has been stored previously
            if (!m_history[a_toolID].m_valid)
            {
                m_history[a_toolID].m_currentStickPosition = a_toolPos;
                m_history[a_toolID].m_valid = true;
            }

            // read parameters for stick and slip model
            double stiffness = m_parent->m_material.getStickSlipStiffness();
            double forceMax = m_parent->m_material.getStickSlipForceMax();

            // compute current force between last stick position and current tool position
            double distance = cDistance(a_toolPos, m_history[a_toolID].m_currentStickPosition);
            double forceMag = distance * stiffness;

            if (forceMag > 0)
            {
                // if force above threshold, slip...
                if (forceMag > forceMax)
                {
                    m_history[a_toolID].m_currentStickPosition = a_toolPos;
                    a_reactionForce.zero();
                }
                // ...otherwise stick
                else
                {
                    a_reactionForce = (forceMag / distance) * cSub(m_history[a_toolID].m_currentStickPosition, a_toolPos);
                }
            }
            else
            {
                a_reactionForce.zero();
            }

            return (true);
        }
        else
        {
            // the tool is located outside the object, so zero reaction force
            m_history[a_toolID].m_valid = false;
            a_reactionForce.zero();
            return (false);
        }
    }
    else
    {
        a_reactionForce.zero();
        return (false);
    }
}
コード例 #3
0
ファイル: CVector3d.cpp プロジェクト: jateeq/FYDP
//-----------------------------------------------------------------------
double cSegment3d::distanceSquaredToPoint(const cVector3d& a_point,
                                          double& a_t,
                                          cVector3d* a_closestPoint)
{
    double mag = cDistance(m_start,m_end);

    // Project this point onto the line
    a_t = (a_point - m_start) * (m_end - m_start) / (mag * mag);

    // Clip to segment endpoints
    if (a_t < 0.0)
        a_t = 0.0;
    else if (a_t > 1.0)
        a_t = 1.0;

    // Find the intersection point
    cVector3d intersection = m_start + a_t * (m_end - m_start);
    if (a_closestPoint)
    {
        *a_closestPoint = intersection;
    }
    
    // Compute distance
    return cDistanceSq(a_point,intersection);
}
コード例 #4
0
//==============================================================================
void cDrawArrow(const cVector3d& a_arrowStart, 
                const cVector3d& a_arrowTip, 
                const double a_width)
{
#ifdef C_USE_OPENGL

    glPushMatrix();

    // We don't really care about the up vector, but it can't
    // be parallel to the arrow...
    cVector3d up = cVector3d(0,1,0);
    cVector3d arrow = a_arrowTip-a_arrowStart;
    arrow.normalize();
    double d = fabs(cDot(up,arrow));
    if (d > .9)
    {
        up = cVector3d(1,0,0);
    }

    cLookAt(a_arrowStart, a_arrowTip, up);
    double distance = cDistance(a_arrowTip,a_arrowStart);

    // This flips the z axis around
    glRotatef(180,1,0,0);

    // create a new OpenGL quadratic object 
    GLUquadricObj *quadObj;
    quadObj = gluNewQuadric();

    #define ARROW_CYLINDER_PORTION 0.75
    #define ARRROW_CONE_PORTION (1.0 - 0.75)

    // set rendering style
    gluQuadricDrawStyle(quadObj, GLU_FILL);

    // set normal-rendering mode
    gluQuadricNormals(quadObj, GLU_SMOOTH);

    // render a cylinder and a cone
    glRotatef(180,1,0,0);
    gluDisk(quadObj,0,a_width,10,10);
    glRotatef(180,1,0,0);

    gluCylinder(quadObj, a_width, a_width, distance*ARROW_CYLINDER_PORTION, 10, 10);
    glTranslated(0, 0, ARROW_CYLINDER_PORTION*distance);

    glRotatef(180, 1, 0, 0);
    gluDisk(quadObj, 0, a_width*2.0, 10, 10);
    glRotatef(180,1,0,0);

    gluCylinder(quadObj, a_width*2.0, 0.0, distance*ARRROW_CONE_PORTION, 10, 10);

    // delete our quadric object
    gluDeleteQuadric(quadObj);

    glPopMatrix();

#endif
}
コード例 #5
0
//==============================================================================
bool cEffectMagnet::computeForce(const cVector3d& a_toolPos,
                                 const cVector3d& a_toolVel,
                                 const unsigned int& a_toolID,
                                 cVector3d& a_reactionForce)
{
    // compute distance from object to tool
    double distance = cDistance(a_toolPos, m_parent->m_interactionPoint);

    // get parameters of magnet
    double magnetMaxForce = m_parent->m_material->getMagnetMaxForce();
    double magnetMaxDistance = m_parent->m_material->getMagnetMaxDistance();
    double stiffness = m_parent->m_material->getStiffness();
    double forceMagnitude = 0;

    if (m_enabledInside || (!m_parent->m_interactionInside))
    {
        if ((distance < magnetMaxDistance) && (stiffness > 0))
        {
            double d = magnetMaxForce / stiffness;
            if (distance < d)
            {
                forceMagnitude = stiffness * distance;
            }
            else
            {
                double dx = (magnetMaxDistance - d);
                if (dx > 0)
                {
                    double k = magnetMaxForce / dx;
                    forceMagnitude = k * (magnetMaxDistance - distance);
                }
            }

            // compute reaction force
            int sign = -1;
            if (m_parent->m_interactionInside)
            {
                sign = 1;
            }

            a_reactionForce = cMul(sign * forceMagnitude, m_parent->m_interactionNormal);

            return (true);
        }
        else
        {
            return (false);
        }
    }
    else
    {
        // the tool is located outside the magnet zone
        a_reactionForce.zero();
        return (false);
    }
}
コード例 #6
0
//===========================================================================
cCollisionSpheresLine::cCollisionSpheresLine(cVector3d& a_segmentPointA,
                                             cVector3d& a_segmentPointB)
{
    // calculate the center of the line segment
    m_center = cMul(0.5, cAdd(a_segmentPointA, a_segmentPointB));

    // calculate the radius of the bounding sphere as the distance from the
    // center of the segment (calculated above) to an endpoint
    m_radius = cDistance(m_center, a_segmentPointA);

    // store segment
    m_segmentPointA = a_segmentPointA;
    m_segmentPointB = a_segmentPointB;
}
コード例 #7
0
//===========================================================================
cGELLinearSpring::cGELLinearSpring(cGELMassParticle* a_node0, cGELMassParticle* a_node1)
{
    // set nodes:
    m_node0 = a_node0;
    m_node1 = a_node1;
	m_enabled = true;

    // set default color
    m_color = default_color;

    // compute initial length
    m_length0 = cDistance(m_node1->m_pos, m_node0->m_pos);

    // set elongation spring constant [N/M]
    m_kSpringElongation = default_kSpringElongation;
}
コード例 #8
0
ファイル: CCamera.cpp プロジェクト: flair2005/chai3d
//===========================================================================
void cCamera::adjustClippingPlanes()
{
    // check if world is valid
    cWorld* world = getParentWorld();
    if (world == NULL) { return; }

    // compute size of the world
    world->computeBoundaryBox(true);

    // compute a distance slightly larger the world size
    cVector3d max = world->getBoundaryMax();
    cVector3d min = world->getBoundaryMin();
    double distance = 2.0 * cDistance(min, max);

    // update clipping plane:
    setClippingPlanes(distance / 1000.0, distance);
}
コード例 #9
0
ファイル: main.cpp プロジェクト: remis/chai3d
void TForm1::compute_spring_forces()
{
    double curtime = g_timer.GetTime();

    if (g_last_iteration_time < 0)
    {
      g_last_iteration_time = curtime;
      return;
    }

    double elapsed = curtime - g_last_iteration_time;
    g_last_iteration_time = curtime;

    unsigned int i;

    // Clear the force that's applied to each ball
    for(i=0; i<m_active_balls.size(); i++)
    {
        m_active_balls[i]->current_force.set(0,0,0);
    }

    if (simulationOn)
    {
        CBall* b = m_active_balls[0];
        cVector3d old_p = b->getPos();
        b->setPos(tool->m_deviceGlobalPos);
        b->m_velocity = cDiv(elapsed,cSub(b->getPos(),old_p));
    }

    // Compute the current length of each spring and apply forces
    // on each mass accordingly
    for(i=0; i<m_active_springs.size(); i++)
    {
        CSpring* s = m_active_springs[i];

        double d = cDistance(s->m_endpoint_1->getPos(),s->m_endpoint_2->getPos());
        s->m_current_length = d;

        // This spring's deviation from its rest length
        //
        // (positive deviation -> spring is too long)
        double x = s->m_current_length - s->m_rest_length;

        // Apply a force to ball 1 that pulls it toward ball 2
        // when the spring is too long
        cVector3d f1 = cMul(s->m_spring_constant*x*1.0,
          cSub(s->m_endpoint_2->getPos(),s->m_endpoint_1->getPos()));
        s->m_endpoint_1->current_force.add(f1);

        // Add the opposite force to ball 2
        s->m_endpoint_2->current_force.add(cMul(-1.0,f1));
    }

    // Update velocities and positions based on forces
    for(i=0; i<m_active_balls.size(); i++)
    {
        CBall* b = m_active_balls[i];

        // Certain forces don't get applied to the "haptic ball"
        // when haptics are enabled...
        if (simulationOn == 0 || i != 0) {
          cVector3d f_damping = cMul(DAMPING_CONSTANT,b->m_velocity);
          b->current_force.add(f_damping);
        }

        cVector3d f_gravity(0,GRAVITY_CONSTANT*b->m_mass,0);
        b->current_force.add(f_gravity);

        cVector3d p = b->getPos();

        if (p.y - b->m_radius < FLOOR_Y_POSITION) {
          double penetration = FLOOR_Y_POSITION - (p.y - b->m_radius);
          b->current_force.add(0,m_floor_spring_constant*penetration,0);
        }

        cVector3d f_floor(0,0,0);

        cVector3d a = cDiv(b->m_mass,b->current_force);

        b->m_velocity.add(cMul(elapsed,a));

        // We handle the 0th ball specially when haptics is enabled
        if (simulationOn == 0 || i != 0) {
          p.add(cMul(elapsed,b->m_velocity));
          b->setPos(p);
        }
    }

    // Set the haptic force appropriately to reflect the force
    // applied to ball 0
    m_haptic_force = cMul(HAPTIC_FORCE_CONSTANT,m_active_balls[0]->current_force);
}
コード例 #10
0
ファイル: CEffectMagnet.cpp プロジェクト: jateeq/FYDP
//===========================================================================
bool cEffectMagnet::computeForce(const cVector3d& a_toolPos,
                                  const cVector3d& a_toolVel,
                                  const unsigned int& a_toolID,
                                  cVector3d& a_reactionForce)
{
    // compute distance from object to tool
    double distance = cDistance(a_toolPos, m_parent->m_interactionProjectedPoint);

    // get parameters of magnet
    double magnetMaxForce = m_parent->m_material.getMagnetMaxForce();
    double magnetMaxDistance = m_parent->m_material.getMagnetMaxDistance();
    double stiffness = m_parent->m_material.getStiffness();
    double forceMagnitude = 0;

    if ((distance > 0) && (distance < magnetMaxDistance) && (stiffness > 0))
    {
        double limitLinearModel = magnetMaxForce / stiffness;
        cClamp(limitLinearModel, 0.0, 0.5 * distance);

        if (distance < limitLinearModel)
        {
            // apply local linear model near magnet
            forceMagnitude = stiffness * distance;
        }
        else
        {
            // compute quadratic model
            cMatrix3d sys;
            sys.m[0][0] = limitLinearModel * limitLinearModel;
            sys.m[0][1] = limitLinearModel;
            sys.m[0][2] = 1.0;
            sys.m[1][0] = magnetMaxDistance * magnetMaxDistance;
            sys.m[1][1] = magnetMaxDistance;
            sys.m[1][2] = 1.0;
            sys.m[2][0] = 2.0 * limitLinearModel;
            sys.m[2][1] = 1.0;
            sys.m[2][2] = 0.0;
            sys.invert();

            cVector3d param;
            sys.mulr(cVector3d(magnetMaxForce, 0.0, -1.0), param);

            // apply quadratic model
            double val = distance - limitLinearModel;
            forceMagnitude = param.x * val * val + param.y * val + param.z;
        }

        // compute magnetic force
        a_reactionForce = cMul(forceMagnitude, cNormalize(cSub(m_parent->m_interactionProjectedPoint, a_toolPos)));

        // add damping component
        double viscosity = m_parent->m_material.getViscosity();
        cVector3d viscousForce = cMul(-viscosity, a_toolVel);
        a_reactionForce.add(viscousForce);

        return (true);
    }
    else
    {
        // the tool is located outside the magnet zone
        a_reactionForce.zero();
        return (false);
    }
}
コード例 #11
0
bool ch_proxyPointForceAlgo::computeNextProxyPositionWithContraints00(const cVector3d& a_goalGlobalPos, const cVector3d& a_toolVel)
{
    // We define the goal position of the proxy.
    cVector3d goalGlobalPos = a_goalGlobalPos;

    // To address numerical errors of the computer, we make sure to keep the proxy
    // slightly above any triangle and not directly on it. If we are using a radius of
    // zero, we need to define a default small value for epsilon
    m_epsilonInitialValue = cAbs(0.0001 * m_radius);
    if (m_epsilonInitialValue < m_epsilonBaseValue)
    {
        m_epsilonInitialValue = m_epsilonBaseValue;
    }

    // The epsilon value is dynamic (can be reduced). We set it to its initial
    // value if the proxy is not touching any triangle.
    if (m_numContacts == 0)
    {
        m_epsilon = m_epsilonInitialValue;
        m_slipping = true;
    }

    // If the distance between the proxy and the goal position (device) is
    // very small then we can be considered done.
    if (!m_useDynamicProxy)
    {
        if (goalAchieved(m_proxyGlobalPos, goalGlobalPos))
        {
            m_nextBestProxyGlobalPos = m_proxyGlobalPos;
            m_algoCounter = 0;
            return (false);
        }
    }

    // compute the normalized form of the vector going from the
    // current proxy position to the desired goal position

    // compute the distance between the proxy and the goal positions
    double distanceProxyGoal = cDistance(m_proxyGlobalPos, goalGlobalPos);

    // A vector from the proxy to the goal
    cVector3d vProxyToGoal;
    cVector3d vProxyToGoalNormalized;
    bool proxyAndDeviceEqual;

    if (distanceProxyGoal > m_epsilon)
    {
        // proxy and goal are sufficiently distant from each other
        goalGlobalPos.subr(m_proxyGlobalPos, vProxyToGoal);
        vProxyToGoal.normalizer(vProxyToGoalNormalized);
        proxyAndDeviceEqual = false;
    }
    else
    {
        // proxy and goal are very close to each other
        vProxyToGoal.zero();
        vProxyToGoalNormalized.zero();
        proxyAndDeviceEqual = true;
    }

    // Test whether the path from the proxy to the goal is obstructed.
    // For this we create a segment that goes from the proxy position to
    // the goal position plus a little extra to take into account the
    // physical radius of the proxy.
    cVector3d targetPos;
    if (m_useDynamicProxy)
    {
        targetPos = goalGlobalPos;
    }
    else
    {
        targetPos = goalGlobalPos +
                    cMul(m_epsilonCollisionDetection, vProxyToGoalNormalized);
    }

    // setup collision detector
    // m_radius is the radius of the proxy
    m_collisionSettings.m_collisionRadius = m_radius;

    // Search for a collision between the first segment (proxy-device)
    // and the environment.
    m_collisionSettings.m_adjustObjectMotion = m_useDynamicProxy;
    m_collisionRecorderConstraint0.clear();
    bool hit = m_world->computeCollisionDetection(m_proxyGlobalPos,
               targetPos,
               m_collisionRecorderConstraint0,
               m_collisionSettings);


    // check if collision occurred between proxy and goal positions.
    double collisionDistance;
    if (hit)
    {
        collisionDistance = sqrt(m_collisionRecorderConstraint0.m_nearestCollision.m_squareDistance);
        if (m_useDynamicProxy)
        {
            // retrieve new position of proxy
            cVector3d posLocal = m_collisionRecorderConstraint0.m_nearestCollision.m_adjustedSegmentAPoint;
            cGenericObject* obj = m_collisionRecorderConstraint0.m_nearestCollision.m_object;
            cVector3d posGlobal = cAdd(obj->getGlobalPos(), cMul( obj->getGlobalRot(), posLocal ));
            m_proxyGlobalPos = posGlobal;

            distanceProxyGoal = cDistance(m_proxyGlobalPos, goalGlobalPos);
            goalGlobalPos.subr(m_proxyGlobalPos, vProxyToGoal);
            vProxyToGoal.normalizer(vProxyToGoalNormalized);
        }


        if (collisionDistance > (distanceProxyGoal + CHAI_SMALL))
        {
            // just to make sure that the collision point lies on the proxy-goal segment and not outside of it
            hit = false;
        }


        if (hit)
        {
            // a collision has occurred and we check if the distance from the
            // proxy to the collision is smaller than epsilon. If yes, then
            // we reduce the epsilon term in order to avoid possible "pop through"
            // effect if we suddenly push the proxy "up" again.
            if (collisionDistance < m_epsilon)
            {
                m_epsilon = collisionDistance;
                if (m_epsilon < m_epsilonMinimalValue)
                {
                    m_epsilon = m_epsilonMinimalValue;
                }
            }
        }
    }

    // If no collision occurs, then we move the proxy to its goal, and we're done
    if (!hit)
    {
        m_numContacts = 0;
        m_algoCounter = 0;
        m_slipping = true;
        m_nextBestProxyGlobalPos = goalGlobalPos;
        return (false);
    }

    // a first collision has occurred
    m_algoCounter = 1;

    //-----------------------------------------------------------------------
    // FIRST COLLISION OCCURES:
    //-----------------------------------------------------------------------

    // We want the center of the proxy to move as far toward the triangle as it can,
    // but we want it to stop when the _sphere_ representing the proxy hits the
    // triangle.  We want to compute how far the proxy center will have to
    // be pushed _away_ from the collision point - along the vector from the proxy
    // to the goal - to keep a distance m_radius between the proxy center and the
    // triangle.
    //
    // So we compute the cosine of the angle between the normal and proxy-goal vector...
    double cosAngle = vProxyToGoalNormalized.dot(m_collisionRecorderConstraint0.m_nearestCollision.m_globalNormal);

    // Now we compute how far away from the collision point - _backwards_
    // along vProxyGoal - we have to put the proxy to keep it from penetrating
    // the triangle.
    //
    // If only ASCII art were a little more expressive...
    double distanceTriangleProxy = m_epsilon / cAbs(cosAngle);
    if (distanceTriangleProxy > collisionDistance) {
        distanceTriangleProxy = cMax(collisionDistance, m_epsilon);
    }

    // We compute the projection of the vector between the proxy and the collision
    // point onto the normal of the triangle.  This is the direction in which
    // we'll move the _goal_ to "push it away" from the triangle (to account for
    // the radius of the proxy).

    // A vector from the most recent collision point to the proxy
    cVector3d vCollisionToProxy;
    m_proxyGlobalPos.subr(m_contactPoint0->m_globalPos, vCollisionToProxy);

    // Move the proxy to the collision point, minus the distance along the
    // movement vector that we computed above.
    //
    // Note that we're adjusting the 'proxy' variable, which is just a local
    // copy of the proxy position.  We still might decide not to move the
    // 'real' proxy due to friction.
    cVector3d vColNextGoal;
    vProxyToGoalNormalized.mulr(-distanceTriangleProxy, vColNextGoal);
    cVector3d nextProxyPos;
    m_contactPoint0->m_globalPos.addr(vColNextGoal, nextProxyPos);

    // we can now set the next position of the proxy
    m_nextBestProxyGlobalPos = nextProxyPos;


    // If the distance between the proxy and the goal position (device) is
    // very small then we can be considered done.
    if (goalAchieved(goalGlobalPos, nextProxyPos))
    {
        m_numContacts = 1;
        m_algoCounter = 0;
        return (true);
    }

    return (true);
}
コード例 #12
0
// ch lab ---to be filled in by the students---
// Overriden from class cProxyPointForceAlgo
// Here, a_goal has been computed by collision detection above as the constrained goal towards which
// the proxy should be moved. But before moving it freely to that location, let us check if friction allows
// us to do so. we answer the question: to what extent along the proxy-goal segment can we forward the proxy?
void ch_proxyPointForceAlgo::testFrictionAndMoveProxy(const cVector3d& a_goal, const cVector3d& a_proxy, cVector3d& a_normal, cGenericObject* a_parent, const cVector3d& a_toolVel)
{

    // In this method, our aim is to calculate the the next best position for the proxy (m_nextBestProxyGlobalPos), considering friction.
    // Among other things, we are given the goal position (a_goal), the current proxy position (a_proxy), the parent object (a_parent),
    // the tool velocity (a_toolVel)


    // We will use this variable to determine if we should use the static or the dynamic
    // friction coeff to compute current frictional force.
    static double last_device_vel;



    // friction coefficients assigned to object surface
    cMesh* parent_mesh = dynamic_cast<cMesh*>(a_parent);

    // Right now we can only work with cMesh's
    if (parent_mesh == NULL)
    {
        m_nextBestProxyGlobalPos = a_goal;
        return;
    }

    // read friction coefficients here
    // -----------------------your code here------------------------------------
    double dynamic_coeff = parent_mesh->m_material.getDynamicFriction();
    double static_coeff = parent_mesh->m_material.getStaticFriction();



    // find the penetration depth of the actual device position from the nominal object surface
    double pen_depth = cDistance(a_goal, m_deviceGlobalPos);

    // shall we use the static or the dynamic friction coeff. for the cone radius calculation?
    double cone_radius;
    if(last_device_vel < SMALL_VEL)
    {
        //// the radius of the friction cone
        //-----------------------your code here------------------------------------
        cone_radius = static_coeff*pen_depth;
    }
    else
    {
        //// the radius of the friction cone
        //-----------------------your code here------------------------------------
        cone_radius = dynamic_coeff*pen_depth;
    }

    // vector from the current proxy position to the new sub-goal
    cVector3d a_proxyGoal, a_proxyGoalNormalized;
    a_goal.subr(a_proxy, a_proxyGoal);

    // normalize the proxy goal vector
    a_proxyGoal.normalizer(a_proxyGoalNormalized);

    double a_proxyGoalLength = a_proxyGoal.length();

    if(a_proxyGoalLength < cone_radius)
        // The proxy is inside the friction cone already.
        return;
    else
    {
        // The proxy is outside the friction cone, we should advance it towards the cone circumference,
        // along the vector from the current proxy position to the current goal position

        //-----------------------your code here------------------------------------
        // calculate a value for m_nextBestProxyGlobalPos
        m_nextBestProxyGlobalPos=a_proxy+(a_proxyGoalLength-cone_radius)*a_proxyGoalNormalized;
    }

    // record last velocity in order to decide if static or dynamic friction is to be applied during the
    // next iteration
    last_device_vel = a_toolVel.length();
}
コード例 #13
0
bool ch_proxyPointForceAlgo::computeNextProxyPositionWithContraints22(const cVector3d& a_goalGlobalPos, const cVector3d& a_toolVel)
{
    // The proxy is now constrained by two triangles and can only move along
    // a virtual line; we now calculate the nearest point to the original
    // goal (device position) along this line by projecting the ideal
    // goal onto the line.
    //
    // The line is expressed by the cross product of both surface normals,
    // which have both been oriented to point away from the device
    cVector3d line;
    m_collisionRecorderConstraint0.m_nearestCollision.m_globalNormal.crossr(m_collisionRecorderConstraint1.m_nearestCollision.m_globalNormal, line);

    // check result.
    if (line.equals(cVector3d(0,0,0)))
    {
        m_nextBestProxyGlobalPos = m_proxyGlobalPos;
        m_algoCounter = 0;
        m_numContacts = 2;
        return (false);
    }

    line.normalize();

    // Compute the projection of the device position (goal) onto the line; this
    // gives us the new goal position.
    cVector3d goalGlobalPos = cProjectPointOnLine(a_goalGlobalPos, m_proxyGlobalPos, line);

    // A vector from the proxy to the goal
    cVector3d vProxyToGoal;
    goalGlobalPos.subr(m_proxyGlobalPos, vProxyToGoal);

    // If the distance between the proxy and the goal position (device) is
    // very small then we can be considered done.
    if (goalAchieved(m_proxyGlobalPos, goalGlobalPos))
    {
        m_nextBestProxyGlobalPos = m_proxyGlobalPos;
        m_algoCounter = 0;
        m_numContacts = 2;
        return (false);
    }

    // compute the normalized form of the vector going from the
    // current proxy position to the desired goal position
    cVector3d vProxyToGoalNormalized;
    vProxyToGoal.normalizer(vProxyToGoalNormalized);

    // Test whether the path from the proxy to the goal is obstructed.
    // For this we create a segment that goes from the proxy position to
    // the goal position plus a little extra to take into account the
    // physical radius of the proxy.
    cVector3d targetPos = goalGlobalPos +
                          cMul(m_epsilonCollisionDetection, vProxyToGoalNormalized);

    // setup collision detector
    m_collisionSettings.m_collisionRadius = m_radius;

    // search for collision
    m_collisionSettings.m_adjustObjectMotion = false;
    m_collisionRecorderConstraint2.clear();
    bool hit = m_world->computeCollisionDetection( m_proxyGlobalPos,
               targetPos,
               m_collisionRecorderConstraint2,
               m_collisionSettings);

    // check if collision occurred between proxy and goal positions.
    double collisionDistance;
    if (hit)
    {
        collisionDistance = sqrt(m_collisionRecorderConstraint2.m_nearestCollision.m_squareDistance);
        if (collisionDistance > (cDistance(m_proxyGlobalPos, goalGlobalPos) + CHAI_SMALL))
        {
            hit = false;
        }
        else
        {
            // a collision has occurred and we check if the distance from the
            // proxy to the collision is smaller than epsilon. If yes, then
            // we reduce the epsilon term in order to avoid possible "pop through"
            // effect if we suddenly push the proxy "up" again.
            if (collisionDistance < m_epsilon)
            {
                m_epsilon = collisionDistance;
                if (m_epsilon < m_epsilonMinimalValue)
                {
                    m_epsilon = m_epsilonMinimalValue;
                }
            }
        }
    }

    // If no collision occurs, we move the proxy to its goal, unless
    // friction prevents us from doing so
    if (!hit)
    {
        cVector3d normal = cMul(0.5,cAdd(m_collisionRecorderConstraint0.m_nearestCollision.m_globalNormal,
                                         m_collisionRecorderConstraint1.m_nearestCollision.m_globalNormal));

        testFrictionAndMoveProxy(goalGlobalPos,
                                 m_proxyGlobalPos,
                                 normal,
                                 m_collisionRecorderConstraint1.m_nearestCollision.m_triangle->getParent(), a_toolVel);
        m_numContacts = 2;
        m_algoCounter = 0;

        return (false);
    }

    //-----------------------------------------------------------------------
    // THIRD COLLISION OCCURES:
    //-----------------------------------------------------------------------
    // We want the center of the proxy to move as far toward the triangle as it can,
    // but we want it to stop when the _sphere_ representing the proxy hits the
    // triangle.  We want to compute how far the proxy center will have to
    // be pushed _away_ from the collision point - along the vector from the proxy
    // to the goal - to keep a distance m_radius between the proxy center and the
    // triangle.
    //
    // So we compute the cosine of the angle between the normal and proxy-goal vector...
    double cosAngle = vProxyToGoalNormalized.dot(m_collisionRecorderConstraint2.m_nearestCollision.m_globalNormal);

    // Now we compute how far away from the collision point - _backwards_
    // along vProxyGoal - we have to put the proxy to keep it from penetrating
    // the triangle.
    //
    // If only ASCII art were a little more expressive...
    double distanceTriangleProxy = m_epsilon / cAbs(cosAngle);
    if (distanceTriangleProxy > collisionDistance) {
        distanceTriangleProxy = cMax(collisionDistance, m_epsilon);
    }

    // We compute the projection of the vector between the proxy and the collision
    // point onto the normal of the triangle.  This is the direction in which
    // we'll move the _goal_ to "push it away" from the triangle (to account for
    // the radius of the proxy).

    // A vector from the most recent collision point to the proxy
    cVector3d vCollisionToProxy;
    m_proxyGlobalPos.subr(m_contactPoint2->m_globalPos, vCollisionToProxy);

    // Move the proxy to the collision point, minus the distance along the
    // movement vector that we computed above.
    //
    // Note that we're adjusting the 'proxy' variable, which is just a local
    // copy of the proxy position.  We still might decide not to move the
    // 'real' proxy due to friction.
    cVector3d vColNextGoal;
    vProxyToGoalNormalized.mulr(-distanceTriangleProxy, vColNextGoal);
    cVector3d nextProxyPos;
    m_contactPoint2->m_globalPos.addr(vColNextGoal, nextProxyPos);

    // we can now set the next position of the proxy
    m_nextBestProxyGlobalPos = nextProxyPos;
    m_algoCounter = 0;
    m_numContacts = 3;

    // TODO: There actually should be a third friction test to see if we
    // can make it to our new goal position, but this is generally such a
    // small movement in one iteration that it's irrelevant...

    return (true);
}
コード例 #14
0
ファイル: 20-map.cpp プロジェクト: jateeq/FYDP
void updateHaptics(void)
{
    // state machine
    const int STATE_IDLE            = 1;
    const int STATE_MODIFY_MAP      = 2;
    const int STATE_MOVE_CAMERA     = 3;
    int state = STATE_IDLE;  

    // current tool position
    cVector3d toolGlobalPos;        // global world coordinates
    cVector3d toolLocalPos;         // local coordinates

    // previous tool position
    cVector3d prevToolGlobalPos;    // global world coordinates
    cVector3d prevToolLocalPos;     // local coordinates

    // main haptic simulation loop
    while(simulationRunning)
    {
        // compute global reference frames for each object
        world->computeGlobalPositions(true);

        // update position and orientation of tool
        tool->updatePose();

        // compute interaction forces
        tool->computeInteractionForces();

        // read user switch
        bool userSwitch = tool->getUserSwitch(0);

        // update tool position
        toolGlobalPos = tool->getDeviceGlobalPos();
        toolLocalPos  = tool->getDeviceLocalPos();

        if ((state == STATE_MOVE_CAMERA) && (!userSwitch))
        {
            state = STATE_IDLE;

            // enable haptic interaction with map
            object->setHapticEnabled(true, true);
        }

        else if (((state == STATE_MODIFY_MAP) && (!userSwitch)) ||
            ((state == STATE_MODIFY_MAP) && (!tool->isInContact(magneticLine))))
        {
            state = STATE_IDLE;

            // disable magnetic line
            magneticLine->setHapticEnabled(false);
            magneticLine->setShowEnabled(false);

            // disable spheres
            sphereA->setShowEnabled(false);
            sphereB->setShowEnabled(false);

            // enable haptic interaction with map
            object->setHapticEnabled(true, true);

            // disable forces
            tool->setForcesOFF();

            // update bounding box (can take a little time)
            object->createAABBCollisionDetector(1.01 * proxyRadius, true, false);
            
            // enable forces again
            tool->setForcesON();
        }

        // user clicks with the mouse
        else if ((state == STATE_IDLE) && (userSwitch))
        {
            // start deforming object
            if (tool->isInContact(object))
            {
                state = STATE_MODIFY_MAP;

                // update position of line
                cVector3d posA = toolGlobalPos;
                posA.z =-0.7;

                cVector3d posB = toolGlobalPos;
                posB.z = 0.7;

                magneticLine->m_pointA = posA;
                magneticLine->m_pointB = posB;

                // update position of spheres
                sphereA->setPos(posA);
                sphereB->setPos(posB);

                // enable spheres
                sphereA->setShowEnabled(true);
                sphereB->setShowEnabled(true);

                // enable magnetic line
                magneticLine->setHapticEnabled(true);
                magneticLine->setShowEnabled(true);

                // disable haptic interaction with map
                object->setHapticEnabled(false, true);
            }

            // start moving camera
            else
            {
                state = STATE_MOVE_CAMERA;
                
                // disable haptic interaction with map
                object->setHapticEnabled(false, true);
            }
        }

        // modify map
        else if (state == STATE_MODIFY_MAP)
        {
            // compute tool offset
            cVector3d offset = toolGlobalPos - prevToolGlobalPos;

            // map offset on z axis
            double offsetHeight = offset.z;

            // apply offset to all vertices through a weighted function
            int numVertices = object->getNumVertices(true);
            for (int i=0; i<numVertices; i++)
            {
                // get next vertex
                cVertex* vertex = object->getVertex(i, true);

                // compute distance between vertex and tool
                cVector3d posTool = tool->getProxyGlobalPos();
                cVector3d posVertex = vertex->getPos();
                double distance = cDistance(posTool, posVertex);

                // compute factor
                double RADIUS = 0.4;
                double relativeDistance = distance / RADIUS;
                double clampedRelativeDistance = cClamp01(relativeDistance);
                double w = 0.5 + 0.5 * cos(clampedRelativeDistance * CHAI_PI);

                // apply offset
                double offsetVertexHeight = w * offsetHeight;
                posVertex.z = posVertex.z + offsetVertexHeight;
                vertex->setPos(posVertex);
            }
        }

        // move camera
        else if (state == STATE_MOVE_CAMERA)
        {
            // compute tool offset
            cVector3d offset = toolLocalPos - prevToolLocalPos;

            // apply camera motion
            cameraDistance = cameraDistance - 2 * offset.x;
            cameraAngleH = cameraAngleH - 40 * offset.y;
            cameraAngleV = cameraAngleV - 40 * offset.z;

            updateCameraPosition();   
        }

        // store tool position
        prevToolLocalPos  = toolLocalPos;
        prevToolGlobalPos = toolGlobalPos;

        // send forces to device
        tool->applyForces();
    }
    
    // exit haptics thread
    simulationFinished = true;
}
コード例 #15
0
ファイル: CGELMesh.cpp プロジェクト: flair2005/chai3d
//===========================================================================
void cGELMesh::connectVerticesToSkeleton(bool a_connectToNodesOnly)
{
    // get number of vertices
    int numVertices = m_gelVertices.size();

    // for each deformable vertex we search for the nearest sphere or link
    for (int i=0; i<numVertices; i++)
    {
        // get current deformable vertex
        cGELVertex* curVertex = &m_gelVertices[i];

        // get current vertex position
        cVector3d pos = curVertex->m_vertex->getPos();

        // initialize constant
        double min_distance = 99999999999999999.0;
        cGELSkeletonNode* nearest_node = NULL;
        cGELSkeletonLink* nearest_link = NULL;

        // search for the nearest node
		list<cGELSkeletonNode*>::iterator itr;
        for(itr = m_nodes.begin(); itr != m_nodes.end(); ++itr)
        {
            cGELSkeletonNode* nextNode = *itr;
            double distance = cDistance(pos, nextNode->m_pos);
            if (distance < min_distance)
            {
                min_distance = distance;
                nearest_node = nextNode;
                nearest_link = NULL;
            }
        }

        // search for the nearest link if any
        if (!a_connectToNodesOnly)
        {
            list<cGELSkeletonLink*>::iterator j;
            for(j = m_links.begin(); j != m_links.end(); ++j)
            {
                cGELSkeletonLink* nextLink = *j;
                double angle0 = cAngle(nextLink->m_wLink01, cSub(pos, nextLink->m_node0->m_pos));
                double angle1 = cAngle(nextLink->m_wLink10, cSub(pos, nextLink->m_node1->m_pos));

                if ((angle0 < (CHAI_PI / 2.0)) && (angle1 < (CHAI_PI / 2.0)))
                {
                    cVector3d p = cProjectPointOnLine(pos,
                                                      nextLink->m_node0->m_pos,
                                                      nextLink->m_wLink01);

                    double distance = cDistance(pos, p);

                    if (distance < min_distance)
                    {
                        min_distance = distance;
                        nearest_node = NULL;
                        nearest_link = nextLink;
                    }
                }
            }
        }

        // attach vertex to nearest node if it exists
        if (nearest_node != NULL)
        {
            curVertex->m_node = nearest_node;
            curVertex->m_link = NULL;
            cVector3d posRel = cSub(pos, nearest_node->m_pos);
            curVertex->m_massParticle->m_pos = cMul(cTrans(nearest_node->m_rot), posRel);
        }

        // attach vertex to nearest link if it exists
        else if (nearest_link != NULL)
        {
            curVertex->m_node = NULL;
            curVertex->m_link = nearest_link;

            cMatrix3d rot;
            rot.setCol( nearest_link->m_A0,
                        nearest_link->m_B0,
                        nearest_link->m_wLink01);
            cVector3d posRel = cSub(pos, nearest_link->m_node0->m_pos);
            curVertex->m_massParticle->m_pos = cMul(cInv(rot), posRel);
        }
    }
}