Пример #1
0
//===========================================================================
bool cCollisionBrute::computeCollision(cVector3d& a_segmentPointA,
                                       cVector3d& a_segmentPointB,
                                       cGenericObject*& a_colObject,
                                       cTriangle*& a_colTriangle,
                                       cVector3d& a_colPoint,
                                       double& a_colSquareDistance,
                                       int a_proxyCall)
{
    // temp variables for storing results
    cGenericObject* colObject;
    cTriangle* colTriangle;
    cVector3d colPoint;
    bool hit = false;

    // convert two point segment into a segment described by a point and
    // a directional vector
    cVector3d dir;
    a_segmentPointB.subr(a_segmentPointA, dir);

    // compute the squared length of the segment
    double colSquareDistance = dir.lengthsq();

    // check all triangles for collision and return the nearest one
    unsigned int ntriangles = m_triangles->size();
    for (unsigned int i=0; i<ntriangles; i++)
    {

        // check for a collision between this triangle and the segment by
        // calling the triangle's collision detection method; it will only
        // return true if the distance between the segment origin and this
        // triangle is less than the current closest intersecting triangle
        // (whose distance squared is kept in colSquareDistance)
        if ((*m_triangles)[i].computeCollision(
            a_segmentPointA, dir, colObject, colTriangle, colPoint, colSquareDistance))
        {
            a_colObject = colObject;
            a_colTriangle = colTriangle;
            a_colPoint = colPoint;
            a_colSquareDistance = colSquareDistance;
            hit = true;
        }
    }

    // return result
    return (hit);
}
Пример #2
0
//===========================================================================
cCollisionSpheresLine::cCollisionSpheresLine(cVector3d& a_segmentPointA,
                                             cVector3d& a_segmentPointB)
{
    // calculate the center of the line segment
    m_center = cAdd(a_segmentPointA, a_segmentPointB);
    m_center.x *= 0.5;
    m_center.y *= 0.5;
    m_center.z *= 0.5;

    // calculate the radius of the bounding sphere as the distance from the
    // center of the segment (calculated above) to an endpoint
    cVector3d rad = cSub(m_center, a_segmentPointA);
    m_radius = sqrt(rad.x*rad.x + rad.y*rad.y + rad.z*rad.z);

    // set origin and direction of the line segment; i.e., redefine the segment
    // as a ray from the first endpoint (presumably the proxy position when
    // the collision detection is being used with the proxy force algorithm) to
    // the second endpoint (presumably the goal position)
    m_segmentPointA = a_segmentPointA;
    a_segmentPointB.subr(a_segmentPointA, m_dir);
}
// 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();
}
Пример #4
0
//===========================================================================
bool cCollisionAABB::computeCollision(cVector3d& a_segmentPointA,
                                      cVector3d& a_segmentPointB,
                                      cGenericObject*& a_colObject,
                                      cTriangle*& a_colTriangle,
                                      cVector3d& a_colPoint,
                                      double& a_colSquareDistance,
                                      int a_proxyCall)
{
    // convert two point segment into a segment described by a point and
    // a directional vector
    cVector3d dir;
    a_segmentPointB.subr(a_segmentPointA, dir);

    // if this is a subsequent call from the proxy algorithm after detecting
    // an initial collision, and if the flag to use neighbor checking is set,
    // only neighbors of the triangle from the first collision detection
    // need to be checked
    if ((m_useNeighbors) && (a_proxyCall > 1) && (m_root != NULL) &&
        (m_lastCollision != NULL) && (m_lastCollision->m_neighbors != NULL))
    {

        // initialize temp variables for output parameters
        cGenericObject* colObject;
        cTriangle* colTriangle;
        cVector3d colPoint;
        double colSquareDistance = dir.lengthsq();
        bool firstHit = true;

        // check each neighbor, and find the closest for which there is a
        // collision, if any
        unsigned int ntris = m_lastCollision->m_neighbors->size();
        std::vector<cTriangle*>* neighbors = m_lastCollision->m_neighbors;
        for (unsigned int i=0; i<ntris; i++)
        {
            cTriangle* tri = (*neighbors)[i];
            if (tri == 0) {
              CHAI_DEBUG_PRINT("Oops... invalid neighbor\n");
              continue;
            }
            if (tri->computeCollision(
                    a_segmentPointA, dir, colObject, colTriangle,
                    colPoint, colSquareDistance))
            {
                // if this intersected triangle is closer to the segment origin
                // than any other found so far, set the output parameters
                if (firstHit || (colSquareDistance < a_colSquareDistance))
                {
                    m_lastCollision = colTriangle;
                    a_colObject = colObject;
                    a_colTriangle = colTriangle;
                    a_colPoint = colPoint;
                    a_colSquareDistance = colSquareDistance;
                    firstHit = false;
                }
            }
        }

        // if at least one neighbor triangle was intersected, return true
        if (!firstHit)  return true;

        // otherwise there was no collision; return false
        if (a_proxyCall != -1) m_lastCollision = NULL;
        return false;
    }

    // otherwise, if this is the first call in an iteration of the proxy
    // algorithm (or a call from any other algorithm), check the AABB tree

    // if the root is null, the tree is empty, so there can be no collision
    if (m_root == NULL)
    {
        if (a_proxyCall != -1) m_lastCollision = NULL;
        return (false);
    }

    // create an axis-aligned bounding box for the line
    cCollisionAABBBox lineBox;
    lineBox.setEmpty();
    lineBox.enclose(a_segmentPointA);
    lineBox.enclose(a_segmentPointB);

    // test for intersection between the line segment and the root of the
    // collision tree; the root will recursively call children down the tree
    a_colSquareDistance = dir.lengthsq();
    bool result = m_root->computeCollision(a_segmentPointA, dir, lineBox,
            a_colTriangle, a_colPoint, a_colSquareDistance);

    // if there was a collision, set m_lastCollision to the intersected triangle
    // returned by the call to the root of the tree, and set the output
    // parameter for the intersected mesh to the parent of this triangle
    if (result)
    {
        if (a_proxyCall != -1) m_lastCollision = a_colTriangle;
        a_colObject = a_colTriangle->getParent();
    }
    else
    {
        if (a_proxyCall != -1) m_lastCollision = NULL;
    }

    // return whether there was an intersection
    return result;
}
//==============================================================================
bool cTriangleArray::computeCollision(const unsigned int a_triangleIndex,
                                      cGenericObject* a_object,
                                      cVector3d& a_segmentPointA,
                                      cVector3d& a_segmentPointB,
                                      cCollisionRecorder& a_recorder,
                                      cCollisionSettings& a_settings) const
{
    // verify that triangle is active
    if (!m_allocated[a_triangleIndex]) { return (false); }

    // temp variables
    bool hit = false;
    cVector3d collisionPoint;
    cVector3d collisionNormal;
    double collisionDistanceSq = C_LARGE;
    double collisionPointV01 = 0.0;
    double collisionPointV02 = 0.0;

    // retrieve information about which side of the triangles need to be checked
    cMaterialPtr material = a_object->m_material;
    bool checkFrontSide = material->getHapticTriangleFrontSide();
    bool checkBackSide = material->getHapticTriangleBackSide();

    // retrieve vertex positions
    cVector3d vertex0 = m_vertices->getLocalPos(getVertexIndex0(a_triangleIndex));
    cVector3d vertex1 = m_vertices->getLocalPos(getVertexIndex1(a_triangleIndex));
    cVector3d vertex2 = m_vertices->getLocalPos(getVertexIndex2(a_triangleIndex));

    // If m_collisionRadius == 0, we search for a possible intersection between
    // the segment AB and the triangle defined by its three vertices V0, V1, V2.
    if (a_settings.m_collisionRadius == 0.0)
    {
        // check for collision between segment and triangle only
        if (cIntersectionSegmentTriangle(a_segmentPointA,
                                         a_segmentPointB,
                                         vertex0,
                                         vertex1,
                                         vertex2,
                                         checkFrontSide,
                                         checkBackSide,
                                         collisionPoint,
                                         collisionNormal,
                                         collisionPointV01,
                                         collisionPointV02))
        {
            hit = true;
            collisionDistanceSq = cDistanceSq(a_segmentPointA, collisionPoint);
        }
    }


    // If m_collisionRadius > 0, we search for a possible intersection between
    // the segment AB and the shell of the selected triangle which is described
    // by its three vertices and m_collisionRadius.
    else
    {
        cVector3d t_collisionPoint, t_collisionNormal;
        double t_collisionDistanceSq;
        cVector3d normal = cComputeSurfaceNormal(vertex0, vertex1, vertex2);
        cVector3d offset; normal.mulr(a_settings.m_collisionRadius, offset);
        cVector3d t_vertex0, t_vertex1, t_vertex2;
        double t_collisionPointV01, t_collisionPointV02, t_collisionPointV12;

        // check for collision between segment and triangle upper shell
        vertex0.addr(offset, t_vertex0);
        vertex1.addr(offset, t_vertex1);
        vertex2.addr(offset, t_vertex2);
        if (cIntersectionSegmentTriangle(a_segmentPointA,
                                         a_segmentPointB,
                                         t_vertex0,
                                         t_vertex1,
                                         t_vertex2,
                                         checkFrontSide,
                                         false,
                                         collisionPoint,
                                         collisionNormal,
                                         collisionPointV01,
                                         collisionPointV02))
        {
            hit = true;
            collisionDistanceSq = cDistanceSq(a_segmentPointA, collisionPoint);
        }

        // check for collision between segment and triangle lower shell
        vertex0.subr(offset, t_vertex0);
        vertex1.subr(offset, t_vertex1);
        vertex2.subr(offset, t_vertex2);
        if (cIntersectionSegmentTriangle(a_segmentPointA,
                                         a_segmentPointB,
                                         t_vertex0,
                                         t_vertex1,
                                         t_vertex2,
                                         false,
                                         checkBackSide,
                                         t_collisionPoint,
                                         t_collisionNormal,
                                         t_collisionPointV01,
                                         t_collisionPointV02))
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = t_collisionPointV01;
                collisionPointV02 = t_collisionPointV02;
            }
        }

        // check for collision between sphere located at vertex 0.
        // if the starting point (a_segmentPointA) is located inside
        // the sphere, we ignore the collision to avoid remaining
        // stuck inside the triangle.
        cVector3d t_p, t_n;
        double t_c;
        if (cIntersectionSegmentSphere(a_segmentPointA,
                                       a_segmentPointB,
                                       vertex0,
                                       a_settings.m_collisionRadius,
                                       t_collisionPoint,
                                       t_collisionNormal,
                                       t_p,
                                       t_n) > 0)
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = 0.0;
                collisionPointV02 = 0.0;
            }
        }


        // check for collision between sphere located at vertex 1.
        // if the starting point (a_segmentPointA) is located inside
        // the sphere, we ignore the collision to avoid remaining
        // stuck inside the triangle.
        if (cIntersectionSegmentSphere(a_segmentPointA,
                                       a_segmentPointB,
                                       vertex1,
                                       a_settings.m_collisionRadius,
                                       t_collisionPoint,
                                       t_collisionNormal,
                                       t_p,
                                       t_n) > 0)
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = 1.0;
                collisionPointV02 = 0.0;
            }
        }


        // check for collision between sphere located at vertex 2.
        // if the starting point (a_segmentPointA) is located inside
        // the sphere, we ignore the collision to avoid remaining
        // stuck inside the triangle.
        if (cIntersectionSegmentSphere(a_segmentPointA,
                                       a_segmentPointB,
                                       vertex2,
                                       a_settings.m_collisionRadius,
                                       t_collisionPoint,
                                       t_collisionNormal,
                                       t_p,
                                       t_n) > 0)
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = 0.0;
                collisionPointV02 = 1.0;
            }
        }

        // check for collision between segment and triangle edge01 shell.
        // if the starting point (a_segmentPointA) is located inside
        // the cylinder, we ignore the collision to avoid remaining
        // stuck inside the triangle.
        if (cIntersectionSegmentToplessCylinder(a_segmentPointA,
                                                a_segmentPointB,
                                                vertex0,
                                                vertex1,
                                                a_settings.m_collisionRadius,
                                                t_collisionPoint,
                                                t_collisionNormal,
                                                t_collisionPointV01,
                                                t_p,
                                                t_n,
                                                t_c) > 0)
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = t_collisionPointV01;
                collisionPointV02 = 0.0;
            }
        }


        // check for collision between segment and triangle edge02 shell.
        // if the starting point (a_segmentPointA) is located inside
        // the cylinder, we ignore the collision to avoid remaining
        // stuck inside the triangle.
        if (cIntersectionSegmentToplessCylinder(a_segmentPointA,
                                                a_segmentPointB,
                                                vertex0,
                                                vertex2,
                                                a_settings.m_collisionRadius,
                                                t_collisionPoint,
                                                t_collisionNormal,
                                                t_collisionPointV02,
                                                t_p,
                                                t_n,
                                                t_c) > 0)
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = 0.0;
                collisionPointV02 = t_collisionPointV02;
            }
        }


        // check for collision between segment and triangle edge12 shell.
        // if the starting point (a_segmentPointA) is located inside
        // the cylinder, we ignore the collision to avoid remaining
        // stuck inside the triangle.
        if (cIntersectionSegmentToplessCylinder(a_segmentPointA,
                                                a_segmentPointB,
                                                vertex1,
                                                vertex2,
                                                a_settings.m_collisionRadius,
                                                t_collisionPoint,
                                                t_collisionNormal,
                                                t_collisionPointV12,
                                                t_p,
                                                t_n,
                                                t_c) > 0)
        {
            hit = true;
            t_collisionDistanceSq = cDistanceSq(a_segmentPointA, t_collisionPoint);
            if (t_collisionDistanceSq <= collisionDistanceSq)
            {
                collisionPoint = t_collisionPoint;
                collisionNormal = t_collisionNormal;
                collisionDistanceSq = t_collisionDistanceSq;
                collisionPointV01 = 1.0 - t_collisionPointV12;
                collisionPointV02 = t_collisionPointV12;
            }
        }
    }

    // report collision
    if (hit)
    {
        // before reporting the new collision, we need to check if
        // the collision settings require us to verify the side of the
        // triangle which has been hit.
        bool hit_confirmed = false;

        if (checkFrontSide && checkBackSide)
        {
            // settings specify that a collision can occur on both sides
            // of the triangle, so the new collision is reported.
            hit_confirmed = true;
        }
        else
        {
            // we need check on which side of the triangle the collision occurred
            // and see if it needs to be reported.
            cVector3d segmentAB;
            a_segmentPointB.subr(a_segmentPointA, segmentAB);

            cVector3d v01, v02, triangleNormal;
            vertex2.subr(vertex0, v02);
            vertex1.subr(vertex0, v01);
            v01.crossr(v02, triangleNormal);

            double value = cCosAngle(segmentAB, triangleNormal);
            if (value <= 0.0)
            {
                if (checkFrontSide)
                    hit_confirmed = true;
            }
            else
            {
                if (checkBackSide)
                    hit_confirmed = true;
            }
        }

        // here we finally report the new collision to the collision event handler.
        if (hit_confirmed)
        {
            // we verify if anew collision needs to be created or if we simply
            // need to update the nearest collision.
            if (a_settings.m_checkForNearestCollisionOnly)
            {
                // no new collision event is create. We just check if we need
                // to update the nearest collision
                if(collisionDistanceSq <= a_recorder.m_nearestCollision.m_squareDistance)
                {
                    // report basic collision data
                    a_recorder.m_nearestCollision.m_object = a_object;
                    a_recorder.m_nearestCollision.m_triangles = ((cMesh*)(a_object))->m_triangles;
                    a_recorder.m_nearestCollision.m_triangleIndex = a_triangleIndex;
                    a_recorder.m_nearestCollision.m_localPos = collisionPoint;
                    a_recorder.m_nearestCollision.m_localNormal = collisionNormal;
                    a_recorder.m_nearestCollision.m_squareDistance = collisionDistanceSq;
                    a_recorder.m_nearestCollision.m_adjustedSegmentAPoint = a_segmentPointA;
                    a_recorder.m_nearestCollision.m_trianglePosV01 = collisionPointV01;
                    a_recorder.m_nearestCollision.m_trianglePosV02 = collisionPointV02;

                    // report advanced collision data
                    if (!a_settings.m_returnMinimalCollisionData)
                    {
                        a_recorder.m_nearestCollision.m_globalPos = cAdd(a_object->getGlobalPos(),
                                cMul(a_object->getGlobalRot(),
                                        a_recorder.m_nearestCollision.m_localPos));
                        a_recorder.m_nearestCollision.m_globalNormal = cMul(a_object->getGlobalRot(),
                                a_recorder.m_nearestCollision.m_localNormal);
                    }
                }
            }
            else
            {
                cCollisionEvent newCollisionEvent;

                // report basic collision data
                newCollisionEvent.m_object = a_object;
                newCollisionEvent.m_triangles = ((cMesh*)(a_object))->m_triangles;
                newCollisionEvent.m_triangleIndex = a_triangleIndex;
                newCollisionEvent.m_localPos = collisionPoint;
                newCollisionEvent.m_localNormal = collisionNormal;
                newCollisionEvent.m_squareDistance = collisionDistanceSq;
                newCollisionEvent.m_adjustedSegmentAPoint = a_segmentPointA;
                newCollisionEvent.m_trianglePosV01 = collisionPointV01;
                newCollisionEvent.m_trianglePosV02 = collisionPointV02;

                // report advanced collision data
                if (!a_settings.m_returnMinimalCollisionData)
                {
                    newCollisionEvent.m_globalPos = cAdd(a_object->getGlobalPos(),
                                                         cMul(a_object->getGlobalRot(),
                                                         newCollisionEvent.m_localPos));
                    newCollisionEvent.m_globalNormal = cMul(a_object->getGlobalRot(),
                                                            newCollisionEvent.m_localNormal);
                }

                // add new collision even to collision list
                a_recorder.m_collisions.push_back(newCollisionEvent);

                // check if this new collision is a candidate for "nearest one"
                if(collisionDistanceSq <= a_recorder.m_nearestCollision.m_squareDistance)
                {
                    a_recorder.m_nearestCollision = newCollisionEvent;
                }
            }
        }

        // return result
        return (hit_confirmed);
    }
    else
    {
        return (false);
    }
}