DiscreteIntersection.cpp

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 #include <sofa/helper/system/config.h>
00026 #include <sofa/helper/FnDispatcher.inl>
00027 #include <sofa/component/collision/DiscreteIntersection.inl>
00028 #include <sofa/core/ObjectFactory.h>
00029 #include <sofa/core/componentmodel/collision/Intersection.inl>
00030 //#include <sofa/component/collision/RayPickInteractor.h>
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 SOFA_DECL_CLASS(DiscreteIntersection)
00050 
00051     int DiscreteIntersectionClass = core::RegisterObject("TODO-DiscreteIntersectionClass")
00052 .add< DiscreteIntersection >()
00053 ;
00054 
00055 
00056 DiscreteIntersection::DiscreteIntersection()
00057 {
00058     intersectors.add<CubeModel,       CubeModel,         DiscreteIntersection> (this);
00059     intersectors.add<SphereModel,     SphereModel,       DiscreteIntersection> (this);
00060     intersectors.add<SphereTreeModel, SphereTreeModel,   DiscreteIntersection> (this);
00061     intersectors.add<SphereTreeModel, CubeModel,         DiscreteIntersection>  (this);
00062     intersectors.add<SphereTreeModel, TriangleModel,     DiscreteIntersection>  (this);
00063     //intersectors.add<SphereTreeModel, SphereModel,       DiscreteIntersection>  (this);
00064     //intersectors.add<SphereModel,     TriangleModel,     DiscreteIntersection>  (this);
00065     intersectors.add<TriangleModel,     LineModel,       DiscreteIntersection>  (this);
00066     //intersectors.add<TriangleModel,   TriangleModel,     DiscreteIntersection> (this);
00067     intersectors.add<TetrahedronModel, PointModel,       DiscreteIntersection>  (this);
00068     intersectors.add<RigidDistanceGridCollisionModel, PointModel,                      DiscreteIntersection>  (this);
00069     intersectors.add<RigidDistanceGridCollisionModel, SphereModel,                     DiscreteIntersection>  (this);
00070     intersectors.add<RigidDistanceGridCollisionModel, TriangleModel,                   DiscreteIntersection>  (this);
00071     intersectors.add<RigidDistanceGridCollisionModel, RigidDistanceGridCollisionModel, DiscreteIntersection> (this);
00072     intersectors.add<FFDDistanceGridCollisionModel, PointModel,                        DiscreteIntersection>  (this);
00073     intersectors.add<FFDDistanceGridCollisionModel, SphereModel,                       DiscreteIntersection>  (this);
00074     intersectors.add<FFDDistanceGridCollisionModel, TriangleModel,                     DiscreteIntersection>  (this);
00075     intersectors.add<FFDDistanceGridCollisionModel,   RigidDistanceGridCollisionModel, DiscreteIntersection>  (this);
00076     intersectors.add<FFDDistanceGridCollisionModel,   FFDDistanceGridCollisionModel,   DiscreteIntersection> (this);
00077 
00078     intersectors.add<RayModel, SphereModel,                     DiscreteIntersection>  (this);
00079     intersectors.add<RayModel, SphereTreeModel,                 DiscreteIntersection>  (this);
00080     intersectors.ignore<RayModel, PointModel>();
00081     intersectors.ignore<RayModel, LineModel>();
00082     intersectors.add<RayModel, TriangleModel,                   DiscreteIntersection>  (this);
00083     intersectors.add<RayModel, TetrahedronModel,                DiscreteIntersection>  (this);
00084     intersectors.add<RayModel, RigidDistanceGridCollisionModel, DiscreteIntersection>  (this);
00085     intersectors.add<RayModel, FFDDistanceGridCollisionModel,   DiscreteIntersection>  (this);
00086 }
00087 
00089 ElementIntersector* DiscreteIntersection::findIntersector(core::CollisionModel* object1, core::CollisionModel* object2, bool& swapModels)
00090 {
00091     return intersectors.get(object1, object2, swapModels);
00092 }
00093 
00094 bool DiscreteIntersection::testIntersection(Cube& cube1, Cube& cube2)
00095 {
00096     const Vector3& minVect1 = cube1.minVect();
00097     const Vector3& minVect2 = cube2.minVect();
00098     const Vector3& maxVect1 = cube1.maxVect();
00099     const Vector3& maxVect2 = cube2.maxVect();
00100 
00101     for (int i=0;i<3;i++)
00102     {
00103         if (minVect1[i] > maxVect2[i] || minVect2[i] > maxVect1[i])
00104             return false;
00105     }
00106 
00107     //std::cout << "Box <"<<minVect1[0]<<","<<minVect1[1]<<","<<minVect1[2]<<">-<"<<maxVect1[0]<<","<<maxVect1[1]<<","<<maxVect1[2]
00108     //  <<"> collide with Box "<<minVect2[0]<<","<<minVect2[1]<<","<<minVect2[2]<<">-<"<<maxVect2[0]<<","<<maxVect2[1]<<","<<maxVect2[2]<<">"<<std::endl;
00109     return true;
00110 }
00111 
00112 //bool DiscreteIntersection::testIntersection(Triangle& t1, Triangle& t2)
00113 //{
00114 //  std::cout<<"Collision between Triangle - Triangle"<<std::endl;
00115 //  return false;
00116 //}
00117 
00118 int DiscreteIntersection::computeIntersection(Cube&, Cube&, OutputVector*)
00119 {
00120     return 0; 
00121 }
00122 
00123 //int DiscreteIntersection::computeIntersection(Triangle&, Triangle&, OutputVector*)
00124 //{
00125 //  std::cout<<"Distance correction between Triangle - Triangle"<<std::endl;
00126 //  return 0;
00127 //}
00128 
00129 bool DiscreteIntersection::testIntersection(Triangle&, Line&)
00130 {
00131     return true;
00132 }
00133 
00134 int DiscreteIntersection::computeIntersection(Triangle& e1, Line& e2, OutputVector* contacts)
00135 {
00136     Vector3 A = e1.p1();
00137     Vector3 AB = e1.p2()-A;
00138     Vector3 AC = e1.p3()-A;
00139     Vector3 P = e2.p1();
00140     Vector3 PQ = e2.p2()-P;
00141     Matrix3 M, Minv;
00142     Vector3 right;
00143     for (int i=0;i<3;i++)
00144     {
00145         M[i][0] = AB[i];
00146         M[i][1] = AC[i];
00147         M[i][2] = -PQ[i];
00148         right[i] = P[i]-A[i];
00149     }
00150     //std::cout << "M="<<M<<std::endl;
00151     if (!Minv.invert(M))
00152         return 0;
00153     Vector3 baryCoords = Minv * right;
00154     if (baryCoords[0] < 0 || baryCoords[1] < 0 || baryCoords[0]+baryCoords[1] > 1)
00155         return 0; // out of the triangle
00156     if (baryCoords[2] < 0 || baryCoords[2] > 1)
00157         return 0; // out of the line
00158     
00159     Vector3 X = P+PQ*baryCoords[2];
00160     
00161     contacts->resize(contacts->size()+1);
00162     DetectionOutput *detection = &*(contacts->end()-1);
00163     detection->point[0] = X;
00164     detection->point[1] = X;
00165     detection->normal = e1.n();
00166     detection->value = 0;
00167     detection->elem.first = e1;
00168     detection->elem.second = e2;
00169     detection->id = e2.getIndex();
00170     return 1;
00171 }
00172 
00173 bool DiscreteIntersection::testIntersection(Ray&, Triangle&)
00174 {
00175     return true;
00176 }
00177 
00178 int DiscreteIntersection::computeIntersection(Ray& e1, Triangle& e2, OutputVector* contacts)
00179 {
00180     Vector3 A = e2.p1();
00181     Vector3 AB = e2.p2()-A;
00182     Vector3 AC = e2.p3()-A;
00183     Vector3 P = e1.origin();
00184     Vector3 PQ = e1.direction();
00185     Matrix3 M, Minv;
00186     Vector3 right;
00187     for (int i=0;i<3;i++)
00188     {
00189         M[i][0] = AB[i];
00190         M[i][1] = AC[i];
00191         M[i][2] = -PQ[i];
00192         right[i] = P[i]-A[i];
00193     }
00194     if (!Minv.invert(M))
00195         return 0;
00196     Vector3 baryCoords = Minv * right;
00197     if (baryCoords[0] < 0 || baryCoords[1] < 0 || baryCoords[0]+baryCoords[1] > 1)
00198         return 0; // out of the triangle
00199     if (baryCoords[2] < 0 || baryCoords[2] > e1.l())
00200         return 0; // out of the line
00201     
00202     Vector3 X = P+PQ*baryCoords[2];
00203     
00204     contacts->resize(contacts->size()+1);
00205     DetectionOutput *detection = &*(contacts->end()-1);
00206     detection->point[0] = X;
00207     detection->point[1] = X;
00208     detection->normal = -e2.n();
00209     detection->value = 0;
00210     detection->elem.first = e1;
00211     detection->elem.second = e2;
00212     detection->id = e1.getIndex();
00213     return 1;
00214 }
00215 
00216 bool DiscreteIntersection::testIntersection(Ray&, Tetrahedron&)
00217 {
00218     return true;
00219 }
00220 
00221 int DiscreteIntersection::computeIntersection(Ray& e1, Tetrahedron& e2, OutputVector* contacts)
00222 {
00223     Vector3 P = e1.origin();
00224     Vector3 PQ = e1.direction();
00225     Vector3 b0 = e2.getBary(P);
00226     Vector3 bdir = e2.getDBary(PQ);
00227     //std::cout << "b0 = "<<b0<<" \tbdir = "<<bdir<<std::endl;
00228     double l0 = 0;
00229     double l1 = e1.l();
00230     for (int c=0;c<3;++c)
00231     {
00232     if (b0[c] < 0 && bdir[c] < 0) return 0; // no intersection
00233     //if (b0[c] > 1 && bdir[c] > 0) return 0; // no intersection
00234     if (bdir[c] < -1.0e-10)
00235     {
00236         double l = -b0[c]/bdir[c];
00237         if (l < l1) l1 = l;
00238     }
00239     else if (bdir[c] > 1.0e-10)
00240     {
00241         double l = -b0[c]/bdir[c];
00242         if (l > l0) l0 = l;
00243     }
00244     }
00245     // 4th plane : bx+by+bz = 1
00246     {
00247     double bd = bdir[0]+bdir[1]+bdir[2];
00248     if (bd > 1.0e-10)
00249     {
00250         double l = (1-(b0[0]+b0[1]+b0[2]))/bd;
00251         if (l < l1) l1 = l;
00252     }
00253     else if (bd < -1.0e-10)
00254     {
00255         double l = (1-(b0[0]+b0[1]+b0[2]))/bd;
00256         if (l > l0) l0 = l;
00257     }
00258     }
00259     if (l0 > l1) return 0; // empty intersection
00260     double l = l0; //(l0+l1)/2;
00261     Vector3 X = P+PQ*l;
00262 
00263     //std::cout << "tetra "<<e2.getIndex()<<": b0 = "<<b0<<" \tbdir = "<<bdir<<std::endl;
00264     //std::cout << "l0 = "<<l0<<" \tl1 = "<<l1<<" \tX = "<<X<<" \tbX = "<<e2.getBary(X)<<" \t?=? "<<(b0+bdir*l)<<std::endl;
00265     //std::cout << "b1 = "<<e2.getBary(e2.p1())<<" \nb2 = "<<e2.getBary(e2.p2())<<" \nb3 = "<<e2.getBary(e2.p3())<<" \nb4 = "<<e2.getBary(e2.p4())<<std::endl;
00266     
00267     contacts->resize(contacts->size()+1);
00268     DetectionOutput *detection = &*(contacts->end()-1);
00269     detection->point[0] = X;
00270     detection->point[1] = X;
00271     PQ.normalize();
00272     detection->normal = PQ;
00273     detection->value = 0;
00274     detection->elem.first = e1;
00275     detection->elem.second = e2;
00276     detection->id = e1.getIndex();
00277     return 1;
00278 }
00279 
00280 bool DiscreteIntersection::testIntersection(Tetrahedron&, Point&)
00281 {
00282     return true;
00283 }
00284 
00285 int DiscreteIntersection::computeIntersection(Tetrahedron& e1, Point& e2, OutputVector* contacts)
00286 {
00287     Vector3 n = e2.n();
00288     if (n == Vector3()) return 0; // no normal on point -> either an internal points or normal is not available
00289 
00290     if (e1.getCollisionModel()->getMechanicalState() == e2.getCollisionModel()->getMechanicalState())
00291     { // self-collisions: make sure the point is not one of the vertices of the tetrahedron
00292     int i = e2.getIndex();
00293     if (i == e1.p1Index() || i == e1.p2Index() || i == e1.p3Index() || i == e1.p4Index())
00294         return 0;
00295     }
00296 
00297     Vector3 P = e2.p();
00298     Vector3 b0 = e1.getBary(P);
00299     if (b0[0] < 0 || b0[1] < 0 || b0[2] < 0 || (b0[0]+b0[1]+b0[2]) > 1)
00300     return 1; // out of tetrahedron
00301 
00302     // Find the point on the surface of the tetrahedron in the direction of -n
00303     Vector3 bdir = e1.getDBary(-n);
00304     //std::cout << "b0 = "<<b0<<" \tbdir = "<<bdir<<std::endl;
00305     double l1 = 1.0e10;
00306     for (int c=0;c<3;++c)
00307     {
00308     if (bdir[c] < -1.0e-10)
00309     {
00310         double l = -b0[c]/bdir[c];
00311         if (l < l1) l1 = l;
00312     }
00313     }
00314     // 4th plane : bx+by+bz = 1
00315     {
00316     double bd = bdir[0]+bdir[1]+bdir[2];
00317     if (bd > 1.0e-10)
00318     {
00319         double l = (1-(b0[0]+b0[1]+b0[2]))/bd;
00320         if (l < l1) l1 = l;
00321     }
00322     }
00323     if (l1 >= 1.0e9) l1 = 0;
00324     double l = l1;
00325     Vector3 X = P-n*l;
00326     
00327     contacts->resize(contacts->size()+1);
00328     DetectionOutput *detection = &*(contacts->end()-1);
00329     detection->point[0] = X;
00330     detection->point[1] = P;
00331     detection->normal = -n;
00332     detection->value = -l;
00333     detection->elem.first = e1;
00334     detection->elem.second = e2;
00335     detection->id = e2.getIndex();
00336     return 1;
00337 }
00338 
00339 bool DiscreteIntersection::testIntersection(RigidDistanceGridCollisionElement&, RigidDistanceGridCollisionElement&)
00340 {
00341     return true;
00342 }
00343 
00344 //#define DEBUG_XFORM
00345 
00346 int DiscreteIntersection::computeIntersection(RigidDistanceGridCollisionElement& e1, RigidDistanceGridCollisionElement& e2, OutputVector* contacts)
00347 {
00348     int nc = 0;
00349     DistanceGrid* grid1 = e1.getGrid();
00350     DistanceGrid* grid2 = e2.getGrid();
00351     bool useXForm = e1.isTransformed() || e2.isTransformed();
00352     const Vector3& t1 = e1.getTranslation();
00353     const Matrix3& r1 = e1.getRotation();
00354     const Vector3& t2 = e2.getTranslation();
00355     const Matrix3& r2 = e2.getRotation();
00356     
00357     const SReal margin = 0.001f; //e1.getProximity() + e2.getProximity();
00358     
00359     // transform from grid1 to grid2
00360     Vec3f translation;
00361     Mat3x3f rotation;
00362     
00363     if (useXForm)
00364     {
00365         // p = t1+r1*p1 = t2+r2*p2
00366         // r2*p2 = t1-t2+r1*p1
00367         // p2 = r2t*(t1-p2) + r2t*r1*p1
00368         translation = r2.multTranspose(t1-t2);
00369         rotation = r2.multTranspose ( r1 );
00370     }
00371     else rotation.identity();
00372 
00373     // For the cube-cube case, we need to detect cases where cubes are stacked
00374     // One way is to find if a pair of faces exists that are nearly parallel and
00375     // that are near each other
00376     // if such pair is found, the corresponding face will be stored in these variables
00377 
00378     enum { FACE_NONE=-1,FACE_XNEG=0,FACE_XPOS,FACE_YNEG,FACE_YPOS,FACE_ZNEG,FACE_ZPOS };
00379     int face_e1 = FACE_NONE;
00380     int face_e2 = FACE_NONE;
00381 
00382     if (grid2->isCube() && grid1->isCube())
00383     {
00384     const SReal cubeDim1 = grid1->getCubeDim();
00385     const SReal cubeDim2 = grid2->getCubeDim();
00386     // current distance found
00387     // we allow only 10% penetration
00388     SReal dist = (SReal)((cubeDim1 + cubeDim2) * 0.1);
00389     // a nearly perpendicular pair would be visible by an entry close to 1 in the rotation matrix
00390     for (int f2 = 0; f2 < 3; f2++)
00391     {
00392         for (int f1 = 0; f1 < 3; f1++)
00393         {
00394         if (rotation[f2][f1] < -0.99 || rotation[f2][f1] > 0.99)
00395         { // found a match
00396             // translation is the position of cube1 center in cube2 space
00397             // so the pair of faces are close if |translation[f2]| is close dim1+dim2
00398             SReal d = rabs(rabs(translation[f2])-(cubeDim1+cubeDim2));
00399             // we should favor normals that are perpendicular to the relative velocity
00400             // however we don't have this information currently, so for now we favor the horizontal face
00401             if (rabs(r2[f2][2]) > 0.99 && d < (cubeDim1 + cubeDim2) * 0.1) d = 0;
00402             if (d < dist)
00403             {
00404             dist = d;
00405             if (translation[f2] > 0)
00406             { // positive side on cube 2
00407                 face_e2 = 2*f2+1;
00408                 if (rotation[f2][f1] > 0)
00409                 { // cubes have same axis orientation -> negative side on cube 1
00410                 face_e1 = 2*f1;
00411                 }
00412                 else
00413                 { // cubes have same opposite orientation -> positive side on cube 1
00414                 face_e1 = 2*f1+1;
00415                 }
00416             }
00417             else
00418             { // negative side on cube 2
00419                 face_e2 = 2*f2;
00420                 if (rotation[f2][f1] > 0)
00421                 { // cubes have same axis orientation -> positive side on cube 1
00422                 face_e1 = 2*f1+1;
00423                 }
00424                 else
00425                 { // cubes have same opposite orientation -> negative side on cube 1
00426                 face_e1 = 2*f1;
00427                 }
00428             }
00429             }
00430         }
00431         }
00432     }
00433     }
00434     
00435     // first points of e1 against distance field of e2
00436     const DistanceGrid::VecCoord& x1 = grid1->meshPts;
00437     if (!x1.empty() && e1.getCollisionModel()->usePoints.getValue())
00438     {
00439         if (grid2->isCube() && grid1->isCube())
00440         {
00441             const SReal cubeDim2 = grid2->getCubeDim();
00442             const SReal cubeDim2Margin = cubeDim2+margin;
00443 
00444         if (face_e2 != FACE_NONE)
00445         { // stacked cubes
00446         DistanceGrid::Coord normal;
00447         normal[face_e2/2] = (face_e2&1)?1.0f:-1.0f;
00448                 Vector3 gnormal = r2 * -normal;
00449                 // special case: if normal in global frame is nearly vertical or horizontal, make it so
00450                      if (gnormal[0] < -0.99f) gnormal = Vector3(-1.0f, 0.0f,  0.0f);
00451                 else if (gnormal[0] >  0.99f) gnormal = Vector3( 1.0f, 0.0f,  0.0f);
00452                      if (gnormal[1] < -0.99f) gnormal = Vector3( 0.0f,-1.0f,  0.0f);
00453                 else if (gnormal[1] >  0.99f) gnormal = Vector3( 0.0f, 1.0f,  0.0f);
00454                      if (gnormal[2] < -0.99f) gnormal = Vector3( 0.0f, 0.0f, -1.0f);
00455                 else if (gnormal[2] >  0.99f) gnormal = Vector3( 0.0f, 0.0f,  1.0f);
00456         for (unsigned int i=0; i<x1.size(); i++)
00457         {
00458             DistanceGrid::Coord p1 = x1[i];
00459             DistanceGrid::Coord p2 = translation + rotation*p1;
00460             if (p2[0] < -cubeDim2Margin || p2[0] > cubeDim2Margin ||
00461             p2[1] < -cubeDim2Margin || p2[1] > cubeDim2Margin ||
00462             p2[2] < -cubeDim2Margin || p2[2] > cubeDim2Margin)
00463             continue;
00464             double d = p2*normal - cubeDim2;
00465 
00466             p2 -= normal * d; // push p2 to the surface
00467             
00468             contacts->resize(contacts->size()+1);
00469             DetectionOutput *detection = &*(contacts->end()-1);
00470             
00471             detection->point[0] = Vector3(p1);
00472             detection->point[1] = Vector3(p2);
00473             detection->normal = gnormal;
00474             detection->value = d;
00475             detection->elem.first = e1;
00476             detection->elem.second = e2;
00477             detection->id = i;
00478             ++nc;
00479         }
00480         }
00481         else
00482         { // general case
00483         for (unsigned int i=0; i<x1.size(); i++)
00484         {
00485             DistanceGrid::Coord p1 = x1[i];
00486             DistanceGrid::Coord p2 = translation + rotation*p1;
00487             if (p2[0] < -cubeDim2Margin || p2[0] > cubeDim2Margin ||
00488             p2[1] < -cubeDim2Margin || p2[1] > cubeDim2Margin ||
00489             p2[2] < -cubeDim2Margin || p2[2] > cubeDim2Margin)
00490             continue;
00491             //double d = p2*normal - cubeDim2;
00492             
00493             DistanceGrid::Coord normal;
00494             normal[0] = rabs(p2[0]) - cubeDim2;
00495             normal[1] = rabs(p2[1]) - cubeDim2;
00496             normal[2] = rabs(p2[2]) - cubeDim2;
00497             
00498             SReal d;
00499             // find the smallest penetration
00500             int axis;
00501             if (normal[0] > normal[1])
00502             if (normal[0] > normal[2]) axis = 0;
00503             else                       axis = 2;
00504             else
00505             if (normal[1] > normal[2]) axis = 1;
00506             else                       axis = 2;
00507             
00508             SReal sign = (p2[axis]<0)?-1.0f:1.0f;
00509             d = normal[axis];
00510             p2[axis] = sign*cubeDim2;
00511             Vector3 gnormal = r2.col(axis) * -sign;
00512             
00513             //p2 -= normal * d; // push p2 to the surface
00514             
00515             contacts->resize(contacts->size()+1);
00516             DetectionOutput *detection = &*(contacts->end()-1);
00517             
00518             detection->point[0] = Vector3(p1);
00519             detection->point[1] = Vector3(p2);
00520             detection->normal = gnormal;
00521             detection->value = d;
00522             detection->elem.first = e1;
00523             detection->elem.second = e2;
00524             detection->id = i;
00525             ++nc;
00526         }
00527         }
00528         }
00529         else
00530         {
00531             for (unsigned int i=0; i<x1.size(); i++)
00532             {
00533                 DistanceGrid::Coord p1 = x1[i];
00534                 DistanceGrid::Coord p2 = translation + rotation*p1;
00535 #ifdef DEBUG_XFORM
00536                 DistanceGrid::Coord p1b = rotation.multTranspose(p2-translation);
00537                 DistanceGrid::Coord gp1 = t1+r1*p1;
00538                 DistanceGrid::Coord gp2 = t2+r2*p2;
00539                 if ((p1b-p1).norm2() > 0.0001f)
00540                     std::cerr << "ERROR1a: " << p1 << " -> " << p2 << " -> " << p1b << std::endl;
00541                 if ((gp1-gp2).norm2() > 0.0001f)
00542                     std::cerr << "ERROR1b: " << p1 << " -> " << gp1 << "    " << p2 << " -> " << gp2 << std::endl;
00543 #endif
00544 
00545                 if (!grid2->inBBox( p2, margin )) continue;
00546                 if (!grid2->inGrid( p2 ))
00547         {
00548             std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e2.getCollisionModel()->getName()<<std::endl;
00549             continue;
00550         }
00551                 
00552                 SReal d = grid2->interp(p2);
00553                 if (d >= margin) continue;
00554                 
00555                 Vector3 grad = grid2->grad(p2); // note that there are some redundant computations between interp() and grad()
00556                 grad.normalize();
00557                 
00558                 //p2 -= grad * d; // push p2 back to the surface
00559                 
00560                 contacts->resize(contacts->size()+1);
00561                 DetectionOutput *detection = &*(contacts->end()-1);
00562                 
00563                 detection->point[0] = Vector3(p1);
00564                 detection->point[1] = Vector3(p2) - grad * d;
00565                 detection->normal = r2 * -grad; // normal in global space from p1's surface
00566                 detection->value = d;
00567                 detection->elem.first = e1;
00568                 detection->elem.second = e2;
00569                 detection->id = i;
00570                 ++nc;
00571             }
00572         }
00573     }
00574     
00575     // then points of e2 against distance field of e1
00576     const DistanceGrid::VecCoord& x2 = grid2->meshPts;
00577     const int i0 = x1.size();
00578     if (!x2.empty() && e2.getCollisionModel()->usePoints.getValue())
00579     {
00580         if (grid1->isCube() && grid2->isCube())
00581         {
00582             const SReal cubeDim1 = grid1->getCubeDim();
00583             const SReal cubeDim1Margin = cubeDim1+margin;
00584 
00585         if (face_e1 != FACE_NONE)
00586         { // stacked cubes
00587         DistanceGrid::Coord normal;
00588         normal[face_e1/2] = (face_e1&1)?1.0f:-1.0f;
00589                 Vector3 gnormal = r1 * normal;
00590                 // special case: if normal in global frame is nearly vertical or horizontal, make it so
00591                      if (gnormal[0] < -0.99f) gnormal = Vector3(-1.0f, 0.0f,  0.0f);
00592                 else if (gnormal[0] >  0.99f) gnormal = Vector3( 1.0f, 0.0f,  0.0f);
00593                      if (gnormal[1] < -0.99f) gnormal = Vector3( 0.0f,-1.0f,  0.0f);
00594                 else if (gnormal[1] >  0.99f) gnormal = Vector3( 0.0f, 1.0f,  0.0f);
00595                      if (gnormal[2] < -0.99f) gnormal = Vector3( 0.0f, 0.0f, -1.0f);
00596                 else if (gnormal[2] >  0.99f) gnormal = Vector3( 0.0f, 0.0f,  1.0f);
00597         for (unsigned int i=0; i<x2.size(); i++)
00598         {
00599             DistanceGrid::Coord p2 = x2[i];
00600             DistanceGrid::Coord p1 = rotation.multTranspose(p2-translation);
00601             if (p1[0] < -cubeDim1Margin || p1[0] > cubeDim1Margin ||
00602             p1[1] < -cubeDim1Margin || p1[1] > cubeDim1Margin ||
00603             p1[2] < -cubeDim1Margin || p1[2] > cubeDim1Margin)
00604             continue;
00605             double d = p1*normal - cubeDim1;
00606 
00607             p1 -= normal * d; // push p2 to the surface
00608             
00609             contacts->resize(contacts->size()+1);
00610             DetectionOutput *detection = &*(contacts->end()-1);
00611             
00612             detection->point[0] = Vector3(p1);
00613             detection->point[1] = Vector3(p2);
00614             detection->normal = gnormal;
00615             detection->value = d;
00616             detection->elem.first = e1;
00617             detection->elem.second = e2;
00618             detection->id = i + i0;
00619             ++nc;
00620         }
00621         }
00622         else
00623         { // general case
00624         for (unsigned int i=0; i<x2.size(); i++)
00625         {
00626             DistanceGrid::Coord p2 = x2[i];
00627             DistanceGrid::Coord p1 = rotation.multTranspose(p2-translation);
00628             if (p1[0] < -cubeDim1Margin || p1[0] > cubeDim1Margin ||
00629             p1[1] < -cubeDim1Margin || p1[1] > cubeDim1Margin ||
00630             p1[2] < -cubeDim1Margin || p1[2] > cubeDim1Margin)
00631             continue;
00632             
00633             DistanceGrid::Coord normal;
00634             normal[0] = rabs(p1[0]) - cubeDim1;
00635             normal[1] = rabs(p1[1]) - cubeDim1;
00636             normal[2] = rabs(p1[2]) - cubeDim1;
00637             
00638             SReal d;
00639             // find the smallest penetration
00640             int axis;
00641             if (normal[0] > normal[1])
00642             if (normal[0] > normal[2]) axis = 0;
00643             else                       axis = 2;
00644             else
00645             if (normal[1] > normal[2]) axis = 1;
00646             else                       axis = 2;
00647             
00648             SReal sign = (p1[axis]<0)?-1.0f:1.0f;
00649             d = normal[axis];
00650             p1[axis] = sign*cubeDim1;
00651             Vector3 gnormal = r1.col(axis) * sign;
00652             
00653             contacts->resize(contacts->size()+1);
00654             DetectionOutput *detection = &*(contacts->end()-1);
00655             
00656             detection->point[0] = Vector3(p1);
00657             detection->point[1] = Vector3(p2);
00658             detection->normal = gnormal;
00659             detection->value = d;
00660             detection->elem.first = e1;
00661             detection->elem.second = e2;
00662             detection->id = i + i0;
00663             ++nc;
00664         }
00665         }
00666 #if 0
00667 #if 0
00668             // -rotationT*translation is the position of cube2 center in cube1 space
00669             // we use its largest component as the dominant contact face normal
00671             Vector3 normal = rotation.multTranspose(-translation);
00672             //normal[2] *= 1.1f; // we like Z contact better ;)
00673             if (rabs(normal[0]) > rabs(normal[1]))
00674             {
00675                 if (rabs(normal[0]) > rabs(normal[2]))
00676                     normal = Vector3(normal[0]>0.0f?1.0f:-1.0f,0.0f,0.0f);
00677                 else
00678                     normal = Vector3(0.0f,0.0f,normal[2]>0.0f?1.0f:-1.0f);
00679             }
00680             else
00681             {
00682                 if (rabs(normal[1]) > rabs(normal[2]))
00683                     normal = Vector3(0.0f,normal[1]>0.0f?1.0f:-1.0f,0.0f);
00684                 else
00685                     normal = Vector3(0.0f,0.0f,normal[2]>0.0f?1.0f:-1.0f);
00686             }
00687 
00688             Vector3 gnormal = r1 * normal; // normal in global space from p1's surface
00689             // special case: if normal in global frame is nearly vertical, make it so
00690                  if (gnormal[2] < -0.99f) gnormal = Vector3(0.0f, 0.0f, -1.0f);
00691             else if (gnormal[2] >  0.99f) gnormal = Vector3(0.0f, 0.0f,  1.0f);
00692 #endif
00693             Vector3 gnormal[3]; // X/Y/Z normals from p1 in global space
00694             for (int i=0;i<3;i++)
00695             {
00696                 gnormal[i] = r1.col(i);
00697                 // special case: if normal in global frame is nearly vertical or horizontal, make it so
00698                      if (gnormal[i][0] < -0.99f) gnormal[i] = Vector3(-1.0f, 0.0f,  0.0f);
00699                 else if (gnormal[i][0] >  0.99f) gnormal[i] = Vector3( 1.0f, 0.0f,  0.0f);
00700                      if (gnormal[i][1] < -0.99f) gnormal[i] = Vector3( 0.0f,-1.0f,  0.0f);
00701                 else if (gnormal[i][1] >  0.99f) gnormal[i] = Vector3( 0.0f, 1.0f,  0.0f);
00702                      if (gnormal[i][2] < -0.99f) gnormal[i] = Vector3( 0.0f, 0.0f, -1.0f);
00703                 else if (gnormal[i][2] >  0.99f) gnormal[i] = Vector3( 0.0f, 0.0f,  1.0f);
00704             }
00705             for (unsigned int i=0; i<x2.size(); i++)
00706             {
00707                 DistanceGrid::Coord p2 = x2[i];
00708                 DistanceGrid::Coord p1 = rotation.multTranspose(p2-translation);
00709                 if (p1[0] < -cubeDim1Margin || p1[0] > cubeDim1Margin ||
00710                     p1[1] < -cubeDim1Margin || p1[1] > cubeDim1Margin ||
00711                     p1[2] < -cubeDim1Margin || p1[2] > cubeDim1Margin)
00712                     continue;
00713                 
00714                 DistanceGrid::Coord p2normal = rotation.multTranspose(grid2->grad(p2)); // normal of p2, in p1's space
00715                 
00716                 DistanceGrid::Coord p1normal;
00717 
00718         p1normal[0] = (cubeDim1Margin - rabs(p1[0]))/(0.000001+rabs(p2normal[0]));
00719                 p1normal[1] = (cubeDim1Margin - rabs(p1[1]))/(0.000001+rabs(p2normal[1]));
00720                 p1normal[2] = (cubeDim1Margin - rabs(p1[2]))/(0.000001+rabs(p2normal[2]));
00721                 
00722                 SReal d;
00723                 Vector3 normal;
00724                 // find the smallest penetration
00725                 int axis;
00726                 //if (p1normal[0]*p2normal[0] < p1normal[1]*p2normal[1])
00727                 if (p1normal[0] < p1normal[1])
00728                 {
00729                     if (p1normal[0] < p1normal[2])
00730                         axis = 0;
00731                     else
00732                         axis = 2;
00733                 }
00734                 else
00735                 {
00736                     if (p1normal[1] < p1normal[2])
00737                         axis = 1;
00738                     else
00739                         axis = 2;
00740                 }
00741                 if (p1[axis]<0)
00742                 {
00743                     d = -cubeDim1 - p1[axis]; // p2normal[axis];
00744                     p1[axis] = -cubeDim1;
00745                     normal = -gnormal[axis];
00746                 }
00747                 else
00748                 {
00749                     d = p1[axis] - cubeDim1; // -p2normal[axis];
00750                     p1[axis] = cubeDim1;
00751                     normal = gnormal[axis];
00752                 }
00753                 
00754                 
00755                 contacts->resize(contacts->size()+1);
00756                 DetectionOutput *detection = &*(contacts->end()-1);
00757                 
00758                 detection->point[0] = Vector3(p1); // - normal * d;
00759                 detection->point[1] = Vector3(p2);
00760                 detection->normal = normal;
00761                 detection->value = d;
00762                 detection->elem.first = e1;
00763                 detection->elem.second = e2;
00764                 detection->id = i0+i;
00765                 ++nc;
00766             }
00767 #endif
00768         }
00769         else
00770         {
00771             for (unsigned int i=0; i<x2.size(); i++)
00772             {
00773                 DistanceGrid::Coord p2 = x2[i];
00774                 DistanceGrid::Coord p1 = rotation.multTranspose(p2-translation);
00775 #ifdef DEBUG_XFORM
00776                 DistanceGrid::Coord p2b = translation + rotation*p1;
00777                 DistanceGrid::Coord gp1 = t1+r1*p1;
00778                 DistanceGrid::Coord gp2 = t2+r2*p2;
00779                 if ((p2b-p2).norm2() > 0.0001f)
00780                     std::cerr << "ERROR2a: " << p2 << " -> " << p1 << " -> " << p2b << std::endl;
00781                 else if ((gp1-gp2).norm2() > 0.0001f)
00782                     std::cerr << "ERROR2b: " << p1 << " -> " << gp1 << "    " << p2 << " -> " << gp2 << std::endl;
00783 #endif
00784 
00785                 if (!grid1->inBBox( p1, margin )) continue;
00786                 if (!grid1->inGrid( p1 ))
00787         {
00788             std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00789             continue;
00790         }
00791                 
00792                 SReal d = grid1->interp(p1);
00793                 if (d >= margin) continue;
00794                 
00795                 Vector3 grad = grid1->grad(p1); // note that there are some redundant computations between interp() and grad()
00796                 grad.normalize();
00797                 
00798                 //p1 -= grad * d; // push p1 back to the surface
00799                 
00800                 contacts->resize(contacts->size()+1);
00801                 DetectionOutput *detection = &*(contacts->end()-1);
00802                 
00803                 detection->point[0] = Vector3(p1) - grad * d;
00804                 detection->point[1] = Vector3(p2);
00805                 detection->normal = r1 * grad; // normal in global space from p1's surface
00806                 detection->value = d;
00807                 detection->elem.first = e1;
00808                 detection->elem.second = e2;
00809                 detection->id = i0+i;
00810                 ++nc;
00811             }
00812         }
00813     }
00814     return nc;
00815 }
00816 
00817 bool DiscreteIntersection::testIntersection(RigidDistanceGridCollisionElement&, Point&)
00818 {
00819     return true;
00820 }
00821 
00822 int DiscreteIntersection::computeIntersection(RigidDistanceGridCollisionElement& e1, Point& e2, OutputVector* contacts)
00823 {
00824     DistanceGrid* grid1 = e1.getGrid();
00825     bool useXForm = e1.isTransformed();
00826     const Vector3& t1 = e1.getTranslation();
00827     const Matrix3& r1 = e1.getRotation();
00828 
00829     const double d0 = e1.getProximity() + e2.getProximity() + getContactDistance();
00830     const SReal margin = 0.001f + (SReal)d0;
00831 
00832     Vector3 p2 = e2.p();
00833     DistanceGrid::Coord p1;
00834 
00835     if (useXForm)
00836     {
00837          p1 = r1.multTranspose(p2-t1);
00838     }
00839     else p1 = p2;
00840 
00841     if (!grid1->inBBox( p1, margin )) return 0;
00842     if (!grid1->inGrid( p1 ))
00843     {
00844     std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00845     return 0;
00846     }
00847 
00848     SReal d = grid1->interp(p1);
00849     if (d >= margin) return 0;
00850 
00851     Vector3 grad = grid1->grad(p1); // note that there are some redundant computations between interp() and grad()
00852     grad.normalize();
00853 
00854     //p1 -= grad * d; // push p1 back to the surface
00855 
00856     contacts->resize(contacts->size()+1);
00857     DetectionOutput *detection = &*(contacts->end()-1);
00858 
00859     detection->point[0] = Vector3(p1) - grad * d;
00860     detection->point[1] = Vector3(p2);
00861     detection->normal = (useXForm) ? r1 * grad : grad; // normal in global space from p1's surface
00862     detection->value = d - d0;
00863     detection->elem.first = e1;
00864     detection->elem.second = e2;
00865     detection->id = e2.getIndex();
00866     return 1;
00867 }
00868 
00869 bool DiscreteIntersection::testIntersection(RigidDistanceGridCollisionElement&, Triangle&)
00870 {
00871     return true;
00872 }
00873 
00874 int DiscreteIntersection::computeIntersection(RigidDistanceGridCollisionElement& e1, Triangle& e2, OutputVector* contacts)
00875 {
00876     const int f2 = e2.flags();
00877     if (!(f2&TriangleModel::FLAG_POINTS)) return 0; // no points associated with this triangle
00878     DistanceGrid* grid1 = e1.getGrid();
00879     bool useXForm = e1.isTransformed();
00880     const Vector3& t1 = e1.getTranslation();
00881     const Matrix3& r1 = e1.getRotation();
00882 
00883     const double d0 = e1.getProximity() + e2.getProximity() + getContactDistance();
00884     const SReal margin = 0.001f + (SReal)d0;
00885 
00886     if (f2&TriangleModel::FLAG_P1)
00887     {
00888         Vector3 p2 = e2.p1();
00889         DistanceGrid::Coord p1;
00890     
00891         if (useXForm)
00892         {
00893             p1 = r1.multTranspose(p2-t1);
00894         }
00895         else p1 = p2;
00896     
00897         if (grid1->inBBox( p1, margin ))
00898     {
00899         if (!grid1->inGrid( p1 ))
00900         {
00901         std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00902         }
00903         else
00904         {
00905         SReal d = grid1->interp(p1);
00906         if (d >= margin) return 0;
00907         
00908         Vector3 grad = grid1->grad(p1); // note that there are some redundant computations between interp() and grad()
00909         grad.normalize();
00910         
00911         //p1 -= grad * d; // push p1 back to the surface
00912         
00913         contacts->resize(contacts->size()+1);
00914         DetectionOutput *detection = &*(contacts->end()-1);
00915         
00916         detection->point[0] = Vector3(p1) - grad * d;
00917         detection->point[1] = Vector3(p2);
00918         detection->normal = (useXForm) ? r1 * grad : grad; // normal in global space from p1's surface
00919         detection->value = d - d0;
00920         detection->elem.first = e1;
00921         detection->elem.second = e2;
00922         detection->id = e2.getIndex()*3+0;
00923         }
00924     }
00925     }
00926 
00927     if (f2&TriangleModel::FLAG_P2)
00928     {
00929         Vector3 p2 = e2.p2();
00930         DistanceGrid::Coord p1;
00931     
00932         if (useXForm)
00933         {
00934             p1 = r1.multTranspose(p2-t1);
00935         }
00936         else p1 = p2;
00937     
00938         if (grid1->inBBox( p1, margin ))
00939     {
00940         if (!grid1->inGrid( p1 ))
00941         {
00942         std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00943         }
00944         else
00945         {
00946         SReal d = grid1->interp(p1);
00947         if (d >= margin) return 0;
00948         
00949         Vector3 grad = grid1->grad(p1); // note that there are some redundant computations between interp() and grad()
00950         grad.normalize();
00951         
00952         //p1 -= grad * d; // push p1 back to the surface
00953         
00954         contacts->resize(contacts->size()+1);
00955         DetectionOutput *detection = &*(contacts->end()-1);
00956         
00957         detection->point[0] = Vector3(p1) - grad * d;
00958         detection->point[1] = Vector3(p2);
00959         detection->normal = (useXForm) ? r1 * grad : grad; // normal in global space from p1's surface
00960         detection->value = d - d0;
00961         detection->elem.first = e1;
00962         detection->elem.second = e2;
00963         detection->id = e2.getIndex()*3+1;
00964         }
00965     }
00966     }
00967 
00968     if (f2&TriangleModel::FLAG_P3)
00969     {
00970         Vector3 p2 = e2.p3();
00971         DistanceGrid::Coord p1;
00972     
00973         if (useXForm)
00974         {
00975             p1 = r1.multTranspose(p2-t1);
00976         }
00977         else p1 = p2;
00978     
00979         if (grid1->inBBox( p1, margin ))
00980     {
00981         if (!grid1->inGrid( p1 ))
00982         {
00983         std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00984         }
00985         else
00986         {
00987         SReal d = grid1->interp(p1);
00988         if (d >= margin) return 0;
00989         
00990         Vector3 grad = grid1->grad(p1); // note that there are some redundant computations between interp() and grad()
00991         grad.normalize();
00992         
00993         //p1 -= grad * d; // push p1 back to the surface
00994         
00995         contacts->resize(contacts->size()+1);
00996         DetectionOutput *detection = &*(contacts->end()-1);
00997         
00998         detection->point[0] = Vector3(p1) - grad * d;
00999         detection->point[1] = Vector3(p2);
01000         detection->normal = (useXForm) ? r1 * grad : grad; // normal in global space from p1's surface
01001         detection->value = d - d0;
01002         detection->elem.first = e1;
01003         detection->elem.second = e2;
01004         detection->id = e2.getIndex()*3+2;
01005         }
01006     }
01007     }
01008     return 1;
01009 }
01010 
01011 bool DiscreteIntersection::testIntersection(Ray& /*e2*/, RigidDistanceGridCollisionElement& /*e1*/)
01012 {
01013     return true;
01014 }
01015 
01016 int DiscreteIntersection::computeIntersection(Ray& e2, RigidDistanceGridCollisionElement& e1, OutputVector* contacts)
01017 {
01018     Vector3 rayOrigin(e2.origin());
01019     Vector3 rayDirection(e2.direction());
01020     const double rayLength = e2.l();
01021 
01022     int nc = 0;
01023     DistanceGrid* grid1 = e1.getGrid();
01024     bool useXForm = e1.isTransformed();
01025 
01026     if (useXForm)
01027     {
01028         const Vector3& t1 = e1.getTranslation();
01029         const Matrix3& r1 = e1.getRotation();
01030         rayOrigin = r1.multTranspose(rayOrigin-t1);
01031         rayDirection = r1.multTranspose(rayDirection);
01032         // now ray infos are in grid1 space
01033     }
01034 
01035     double l0 = 0;
01036     double l1 = rayLength;
01037     Vector3 r0 = rayOrigin;
01038     Vector3 r1 = rayOrigin + rayDirection*l1;
01039 
01040     DistanceGrid::Coord bbmin = grid1->getBBMin(), bbmax = grid1->getBBMax();
01041     // clip along each axis
01042     for (int c=0;c<3 && l1>l0;c++)
01043     {
01044         if (rayDirection[c] > 0)
01045         {
01046             // test if the ray is inside
01047             if (r1[c] < bbmin[c] || r0[c] > bbmax[c])
01048             { l1 = 0; break; }
01049             if (r0[c] < bbmin[c])
01050             {
01051                 // intersect with p[c] == bbmin[c] plane
01052                 double l = (bbmin[c]-rayOrigin[c]) / rayDirection[c];
01053                 if(l0 < l)
01054                 {
01055                     l0 = l;
01056                     r0 = rayOrigin + rayDirection*l0;
01057                 }
01058             }
01059             if (r1[c] > bbmax[c])
01060             {
01061                 // intersect with p[c] == bbmax[c] plane
01062                 double l = (bbmax[c]-rayOrigin[c]) / rayDirection[c];
01063                 if(l1 > l)
01064                 {
01065                     l1 = l;
01066                     r1 = rayOrigin + rayDirection*l1;
01067                 }
01068             }
01069         }
01070         else
01071         {
01072             // test if the ray is inside
01073             if (r0[c] < bbmin[c] || r1[c] > bbmax[c])
01074             { l1 = 0; break; }
01075             if (r0[c] > bbmax[c])
01076             {
01077                 // intersect with p[c] == bbmax[c] plane
01078                 double l = (bbmax[c]-rayOrigin[c]) / rayDirection[c];
01079                 if(l0 < l)
01080                 {
01081                     l0 = l;
01082                     r0 = rayOrigin + rayDirection*l0;
01083                 }
01084             }
01085             if (r1[c] < bbmin[c])
01086             {
01087                 // intersect with p[c] == bbmin[c] plane
01088                 double l = (bbmin[c]-rayOrigin[c]) / rayDirection[c];
01089                 if(l1 > l)
01090                 {
01091                     l1 = l;
01092                     r1 = rayOrigin + rayDirection*l1;
01093                 }
01094             }
01095         }
01096 
01097     }
01098 
01099     if (l0 < l1)
01100     { // some part of the ray is inside the grid
01101         Vector3 p = rayOrigin + rayDirection*l0;
01102         double dist = grid1->interp(p);
01103         double epsilon = grid1->getCellWidth().norm()*0.1f;
01104         while (l0 < l1 && (dist > epsilon || dist < -epsilon))
01105         {
01106             l0 += dist;
01107             p = rayOrigin + rayDirection*l0;
01108             dist = grid1->interp(p);
01109         //std::cout << "p="<<p<<" dist="<<dist<<" l0="<<l0<<" l1="<<l1<<" epsilon="<<epsilon<<std::endl;
01110         }
01111         if (dist < epsilon)
01112         { // intersection found
01113             
01114             contacts->resize(contacts->size()+1);
01115             DetectionOutput *detection = &*(contacts->end()-1);
01116             
01117             detection->point[0] = e2.origin() + e2.direction()*l0;
01118             detection->point[1] = p;
01119             detection->normal = e2.direction(); // normal in global space from p1's surface
01120             detection->value = dist;
01121             detection->elem.first = e2;
01122             detection->elem.second = e1;
01123             detection->id = e2.getIndex();
01124             ++nc;
01125         }
01126     }
01127     return nc;
01128 }
01129 
01130 bool DiscreteIntersection::testIntersection(FFDDistanceGridCollisionElement&, RigidDistanceGridCollisionElement&)
01131 {
01132     return true;
01133 }
01134 
01135 int DiscreteIntersection::computeIntersection(FFDDistanceGridCollisionElement& e1, RigidDistanceGridCollisionElement& e2, OutputVector* contacts)
01136 {
01137     int nc = 0;
01138     DistanceGrid* grid1 = e1.getGrid();
01139     DistanceGrid* grid2 = e2.getGrid();
01140     FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
01141     bool useXForm = e2.isTransformed();
01142     //const Vector3& t1 = e1.getTranslation();
01143     //const Matrix3& r1 = e1.getRotation();
01144     const Vector3& t2 = e2.getTranslation();
01145     const Matrix3& r2 = e2.getRotation();
01146     
01147     const double d0 = e1.getProximity() + e2.getProximity();
01148     const SReal margin = 0.001f + (SReal)d0;
01149     
01150     // transform from grid1 to grid2
01151     Vec3f translation;
01152     Mat3x3f rotation;
01153     
01154     if (useXForm)
01155     {
01156         translation = r2.multTranspose(-t2);
01157         rotation = r2; rotation.transpose();
01158     }
01159     else rotation.identity();
01160     
01161     const DistanceGrid::Coord center2 = translation + rotation*c1.center;
01162     const SReal radius2 = c1.radius*c1.radius;
01163     const DistanceGrid::VecCoord& x2 = grid2->meshPts;
01164     const int i0 = x2.size();
01165     // first points of e1 against distance field of e2
01166     if (e1.getCollisionModel()->usePoints.getValue()) // && !e2.getCollisionModel()->usePoints.getValue())
01167     {
01168         if (grid2->inBBox( center2, margin + c1.radius ))
01169         {
01170             c1.updatePoints();
01171             const sofa::helper::vector<DistanceGrid::Coord>& x1 = c1.deformedPoints;
01172             for (unsigned int i=0; i<x1.size(); i++)
01173             {
01174                 DistanceGrid::Coord p1 = x1[i];
01175                 DistanceGrid::Coord p2 = translation + rotation*p1;
01176 
01177                 if (!grid2->inBBox( p2, margin )) continue;
01178         if (!grid2->inGrid( p2 ))
01179         {
01180             std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e2.getCollisionModel()->getName()<<std::endl;
01181             continue;
01182         }
01183                 
01184                 SReal d = grid2->interp(p2);
01185                 if (d >= margin) continue;
01186                 
01187                 Vector3 grad = grid2->grad(p2); // note that there are some redundant computations between interp() and grad()
01188                 grad.normalize();
01189                 
01190                 //p2 -= grad * d; // push p2 back to the surface
01191                 
01192                 contacts->resize(contacts->size()+1);
01193                 DetectionOutput *detection = &*(contacts->end()-1);
01194                 
01195                 detection->point[0] = grid1->meshPts[c1.points[i].index];
01196                 detection->point[1] = Vector3(p2) - grad * d;
01197                 detection->normal = r2 * -grad; // normal in global space from p1's surface
01198                 detection->value = d - d0;
01199                 detection->elem.first = e1;
01200                 detection->elem.second = e2;
01201                 detection->id = i0 + c1.points[i].index;
01202                 ++nc;
01203             }
01204         }
01205     }
01206     
01207     // then points of e2 against distance field of e1
01208     
01209     if (!x2.empty() && e2.getCollisionModel()->usePoints.getValue())
01210     {
01211         const SReal cubesize = c1.invDP.norm();
01212         for (unsigned int i=0; i<x2.size(); i++)
01213         {
01214             DistanceGrid::Coord p2 = x2[i];
01215             if ((p2-center2).norm2() >= radius2) continue;
01216             DistanceGrid::Coord p1 = rotation.multTranspose(p2-translation);
01217             // try to find the point in the undeformed cube
01218             {
01219                 c1.updateFaces();
01220                 // estimate the barycentric coordinates
01221                 DistanceGrid::Coord b = c1.undeform0(p1);
01222                 
01223                 // refine the estimate until we are very close to the p1 or we are sure p1 cannot intersect with the object
01224                 int iter;
01225                 SReal err1 = 1000.0f;
01226                 for(iter=0; iter<5; ++iter)
01227                 {
01228                     DistanceGrid::Coord pdeform = c1.deform(b);
01229                     DistanceGrid::Coord diff = p1-pdeform;
01230                     SReal err = diff.norm();
01231                     SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01232                     if (b[0] < -berr || b[0] > 1+berr
01233                      || b[1] < -berr || b[1] > 1+berr
01234                      || b[2] < -berr || b[2] > 1+berr)
01235                         break; // far from the cube
01236                     if (iter>3)
01237                         std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01238                     if (err < 0.005f)
01239                     { // we found the corresponding point, but is is only valid if inside the current cube
01240                         if (b[0] > 0.001f && b[0] < 0.999f
01241                          && b[1] > 0.001f && b[1] < 0.999f
01242                          && b[2] > 0.001f && b[2] < 0.999f)
01243                         {
01244                             DistanceGrid::Coord pinit = c1.initpos(b);
01245                             SReal d = grid1->interp(pinit);
01246                             if (d < margin)
01247                             {
01248                                 DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
01249                                 grad.normalize();
01250                                 pinit -= grad*d;
01251                                 grad = c1.deformDir(c1.baryCoords(pinit),grad);
01252                                 grad.normalize();
01253                                 
01254                                 contacts->resize(contacts->size()+1);
01255                                 DetectionOutput *detection = &*(contacts->end()-1);
01256                                 
01257                                 detection->point[0] = Vector3(pinit);
01258                                 detection->point[1] = Vector3(p2);
01259                                 detection->normal = Vector3(grad); // normal in global space from p1's surface
01260                                 detection->value = d - d0;
01261                                 detection->elem.first = e1;
01262                                 detection->elem.second = e2;
01263                                 detection->id = i;
01264                                 ++nc;
01265                             }
01266                         }
01267                         break;
01268                     }
01269                     err1 = err;
01270                     SReal d = grid1->interp(c1.initpos(b));
01271                     if (d*0.5f - err > margin)
01272                         break; // the point is too far from the object
01273                     // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01274                     // deform(b+db) ~= deform(b) + J db  -> J db = p1-deform(b) -> db = J^-1 (p1-deform(b))
01275                     b += c1.undeformDir( b, diff );
01276                 }
01277                 if (iter == 5)
01278                 {
01279                     if (b[0] > 0.001f && b[0] < 0.999f
01280                      && b[1] > 0.001f && b[1] < 0.999f
01281                      && b[2] > 0.001f && b[2] < 0.999f)
01282                         std::cerr << "ERROR: FFD-Rigid 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;
01283                 }
01284             }
01285         }
01286     }
01287     return nc;
01288 }
01289 
01290 
01291 bool DiscreteIntersection::testIntersection(FFDDistanceGridCollisionElement&, FFDDistanceGridCollisionElement&)
01292 {
01293     return true;
01294 }
01295 
01296 int DiscreteIntersection::computeIntersection(FFDDistanceGridCollisionElement& e1, FFDDistanceGridCollisionElement& e2, OutputVector* contacts)
01297 {
01298     int nc = 0;
01299     DistanceGrid* grid1 = e1.getGrid();
01300     DistanceGrid* grid2 = e2.getGrid();
01301     FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
01302     FFDDistanceGridCollisionModel::DeformedCube& c2 = e2.getCollisionModel()->getDeformCube(e2.getIndex());
01303     const bool usePoints1 = e1.getCollisionModel()->usePoints.getValue();
01304     const bool usePoints2 = e2.getCollisionModel()->usePoints.getValue();
01305     
01306     if (!usePoints1 && !usePoints2) return 0; // no tests possible
01307     
01308     const double d0 = e1.getProximity() + e2.getProximity();
01309     const SReal margin = 0.001f + (SReal)d0;
01310     
01311     if ((c2.center - c1.center).norm2() > (c1.radius+c2.radius)*(c1.radius+c2.radius))
01312         return 0; // the two enclosing spheres are not colliding
01313     
01314     int i0 = grid1->meshPts.size();
01315     if (usePoints1)
01316     {
01317         c1.updatePoints();
01318         c2.updateFaces();
01319         const SReal cubesize = c2.invDP.norm();
01320         const sofa::helper::vector<DistanceGrid::Coord>& x1 = c1.deformedPoints;
01321         for (unsigned int i=0; i<x1.size(); i++)
01322         {
01323             DistanceGrid::Coord p2 = x1[i];
01324 
01325             // estimate the barycentric coordinates
01326             DistanceGrid::Coord b = c2.undeform0(p2);
01327 
01328             // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01329             int iter;
01330             SReal err1 = 1000.0f;
01331             for(iter=0; iter<5; ++iter)
01332             {
01333                 DistanceGrid::Coord pdeform = c2.deform(b);
01334                 DistanceGrid::Coord diff = p2-pdeform;
01335                 SReal err = diff.norm();
01336                 SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01337                 if (b[0] < -berr || b[0] > 1+berr
01338                  || b[1] < -berr || b[1] > 1+berr
01339                  || b[2] < -berr || b[2] > 1+berr)
01340                     break; // far from the cube
01341                 if (iter>3)
01342                     std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid2->interp(c2.initpos(b))<<"\n";
01343                 if (err < 0.005f)
01344                 { // we found the corresponding point, but is is only valid if inside the current cube
01345                     if (b[0] > 0.001f && b[0] < 0.999f
01346                      && b[1] > 0.001f && b[1] < 0.999f
01347                      && b[2] > 0.001f && b[2] < 0.999f)
01348                     {
01349                         DistanceGrid::Coord pinit = c2.initpos(b);
01350                         SReal d = grid2->interp(pinit);
01351                         if (d < margin)
01352                         {
01353                             DistanceGrid::Coord grad = grid2->grad(pinit); // note that there are some redundant computations between interp() and grad()
01354                             grad.normalize();
01355                             pinit -= grad*d;
01356                             grad = c2.deformDir(c2.baryCoords(pinit),grad);
01357                             grad.normalize();
01358                             
01359                             contacts->resize(contacts->size()+1);
01360                             DetectionOutput *detection = &*(contacts->end()-1);
01361                             
01362                             detection->point[0] = Vector3(grid1->meshPts[c1.points[i].index]);
01363                             detection->point[1] = Vector3(pinit);
01364                             detection->normal = Vector3(-grad); // normal in global space from p1's surface
01365                             detection->value = d - d0;
01366                             detection->elem.first = e1;
01367                             detection->elem.second = e2;
01368                             detection->id = c1.points[i].index;
01369                             ++nc;
01370                         }
01371                     }
01372                     break;
01373                 }
01374                 err1 = err;
01375                 SReal d = grid2->interp(c2.initpos(b));
01376                 if (d*0.5f - err > margin)
01377                     break; // the point is too far from the object
01378                 // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01379                 // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
01380                 b += c2.undeformDir( b, diff );
01381             }
01382             if (iter == 5)
01383             {
01384                 if (b[0] > 0.001f && b[0] < 0.999f
01385                  && b[1] > 0.001f && b[1] < 0.999f
01386                  && b[2] > 0.001f && b[2] < 0.999f)
01387                     std::cerr << "ERROR: FFD-FFD collision failed to converge to undeformed point: p2 = "<<p2<<" b = "<<b<<" c000 = "<<c2.corners[0]<<" c100 = "<<c2.corners[1]<<" c010 = "<<c2.corners[2]<<" c110 = "<<c2.corners[3]<<" c001 = "<<c2.corners[4]<<" c101 = "<<c2.corners[5]<<" c011 = "<<c2.corners[6]<<" c111 = "<<c2.corners[7]<<" pinit = "<<c2.initpos(b)<<" pdeform = "<<c2.deform(b)<<" err = "<<err1<<std::endl;
01388             }
01389         }
01390     }
01391     if (usePoints2)
01392     {
01393         c2.updatePoints();
01394         c1.updateFaces();
01395         const SReal cubesize = c1.invDP.norm();
01396         const sofa::helper::vector<DistanceGrid::Coord>& x2 = c2.deformedPoints;
01397         for (unsigned int i=0; i<x2.size(); i++)
01398         {
01399             DistanceGrid::Coord p1 = x2[i];
01400 
01401             // estimate the barycentric coordinates
01402             DistanceGrid::Coord b = c1.undeform0(p1);
01403 
01404             // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01405             int iter;
01406             SReal err1 = 1000.0f;
01407             for(iter=0; iter<5; ++iter)
01408             {
01409                 DistanceGrid::Coord pdeform = c1.deform(b);
01410                 DistanceGrid::Coord diff = p1-pdeform;
01411                 SReal err = diff.norm();
01412                 if (iter>3)
01413                     std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01414                 SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01415                 if (b[0] < -berr || b[0] > 1+berr
01416                  || b[1] < -berr || b[1] > 1+berr
01417                  || b[2] < -berr || b[2] > 1+berr)
01418                     break; // far from the cube
01419                 if (err < 0.005f)
01420                 { // we found the corresponding point, but is is only valid if inside the current cube
01421                     if (b[0] > 0.001f && b[0] < 0.999f
01422                      && b[1] > 0.001f && b[1] < 0.999f
01423                      && b[2] > 0.001f && b[2] < 0.999f)
01424                     {
01425                         DistanceGrid::Coord pinit = c1.initpos(b);
01426                         SReal d = grid1->interp(pinit);
01427                         if (d < margin)
01428                         {
01429                             DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
01430                             grad.normalize();
01431                             pinit -= grad*d;
01432                             grad = c1.deformDir(c1.baryCoords(pinit),grad);
01433                             grad.normalize();
01434                             
01435                             contacts->resize(contacts->size()+1);
01436                             DetectionOutput *detection = &*(contacts->end()-1);
01437                             
01438                             detection->point[0] = Vector3(pinit);
01439                             detection->point[1] = Vector3(grid2->meshPts[c2.points[i].index]);
01440                             detection->normal = Vector3(grad); // normal in global space from p1's surface
01441                             detection->value = d - d0;
01442                             detection->elem.first = e1;
01443                             detection->elem.second = e2;
01444                             detection->id = i0+c2.points[i].index;
01445                             ++nc;
01446                         }
01447                     }
01448                     break;
01449                 }
01450                 err1 = err;
01451                 SReal d = grid1->interp(c1.initpos(b));
01452                 if (d*0.5f - err > margin)
01453                     break; // the point is too far from the object
01454                 // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01455                 // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
01456                 b += c1.undeformDir( b, diff );
01457             }
01458             if (iter == 5)
01459             {
01460                 if (b[0] > 0.001f && b[0] < 0.999f
01461                  && b[1] > 0.001f && b[1] < 0.999f
01462                  && b[2] > 0.001f && b[2] < 0.999f)
01463                     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;
01464             }
01465         }
01466     }
01467     return nc;
01468 }
01469 
01470 bool DiscreteIntersection::testIntersection(FFDDistanceGridCollisionElement&, Point&)
01471 {
01472     return true;
01473 }
01474 
01475 int DiscreteIntersection::computeIntersection(FFDDistanceGridCollisionElement& e1, Point& e2, OutputVector* contacts)
01476 {
01477 
01478     DistanceGrid* grid1 = e1.getGrid();
01479     FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
01480 
01481     const double d0 = e1.getProximity() + e2.getProximity() + getContactDistance();
01482     const SReal margin = 0.001f + (SReal)d0;
01483 
01484     c1.updateFaces();
01485     const SReal cubesize = c1.invDP.norm();
01486     int nc = 0;
01487     
01488     Vector3 p2 = e2.p();
01489     DistanceGrid::Coord p1 = p2;
01490 
01491     // estimate the barycentric coordinates
01492     DistanceGrid::Coord b = c1.undeform0(p1);
01493 
01494     // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01495     int iter;
01496     SReal err1 = 1000.0f;
01497     for(iter=0; iter<5; ++iter)
01498     {
01499         DistanceGrid::Coord pdeform = c1.deform(b);
01500         DistanceGrid::Coord diff = p1-pdeform;
01501         SReal err = diff.norm();
01502         if (iter>3)
01503             std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01504         SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01505         if (b[0] < -berr || b[0] > 1+berr
01506             || b[1] < -berr || b[1] > 1+berr
01507             || b[2] < -berr || b[2] > 1+berr)
01508             break; // far from the cube
01509         if (err < 0.005f)
01510         { // we found the corresponding point, but is is only valid if inside the current cube
01511             if (b[0] > 0.001f && b[0] < 0.999f
01512                 && b[1] > 0.001f && b[1] < 0.999f
01513                 && b[2] > 0.001f && b[2] < 0.999f)
01514             {
01515                 DistanceGrid::Coord pinit = c1.initpos(b);
01516                 SReal d = grid1->interp(pinit);
01517                 if (d < margin)
01518                 {
01519                     DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
01520                     grad.normalize();
01521                     pinit -= grad*d;
01522                     grad = c1.deformDir(c1.baryCoords(pinit),grad);
01523                     grad.normalize();
01524                     
01525                     contacts->resize(contacts->size()+1);
01526                     DetectionOutput *detection = &*(contacts->end()-1);
01527                     
01528                     detection->point[0] = Vector3(pinit);
01529                     detection->point[1] = Vector3(p2);
01530                     detection->normal = Vector3(grad); // normal in global space from p1's surface
01531                     detection->value = d - d0;
01532                     detection->elem.first = e1;
01533                     detection->elem.second = e2;
01534                     detection->id = e2.getIndex();
01535                     ++nc;
01536                 }
01537             }
01538             break;
01539         }
01540         err1 = err;
01541         SReal d = grid1->interp(c1.initpos(b));
01542         if (d*0.5f - err > margin)
01543             break; // the point is too far from the object
01544         // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01545         // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
01546         b += c1.undeformDir( b, diff );
01547     }
01548     if (iter == 5)
01549     {
01550         if (b[0] > 0.001f && b[0] < 0.999f
01551             && b[1] > 0.001f && b[1] < 0.999f
01552             && b[2] > 0.001f && b[2] < 0.999f)
01553             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;
01554     }
01555 
01556     return nc;
01557 }
01558 
01559 bool DiscreteIntersection::testIntersection(FFDDistanceGridCollisionElement&, Triangle&)
01560 {
01561     return true;
01562 }
01563 
01564 int DiscreteIntersection::computeIntersection(FFDDistanceGridCollisionElement& e1, Triangle& e2, OutputVector* contacts)
01565 {
01566     const int f2 = e2.flags();
01567     if (!(f2&TriangleModel::FLAG_POINTS)) return 0; // no points associated with this triangle
01568 
01569     DistanceGrid* grid1 = e1.getGrid();
01570     FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
01571 
01572     const double d0 = e1.getProximity() + e2.getProximity() + getContactDistance();
01573     const SReal margin = 0.001f + (SReal)d0;
01574 
01575     c1.updateFaces();
01576     const SReal cubesize = c1.invDP.norm();
01577     int nc = 0;
01578 
01579     if (f2&TriangleModel::FLAG_P1)
01580     {
01581         Vector3 p2 = e2.p1();
01582         DistanceGrid::Coord p1 = p2;
01583     
01584         // estimate the barycentric coordinates
01585         DistanceGrid::Coord b = c1.undeform0(p1);
01586     
01587         // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01588         int iter;
01589         SReal err1 = 1000.0f;
01590         for(iter=0; iter<5; ++iter)
01591         {
01592             DistanceGrid::Coord pdeform = c1.deform(b);
01593             DistanceGrid::Coord diff = p1-pdeform;
01594             SReal err = diff.norm();
01595             if (iter>3)
01596                 std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01597             SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01598             if (b[0] < -berr || b[0] > 1+berr
01599                 || b[1] < -berr || b[1] > 1+berr
01600                 || b[2] < -berr || b[2] > 1+berr)
01601                 break; // far from the cube
01602             if (err < 0.005f)
01603             { // we found the corresponding point, but is is only valid if inside the current cube
01604                 if (b[0] > 0.001f && b[0] < 0.999f
01605                     && b[1] > 0.001f && b[1] < 0.999f
01606                     && b[2] > 0.001f && b[2] < 0.999f)
01607                 {
01608                     DistanceGrid::Coord pinit = c1.initpos(b);
01609                     SReal d = grid1->interp(pinit);
01610                     if (d < margin)
01611                     {
01612                         DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
01613                         grad.normalize();
01614                         pinit -= grad*d;
01615                         grad = c1.deformDir(c1.baryCoords(pinit),grad);
01616                         grad.normalize();
01617                         
01618                         contacts->resize(contacts->size()+1);
01619                         DetectionOutput *detection = &*(contacts->end()-1);
01620                         
01621                         detection->point[0] = Vector3(pinit);
01622                         detection->point[1] = Vector3(p2);
01623                         detection->normal = Vector3(grad); // normal in global space from p1's surface
01624                         detection->value = d - d0;
01625                         detection->elem.first = e1;
01626                         detection->elem.second = e2;
01627                         detection->id = e2.getIndex()*3+0;
01628                         ++nc;
01629                     }
01630                 }
01631                 break;
01632             }
01633             err1 = err;
01634             SReal d = grid1->interp(c1.initpos(b));
01635             if (d*0.5f - err > margin)
01636                 break; // the point is too far from the object
01637             // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01638             // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
01639             b += c1.undeformDir( b, diff );
01640         }
01641         if (iter == 5)
01642         {
01643             if (b[0] > 0.001f && b[0] < 0.999f
01644                 && b[1] > 0.001f && b[1] < 0.999f
01645                 && b[2] > 0.001f && b[2] < 0.999f)
01646                 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;
01647         }
01648     }
01649 
01650     if (f2&TriangleModel::FLAG_P2)
01651     {
01652         Vector3 p2 = e2.p2();
01653         DistanceGrid::Coord p1 = p2;
01654     
01655         // estimate the barycentric coordinates
01656         DistanceGrid::Coord b = c1.undeform0(p1);
01657     
01658         // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01659         int iter;
01660         SReal err1 = 1000.0f;
01661         for(iter=0; iter<5; ++iter)
01662         {
01663             DistanceGrid::Coord pdeform = c1.deform(b);
01664             DistanceGrid::Coord diff = p1-pdeform;
01665             SReal err = diff.norm();
01666             if (iter>3)
01667                 std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01668             SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01669             if (b[0] < -berr || b[0] > 1+berr
01670                 || b[1] < -berr || b[1] > 1+berr
01671                 || b[2] < -berr || b[2] > 1+berr)
01672                 break; // far from the cube
01673             if (err < 0.005f)
01674             { // we found the corresponding point, but is is only valid if inside the current cube
01675                 if (b[0] > 0.001f && b[0] < 0.999f
01676                     && b[1] > 0.001f && b[1] < 0.999f
01677                     && b[2] > 0.001f && b[2] < 0.999f)
01678                 {
01679                     DistanceGrid::Coord pinit = c1.initpos(b);
01680                     SReal d = grid1->interp(pinit);
01681                     if (d < margin)
01682                     {
01683                         DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
01684                         grad.normalize();
01685                         pinit -= grad*d;
01686                         grad = c1.deformDir(c1.baryCoords(pinit),grad);
01687                         grad.normalize();
01688                         
01689                         contacts->resize(contacts->size()+1);
01690                         DetectionOutput *detection = &*(contacts->end()-1);
01691                         
01692                         detection->point[0] = Vector3(pinit);
01693                         detection->point[1] = Vector3(p2);
01694                         detection->normal = Vector3(grad); // normal in global space from p1's surface
01695                         detection->value = d - d0;
01696                         detection->elem.first = e1;
01697                         detection->elem.second = e2;
01698                         detection->id = e2.getIndex()*3+1;
01699                         ++nc;
01700                     }
01701                 }
01702                 break;
01703             }
01704             err1 = err;
01705             SReal d = grid1->interp(c1.initpos(b));
01706             if (d*0.5f - err > margin)
01707                 break; // the point is too far from the object
01708             // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01709             // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
01710             b += c1.undeformDir( b, diff );
01711         }
01712         if (iter == 5)
01713         {
01714             if (b[0] > 0.001f && b[0] < 0.999f
01715                 && b[1] > 0.001f && b[1] < 0.999f
01716                 && b[2] > 0.001f && b[2] < 0.999f)
01717                 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;
01718         }
01719     }
01720 
01721     if (f2&TriangleModel::FLAG_P3)
01722     {
01723         Vector3 p2 = e2.p3();
01724         DistanceGrid::Coord p1 = p2;
01725     
01726         // estimate the barycentric coordinates
01727         DistanceGrid::Coord b = c1.undeform0(p1);
01728     
01729         // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01730         int iter;
01731         SReal err1 = 1000.0f;
01732         for(iter=0; iter<5; ++iter)
01733         {
01734             DistanceGrid::Coord pdeform = c1.deform(b);
01735             DistanceGrid::Coord diff = p1-pdeform;
01736             SReal err = diff.norm();
01737             if (iter>3)
01738                 std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01739             SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01740             if (b[0] < -berr || b[0] > 1+berr
01741                 || b[1] < -berr || b[1] > 1+berr
01742                 || b[2] < -berr || b[2] > 1+berr)
01743                 break; // far from the cube
01744             if (err < 0.005f)
01745             { // we found the corresponding point, but is is only valid if inside the current cube
01746                 if (b[0] > 0.001f && b[0] < 0.999f
01747                     && b[1] > 0.001f && b[1] < 0.999f
01748                     && b[2] > 0.001f && b[2] < 0.999f)
01749                 {
01750                     DistanceGrid::Coord pinit = c1.initpos(b);
01751                     SReal d = grid1->interp(pinit);
01752                     if (d < margin)
01753                     {
01754                         DistanceGrid::Coord grad = grid1->grad(pinit); // note that there are some redundant computations between interp() and grad()
01755                         grad.normalize();
01756                         pinit -= grad*d;
01757                         grad = c1.deformDir(c1.baryCoords(pinit),grad);
01758                         grad.normalize();
01759                         
01760                         contacts->resize(contacts->size()+1);
01761                         DetectionOutput *detection = &*(contacts->end()-1);
01762                         
01763                         detection->point[0] = Vector3(pinit);
01764                         detection->point[1] = Vector3(p2);
01765                         detection->normal = Vector3(grad); // normal in global space from p1's surface
01766                         detection->value = d - d0;
01767                         detection->elem.first = e1;
01768                         detection->elem.second = e2;
01769                         detection->id = e2.getIndex()*3+2;
01770                         ++nc;
01771                     }
01772                 }
01773                 break;
01774             }
01775             err1 = err;
01776             SReal d = grid1->interp(c1.initpos(b));
01777             if (d*0.5f - err > margin)
01778                 break; // the point is too far from the object
01779             // we are solving for deform(b+db)-deform(b) = p1-deform(b)
01780             // deform(b+db) ~= deform(b) + M db  -> M db = p1-deform(b) -> db = M^-1 (p1-deform(b))
01781             b += c1.undeformDir( b, diff );
01782         }
01783         if (iter == 5)
01784         {
01785             if (b[0] > 0.001f && b[0] < 0.999f
01786                 && b[1] > 0.001f && b[1] < 0.999f
01787                 && b[2] > 0.001f && b[2] < 0.999f)
01788                 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;
01789         }
01790     }
01791     return nc;
01792 }
01793 
01794 bool DiscreteIntersection::testIntersection(Ray& /*e1*/, FFDDistanceGridCollisionElement& /*e2*/)
01795 {
01796     return true;
01797 }
01798 
01799 int DiscreteIntersection::computeIntersection(Ray& e2, FFDDistanceGridCollisionElement& e1, OutputVector* contacts)
01800 {
01801     Vector3 rayOrigin(e2.origin());
01802     Vector3 rayDirection(e2.direction());
01803     const double rayLength = e2.l();
01804 
01805     DistanceGrid* grid1 = e1.getGrid();
01806     FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
01807 
01808     // Center of the sphere
01809     const Vector3 center1 = c1.center;
01810     // Radius of the sphere
01811     const double radius1 = c1.radius;
01812 
01813     const Vector3 tmp = center1 - rayOrigin;
01814     double rayPos = tmp*rayDirection;
01815     const double dist2 = tmp.norm2() - (rayPos*rayPos);
01816     if (dist2 >= (radius1*radius1))
01817             return 0;
01818     
01819     double l0 = rayPos - sqrt(radius1*radius1 - dist2);
01820     double l1 = rayPos + sqrt(radius1*radius1 - dist2);
01821     if (l0 < 0) l0 = 0;
01822     if (l1 > rayLength) l1 = rayLength;
01823     if (l0 > l1) return 0; // outside of ray
01824     //const double dist = sqrt(dist2);
01825     //double epsilon = grid1->getCellWidth().norm()*0.1f;
01826     
01827     c1.updateFaces();
01828     DistanceGrid::Coord p1;
01829     const SReal cubesize = c1.invDP.norm();
01830     for(int i=0;i<100;i++)
01831     {
01832         rayPos = l0 + (l1-l0)*(i*0.01);
01833         p1 = rayOrigin + rayDirection*rayPos;
01834         // estimate the barycentric coordinates
01835         DistanceGrid::Coord b = c1.undeform0(p1);
01836         // refine the estimate until we are very close to the p2 or we are sure p2 cannot intersect with the object
01837         int iter;
01838         SReal err1 = 1000.0f;
01839         bool found = false;
01840         for(iter=0; iter<5; ++iter)
01841         {
01842             DistanceGrid::Coord pdeform = c1.deform(b);
01843             DistanceGrid::Coord diff = p1-pdeform;
01844             SReal err = diff.norm();
01845             //if (iter>3)
01846             //    std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
01847             SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
01848             if (b[0] < -berr || b[0] > 1+berr
01849                 || b[1] < -berr || b[1] > 1+berr
01850                 || b[2] < -berr || b[2] > 1+berr)
01851                 break; // far from the cube
01852             if (err < 0.001f)
01853             { // we found the corresponding point, but is is only valid if inside the current cube
01854                 if (b[0] > -0.1f && b[0] < 1.1f
01855                 && b[1] > -0.1f && b[1] < 1.1f
01856                 && b[2] > -0.1f && b[2] < 1.1f)
01857                 {
01858                     found = true;
01859                 }
01860                 break;
01861             }
01862             err1 = err;
01863             b += c1.undeformDir( b, diff );
01864         }
01865         if (found)
01866         {
01867             SReal d = grid1->interp(c1.initpos(b));
01868             if (d < 0)
01869             { // intersection found
01870                 
01871                 contacts->resize(contacts->size()+1);
01872                 DetectionOutput *detection = &*(contacts->end()-1);
01873                 
01874                 detection->point[0] = e2.origin() + e2.direction()*rayPos;
01875                 detection->point[1] = c1.initpos(b);
01876                 detection->normal = e2.direction(); // normal in global space from p1's surface
01877                 detection->value = d;
01878                 detection->elem.first = e2;
01879                 detection->elem.second = e1;
01880                 detection->id = e2.getIndex();
01881                 return 1;
01882             }
01883         }
01884         // else move along the ray
01885         //if (dot(Vector3(grid1->grad(c1.initpos(b))),rayDirection) < 0)
01886         //    rayPos += 0.5*d;
01887         //else
01888         //    rayPos -= 0.5*d;
01889     }
01890     return 0;
01891 }
01892 
01893 } // namespace collision
01894 
01895 } // namespace component
01896 
01897 } // namespace sofa
01898 

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