DiscreteIntersection.inl

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #ifndef SOFA_COMPONENT_COLLISION_DISCRETEINTERSECTION_INL
00026 #define SOFA_COMPONENT_COLLISION_DISCRETEINTERSECTION_INL
00027 #include <sofa/helper/system/config.h>
00028 #include <sofa/component/collision/DiscreteIntersection.h>
00029 #include <sofa/core/ObjectFactory.h>
00030 #include <sofa/core/componentmodel/collision/Intersection.inl>
00031 //#include <sofa/component/collision/ProximityIntersection.h>
00032 #include <sofa/component/collision/proximity.h>
00033 #include <iostream>
00034 #include <algorithm>
00035 
00036 
00037 namespace sofa
00038 {
00039 
00040 namespace component
00041 {
00042 
00043 namespace collision
00044 {
00045 
00046 using namespace sofa::defaulttype;
00047 using namespace sofa::core::componentmodel::collision;
00048 
00049 template<class Sphere>
00050 bool DiscreteIntersection::testIntersection(Sphere& sph1, Sphere& sph2)
00051 {
00052     //std::cout<<"Collision between Sphere - Sphere"<<std::endl;
00053     typename Sphere::Coord sph1Pos(sph1.center());
00054     typename Sphere::Coord sph2Pos(sph2.center());
00055     typename Sphere::Real radius1 = sph1.r(), radius2 = sph2.r();
00056     typename Sphere::Coord tmp = sph1Pos - sph2Pos;
00057     return (tmp.norm2() < (radius1 + radius2) * (radius1 + radius2));
00058 }
00059 
00060 template<class Sphere>
00061 bool DiscreteIntersection::testIntersection( Sphere& sph1, Cube& cube)
00062 {
00063     // Values of the "aligned" bounding box
00064     Vector3 Bmin = cube.minVect();
00065     Vector3 Bmax = cube.maxVect();
00066     // Center of sphere
00067     Vector3 ctr(sph1.center());
00068     // Square of radius 
00069     double r2 = sph1.r()*sph1.r();
00070     // Distance
00071     double dmin = 0;
00072 
00073     for ( int i = 0; i<3; i++)
00074     {
00075         if ( ctr[i] < Bmin[i] )      dmin += (ctr[i]-Bmin[i])*(ctr[i]-Bmin[i]);
00076         else if ( ctr[i] > Bmax[i] ) dmin += (ctr[i]-Bmax[i])*(ctr[i]-Bmax[i]);
00077     }
00078 
00079     return (dmin <= r2 );
00080 }
00081 
00082 template<class Sphere>
00083 bool DiscreteIntersection::testIntersection( Sphere& sph, Triangle& triangle)
00084 {
00085     double EPSILON = 0.00001;
00086     //Vertices of the triangle:
00087     Vector3 p0 = triangle.p1(); 
00088     Vector3 p1 = triangle.p2();
00089     Vector3 p2 = triangle.p3();
00090 
00091     // Center of the sphere
00092     const Vector3 sphCenter(sph.center());
00093     // Radius of the sphere
00094     const double r = sph.r();
00095 
00096     //Normal to the plane (plane spanned by tree points of the triangle)
00097     Vector3 normal = cross( (p1 - p0), (p2 - p0) );
00098     normal.normalize();
00099 
00100     //Distance from the center of the sphere to the plane.
00101     double distance = sphCenter*normal - normal*p0;
00102 
00103     //Projection of the center of the sphere onto the plane
00104     Vector3 projPoint = sphCenter - normal*distance;
00105 
00106     //Distance correction in case is negative.
00107     if (distance < 0.0)
00108      distance = -distance;
00109 
00110     //Distance to the sphere:
00111     distance -= r;
00112 
00113     //If the distance is positive, the point has been proyected outside
00114     //the sphere and hence the plane does not intersect the sphere
00115     //and so the triangle (that spanned the plane) cannot be inside the sphere.
00116     if (distance  > EPSILON)
00117     {
00118            return false;
00119     }
00120 
00121     //However, if the plane has intersected the sphere, then it is
00122     //necessary to check if the projected point "projPoint" is inside
00123     //the triangle.
00124 #define SAMESIDE(ap1,ap2,ap3,ap4) (((cross((ap4-ap3),(ap1-ap3))) * (cross((ap4-ap3),(ap2-ap3)))) >= 0)
00125     if ( (SAMESIDE(projPoint,p0,p1,p2) && SAMESIDE(projPoint,p1,p0,p2) && SAMESIDE(projPoint,p2,p0,p1)))
00126     {
00127         return true;
00128     }
00129 #undef SAMESIDE
00130     return false;
00131 }
00132 
00133 template<class Sphere>
00134 bool DiscreteIntersection::testIntersection(Ray& ray1, Sphere& sph2)
00135 {
00136   //std::cout<<"intersectionSphereRay: Collision between Sphere - Ray"<<std::endl;
00137     // Center of the sphere
00138     const Vector3 sph2Pos(sph2.center());
00139     // Radius of the sphere
00140     const double radius1 = sph2.r();
00141 
00142     const Vector3 ray1Origin(ray1.origin());
00143     const Vector3 ray1Direction(ray1.direction());
00144     const double length2 = ray1.l();
00145     const Vector3 tmp = sph2Pos - ray1Origin;
00146     const double rayPos = tmp*ray1Direction;
00147     const double rayPosInside = std::max(std::min(rayPos,length2),0.0);
00148     const double dist2 = tmp.norm2() - (rayPosInside*rayPosInside);
00149     return (dist2 < (radius1*radius1));
00150 }
00151 
00152 template<class Sphere>
00153 int DiscreteIntersection::computeIntersection( Sphere& sph, Triangle& triangle, OutputVector* contacts)
00154 {   
00155     double EPSILON = 0.00001;
00156     //Vertices of the triangle:
00157     Vector3 p0 = triangle.p1(); 
00158     Vector3 p1 = triangle.p2();
00159     Vector3 p2 = triangle.p3();
00160 
00161     // Center of the sphere
00162     const Vector3 sphCenter(sph.center());
00163     // Radius of the sphere
00164     const double r = sph.r();
00165 
00166     //Normal to the plane (plane spanned by tree points of the triangle)
00167     Vector3 normal = cross( (p1 - p0), (p2 - p0) );
00168     normal.normalize();
00169 
00170     //Distance from the center of the sphere to the plane.
00171     double distance = sphCenter*normal - normal*p0;
00172 
00173     //Projection of the center of the sphere onto the plane
00174     Vector3 projPoint = sphCenter - normal*distance;
00175 
00176     //Distance correction in case is negative.
00177     if (distance < 0.0)
00178      distance = -distance;
00179 
00180     //Distance to the sphere:
00181     distance -= r;
00182 
00183     //If the distance is positive, the point has been proyected outside
00184     //the sphere and hence the plane does not intersect the sphere
00185     //and so the triangle (that spanned the plane) cannot be inside the sphere.
00186     if (distance  > EPSILON)
00187     {
00188            return 0;
00189     }
00190 
00191     //However, if the plane has intersected the sphere, then it is
00192     //neccesary to check if the proyected point "projPoint" is inside
00193     //the triangle.
00194 #define SAMESIDE(ap1,ap2,ap3,ap4) (((cross((ap4-ap3),(ap1-ap3))) * (cross((ap4-ap3),(ap2-ap3)))) >= 0)
00195   if ( (SAMESIDE(projPoint,p0,p1,p2) && SAMESIDE(projPoint,p1,p0,p2) && SAMESIDE(projPoint,p2,p0,p1)))
00196   {
00197     contacts->resize(contacts->size()+1);
00198     DetectionOutput *detection = &*(contacts->end()-1);
00199     detection->normal = -normal;
00200     detection->point[1] = projPoint;
00201     detection->point[0] = sph.center() - detection->normal * sph.r();
00202 
00203     detection->value = -distance;
00204     //detection->elem.first = triangle;
00205     //detection->elem.second = sph;
00206     detection->elem.first = sph;
00207     detection->elem.second = triangle;
00208         detection->id = sph.getIndex();
00209  return 1;
00210   }
00211 #undef SAMESIDE
00212 
00215     // RayModel edges;
00217     // Vector3 dir = p1 - p0;
00218     // double length = dir.norm();
00219     // edges.addRay(p0,dir,length);
00221     // dir = p1 - p2;
00222     // length = dir.norm();
00223     // edges.addRay(p1,dir,length);
00224     // //Edge2 
00225     // dir = p2 - p0;
00226     // length = dir.norm();
00227     // edges.addRay(p2,dir,length);
00228     // 
00229     // detection = distCorrectionSingleSphereRay( sph,edges.getRay(0));
00230     //if ( detection != NULL ) 
00231     //{
00232     //  detection->elem.first = triangle;
00233     //  detection->elem.second = sph;
00234     //  return detection;
00235     //}
00236 
00237     //detection = distCorrectionSingleSphereRay( sph,edges.getRay(1));
00238     //if ( detection != NULL ) 
00239     //{
00240     //  detection->elem.first = triangle;
00241     //  detection->elem.second = sph;
00242     //  return detection;
00243     //}
00244     // detection = distCorrectionSingleSphereRay( sph,edges.getRay(2));
00245     //  if ( detection != NULL ) 
00246     //{
00247     //  detection->elem.first = triangle;
00248     //  detection->elem.second = sph;
00249     //  return detection;
00250     //}
00251 
00252     return 0; // No intersection: passed all tests for intersections !
00253 }
00254 
00255 
00256 template<class Sphere>
00257 int DiscreteIntersection::computeIntersection(Sphere& sph1, Sphere& sph2, OutputVector* contacts)
00258 {
00259     double r = sph1.r() + sph2.r();
00260     Vector3 dist = sph2.center() - sph1.center();
00261 
00262     if (dist.norm2() >= r*r)
00263         return 0;
00264 
00265     contacts->resize(contacts->size()+1);
00266     DetectionOutput *detection = &*(contacts->end()-1);
00267     detection->normal = dist;
00268     double distSph1Sph2 = detection->normal.norm();
00269     detection->normal /= distSph1Sph2;
00270     detection->point[0] = sph1.center() + detection->normal * sph1.r();
00271     detection->point[1] = sph2.center() - detection->normal * sph2.r();
00272 
00273     detection->value = distSph1Sph2 - r;
00274     detection->elem.first = sph1;
00275     detection->elem.second = sph2;
00276     detection->id = (sph1.getCollisionModel()->getSize() > sph2.getCollisionModel()->getSize()) ? sph1.getIndex() : sph2.getIndex();
00277 
00278     return 1;
00279 }
00280 
00281 template<class Sphere>
00282 int DiscreteIntersection::computeIntersection(Sphere& /*sph1*/, Cube& /*cube*/, OutputVector* /*contacts*/)
00283 {
00284     //to do
00285     return 0;
00286 }
00287 
00288 template<class Sphere>
00289 int DiscreteIntersection::computeIntersection(Ray& ray1, Sphere& sph2, OutputVector* contacts)
00290 {
00291     // Center of the sphere
00292     const Vector3 sph2Pos(sph2.center());
00293     // Radius of the sphere
00294     const double radius1 = sph2.r();
00295 
00296     const Vector3 ray1Origin(ray1.origin());
00297     const Vector3 ray1Direction(ray1.direction());
00298     const double length2 = ray1.l();
00299     const Vector3 tmp = sph2Pos - ray1Origin;
00300     const double rayPos = tmp*ray1Direction;
00301     const double rayPosInside = std::max(std::min(rayPos,length2),0.0);
00302     const double dist2 = tmp.norm2() - (rayPosInside*rayPosInside);
00303     if (dist2 >= (radius1*radius1))
00304         return 0;
00305 
00306     const double dist = sqrt(dist2);
00307     
00308     contacts->resize(contacts->size()+1);
00309     DetectionOutput *detection = &*(contacts->end()-1);
00310 
00311     detection->point[0] = ray1Origin + ray1Direction*rayPosInside;
00312     detection->normal = sph2Pos - detection->point[0];
00313     detection->normal /= dist;
00314     detection->point[1] = sph2Pos - detection->normal * radius1;
00315     detection->value = dist - radius1;
00316     detection->elem.first = ray1;
00317     detection->elem.second = sph2;
00318     detection->id = ray1.getIndex();
00319 
00320     return 1;
00321 }
00322 
00323 template<class Sphere>
00324 bool DiscreteIntersection::testIntersection(RigidDistanceGridCollisionElement&, Sphere&)
00325 {
00326     return true;
00327 }
00328 
00329 template<class Sphere>
00330 int DiscreteIntersection::computeIntersection(RigidDistanceGridCollisionElement& e1, Sphere& e2, OutputVector* contacts)
00331 {
00332     DistanceGrid* grid1 = e1.getGrid();
00333     bool useXForm = e1.isTransformed();
00334     const Vector3& t1 = e1.getTranslation();
00335     const Matrix3& r1 = e1.getRotation();
00336 
00337     const double d0 = e1.getProximity() + e2.getProximity() + this->getContactDistance() + e2.r();
00338     const SReal margin = 0.001f + (SReal)d0;
00339 
00340     Vector3 p2 = e2.center();
00341     DistanceGrid::Coord p1;
00342 
00343     if (useXForm)
00344     {
00345          p1 = r1.multTranspose(p2-t1);
00346     }
00347     else p1 = p2;
00348 
00349     if (!grid1->inBBox( p1, margin )) return 0;
00350     if (!grid1->inGrid( p1 ))
00351     {
00352     std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00353     return 0;
00354     }
00355 
00356     SReal d = grid1->interp(p1);
00357     if (d >= margin) return 0;
00358 
00359     Vector3 grad = grid1->grad(p1); // note that there are some redundant computations between interp() and grad()
00360     grad.normalize();
00361 
00362     //p1 -= grad * d; // push p1 back to the surface
00363 
00364     contacts->resize(contacts->size()+1);
00365     DetectionOutput *detection = &*(contacts->end()-1);
00366 
00367     detection->point[0] = Vector3(p1) - grad * d;
00368     detection->point[1] = Vector3(p2);
00369     detection->normal = (useXForm) ? r1 * grad : grad; // normal in global space from p1's surface
00370     detection->value = d - d0;
00371     detection->elem.first = e1;
00372     detection->elem.second = e2;
00373     detection->id = e2.getIndex();
00374     return 1;
00375 }
00376 
00377 template<class Sphere>
00378 bool DiscreteIntersection::testIntersection(FFDDistanceGridCollisionElement&, Sphere&)
00379 {
00380     return true;
00381 }
00382 
00383 template<class Sphere>
00384 int DiscreteIntersection::computeIntersection(FFDDistanceGridCollisionElement& e1, Sphere& e2, OutputVector* contacts)
00385 {
00386 
00387     DistanceGrid* grid1 = e1.getGrid();
00388     FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
00389 
00390     const double d0 = e1.getProximity() + e2.getProximity() + getContactDistance() + e2.r();
00391     const SReal margin = 0.001f + (SReal)d0;
00392 
00393     c1.updateFaces();
00394     const SReal cubesize = c1.invDP.norm();
00395     Vector3 p2 = e2.center();
00396     DistanceGrid::Coord p1 = p2;
00397 
00398     // estimate the barycentric coordinates
00399     DistanceGrid::Coord b = c1.undeform0(p1);
00400 
00401     // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
00402     int iter;
00403     SReal err1 = 1000.0f;
00404     for(iter=0; iter<5; ++iter)
00405     {
00406         DistanceGrid::Coord pdeform = c1.deform(b);
00407         DistanceGrid::Coord diff = p1-pdeform;
00408         SReal err = diff.norm();
00409         if (iter>3)
00410             std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
00411         SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
00412         if (b[0] < -berr || b[0] > 1+berr
00413             || b[1] < -berr || b[1] > 1+berr
00414             || b[2] < -berr || b[2] > 1+berr)
00415             break; // far from the cube
00416         if (err < 0.005f)
00417         { // we found the corresponding point, but is is only valid if inside the current cube
00418             if (b[0] > 0.001f && b[0] < 0.999f
00419                 && b[1] > 0.001f && b[1] < 0.999f
00420                 && b[2] > 0.001f && b[2] < 0.999f)
00421             {
00422                 DistanceGrid::Coord pinit = c1.initpos(b);
00423                 SReal d = grid1->interp(pinit);
00424                 if (d < margin)
00425                 {
00426                     DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
00427                     grad.normalize();
00428                     pinit -= grad*d;
00429                     grad = c1.deformDir(c1.baryCoords(pinit),grad);
00430                     grad.normalize();
00431                     
00432                     contacts->resize(contacts->size()+1);
00433                     DetectionOutput *detection = &*(contacts->end()-1);
00434                     
00435                     detection->point[0] = Vector3(pinit);
00436                     detection->point[1] = Vector3(p2);
00437                     detection->normal = Vector3(grad); // normal in global space from p1's surface
00438                     detection->value = d - d0;
00439                     detection->elem.first = e1;
00440                     detection->elem.second = e2;
00441                     detection->id = e2.getIndex();
00442                     return 1;
00443                 }
00444             }
00445             break;
00446         }
00447         err1 = err;
00448         SReal d = grid1->interp(c1.initpos(b));
00449         if (d*0.5f - err > margin)
00450             break; // the point is too far from the object
00451         // we are solving for deform(b+db)-deform(b) = p1-deform(b)
00452         // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
00453         b += c1.undeformDir( b, diff );
00454     }
00455     if (iter == 5)
00456     {
00457         if (b[0] > 0.001f && b[0] < 0.999f
00458             && b[1] > 0.001f && b[1] < 0.999f
00459             && b[2] > 0.001f && b[2] < 0.999f)
00460             std::cerr << "ERROR: FFD-FFD collision failed to converge to undeformed point: p1 = "<<p1<<" b = "<<b<<" c000 = "<<c1.corners[0]<<" c100 = "<<c1.corners[1]<<" c010 = "<<c1.corners[2]<<" c110 = "<<c1.corners[3]<<" c001 = "<<c1.corners[4]<<" c101 = "<<c1.corners[5]<<" c011 = "<<c1.corners[6]<<" c111 = "<<c1.corners[7]<<" pinit = "<<c1.initpos(b)<<" pdeform = "<<c1.deform(b)<<" err = "<<err1<<std::endl;
00461     }
00462 
00463     return 0;
00464 }
00465 
00466 } // namespace collision
00467 
00468 } // namespace component
00469 
00470 } // namespace sofa
00471 
00472 #endif

Generated on Sun Nov 23 02:33:45 2008 for Sofa by  doxygen 1.5.7.1