Example #1
0
//-----------------------------------------------------------------------
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);
}
Example #2
0
bool createTetGenMesh(cGELMesh *a_object, char *a_filename,  char *a_filenameHighRes)
{
    a_object->m_useSkeletonModel = false;
    a_object->m_useMassParticleModel = true;

    cGELMesh* model = new cGELMesh(world);
    model->loadFromFile(a_filenameHighRes);

    tetgenio input;
    if (input.load_off(a_filename))
    {
        // use TetGen to tetrahedralize our mesh
        tetgenio output;
        tetrahedralize(TETGEN_SWITCHES0, &input, &output);

        // create a vertex in the object for each point of the result
        for (int p = 0, pi = 0; p < output.numberofpoints; ++p, pi += 3)
        {
            cVector3d point;
            point.x = output.pointlist[pi+0];
            point.y = output.pointlist[pi+1];
            point.z = output.pointlist[pi+2];
            a_object->newVertex(point);
        }

        // create a triangle for each face on the surface
        set<int> outside;
        for (int t = 0, ti = 0; t < output.numberoftrifaces; ++t, ti += 3)
        {
            cVector3d p[3];
            int vi[3];
            for (int i = 0; i < 3; ++i) {
                int tc = output.trifacelist[ti+i];
                outside.insert(tc);
                vi[i] = tc;
                int pi = tc*3;
                p[i].x = output.pointlist[pi+0];
                p[i].y = output.pointlist[pi+1];
                p[i].z = output.pointlist[pi+2];
            }
            //unsigned int index = a_object->newTriangle(p[1], p[0], p[2]);
            a_object->newTriangle(vi[1], vi[0], vi[2]);
        }

        a_object->computeAllNormals();

        // compute a boundary box
        a_object->computeBoundaryBox(true);

        // get dimensions of object
        double size = cSub(a_object->getBoundaryMax(), a_object->getBoundaryMin()).length();

        // resize object to screen
        if (size > 0)
        {
            model->scale(1.5 / size);
            a_object->scale(1.5 / size);
        }

        // build dynamic vertices
        cGELMassParticle::default_mass = 0.002;
        cGELMassParticle::default_kDampingPos = 4.0;
        cGELMassParticle::default_gravity.set(0,0,-0.1);

        a_object->buildVertices();

        // get all the edges of our tetrahedra
        set< pair<int,int> > springs;
        for (int t = 0, ti = 0; t < output.numberoftetrahedra; ++t, ti += 4)
        {
            // store each edge of the tetrahedron as a pair of indices
            for (int i = 0; i < 4; ++i) {
                int v0 = output.tetrahedronlist[ti+i];
                for (int j = i+1; j < 4; ++j) {
                    int v1 = output.tetrahedronlist[ti+j];
                    springs.insert(pair<int,int>(min(v0,v1), max(v0,v1)));
                }
            }
        }

        // create a spring on each tetrahedral edge we found in the output
        cGELLinearSpring::default_kSpringElongation = 40.0; // 0.55;
        for (set< pair<int,int> >::iterator it = springs.begin(); it != springs.end(); ++it)
        {
            cVertex* v0 = a_object->getVertex(it->first);
            cVertex* v1 = a_object->getVertex(it->second);

            cGELMassParticle* m0 = a_object->m_gelVertices[v0->m_tag].m_massParticle;
            cGELMassParticle* m1 = a_object->m_gelVertices[v1->m_tag].m_massParticle;

            cGELLinearSpring* spring = new cGELLinearSpring(m0, m1);
            a_object->m_linearSprings.push_back(spring);
        }

        // extract texture
        int numModelV = model->getNumVertices(true);
        for (set<int>::iterator it = outside.begin(); it != outside.end(); ++it)
        {
            cVertex *v = a_object->getVertex(*it);
            cVertex *t = 0;
            double closest = 1e10;
            for (int j = 0; j < numModelV; ++j) {
                cVertex *test = model->getVertex(j, true);
                double d = cDistanceSq(v->getPos(), test->getPos());
                if (d < closest) {
                    closest = d;
                    t = test;
                }
            }

            v->setTexCoord(t->getTexCoord());
        }

        cMesh* mesh = (cMesh*)model->getChild(0);
        mesh->m_texture->setWrapMode(GL_CLAMP, GL_CLAMP);
        a_object->setTexture(mesh->m_texture, true);
        a_object->setUseTexture(true, true);

        cMaterial mat;
        mat.m_ambient.set(0.7, 0.7, 0.7);
        mat.m_diffuse.set(0.8, 0.8, 0.8);
        mat.m_specular.set(0.0, 0.0, 0.0);
        a_object->setMaterial(mat, true);

        return (true);
    }
    return (false);
}
//==============================================================================
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);
    }
}