DistanceGridCollisionModel.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/component/collision/DistanceGridCollisionModel.h>
00026 #include <sofa/core/ObjectFactory.h>
00027 #include <sofa/component/collision/CubeModel.h>
00028 #include <fstream>
00029 #include <sofa/helper/system/gl.h>
00030 #include <sofa/helper/gl/template.h>
00031 #include <sofa/core/componentmodel/topology/BaseMeshTopology.h>
00032 //#ifdef SOFA_HAVE_FLOWVR
00033 #include <flowvr/render/mesh.h>
00034 //#endif
00035 namespace sofa
00036 {
00037 
00038 namespace component
00039 {
00040 
00041 namespace collision
00042 {
00043 
00044 SOFA_DECL_CLASS(DistanceGridCollisionModel)
00045 
00046 int RigidDistanceGridCollisionModelClass = core::RegisterObject("Grid-based distance field")
00047 .add< RigidDistanceGridCollisionModel >()
00048 .addAlias("DistanceGridCollisionModel")
00049 .addAlias("RigidDistanceGrid")
00050 .addAlias("DistanceGrid")
00051 ;
00052 
00053 int FFDDistanceGridCollisionModelClass = core::RegisterObject("Grid-based deformable distance field")
00054 .add< FFDDistanceGridCollisionModel >()
00055 .addAlias("FFDDistanceGrid")
00056 ;
00057 
00058 using namespace defaulttype;
00059 
00063 
00064 RigidDistanceGridCollisionModel::RigidDistanceGridCollisionModel()
00065 : modified(true)
00066 , filename( initData( &filename, "filename", "load distance grid from specified file"))
00067 , scale( initData( &scale, 1.0, "scale", "scaling factor for input file"))
00068 , box( initData( &box, "box", "Field bounding box defined by xmin,ymin,zmin, xmax,ymax,zmax") )
00069 , nx( initData( &nx, 64, "nx", "number of values on X axis") )
00070 , ny( initData( &ny, 64, "ny", "number of values on Y axis") )
00071 , nz( initData( &nz, 64, "nz", "number of values on Z axis") )
00072 , dumpfilename( initData( &dumpfilename, "dumpfilename","write distance grid to specified file"))
00073 , usePoints( initData( &usePoints, true, "usePoints", "use mesh vertices for collision detection"))
00074 {
00075     rigid = NULL;
00076 }
00077 
00078 RigidDistanceGridCollisionModel::~RigidDistanceGridCollisionModel() 
00079 {
00080     for (unsigned int i=0; i<elems.size(); i++)
00081     {
00082         if (elems[i].grid!=NULL) elems[i].grid->release();
00083         if (elems[i].prevGrid!=NULL) elems[i].prevGrid->release();
00084     }
00085 }
00086 
00087 void RigidDistanceGridCollisionModel::init()
00088 {
00089     std::cout << "> RigidDistanceGridCollisionModel::init()"<<std::endl;
00090     this->core::CollisionModel::init();
00091     rigid = dynamic_cast< core::componentmodel::behavior::MechanicalState<RigidTypes>* > (getContext()->getMechanicalState());
00092 
00093     DistanceGrid* grid = NULL;
00094     if (filename.getValue().empty())
00095     {
00096         if (elems.size()==0 || elems[0].grid==NULL)
00097             std::cerr << "ERROR: RigidDistanceGridCollisionModel requires an input filename.\n";
00098         // else the grid has already been set
00099         return;
00100     }
00101     std::cout << "RigidDistanceGridCollisionModel: creating "<<nx.getValue()<<"x"<<ny.getValue()<<"x"<<nz.getValue()<<" DistanceGrid from file "<<filename.getValue();
00102     if (scale.getValue()!=1.0) std::cout<<" scale="<<scale.getValue();
00103     if (box.getValue()[0][0]<box.getValue()[1][0]) std::cout<<" bbox=<"<<box.getValue()[0]<<">-<"<<box.getValue()[0]<<">";
00104     std::cout << std::endl;
00105     grid = DistanceGrid::loadShared(filename.getValue(), scale.getValue(), nx.getValue(),ny.getValue(),nz.getValue(),box.getValue()[0],box.getValue()[1]);
00106 
00107     resize(1);
00108     elems[0].grid = grid;
00109     if (grid && !dumpfilename.getValue().empty())
00110     {
00111         std::cout << "RigidDistanceGridCollisionModel: dump grid to "<<dumpfilename.getValue()<<std::endl;
00112         grid->save(dumpfilename.getValue());
00113     }
00114     std::cout << "< RigidDistanceGridCollisionModel::init()"<<std::endl;
00115 }
00116 
00117 void RigidDistanceGridCollisionModel::resize(int s)
00118 {
00119     this->core::CollisionModel::resize(s);
00120     elems.resize(s);
00121 }
00122 
00123 void RigidDistanceGridCollisionModel::setGrid(DistanceGrid* surf, int index)
00124 {
00125     if (elems[index].grid == surf) return;
00126     if (elems[index].grid!=NULL) elems[index].grid->release();
00127     elems[index].grid = surf->addRef();
00128     modified = true;
00129 }
00130 
00131 void RigidDistanceGridCollisionModel::setNewState(int index, double dt, DistanceGrid* grid, const Matrix3& rotation, const Vector3& translation)
00132 {
00133     grid->addRef();
00134     if (elems[index].prevGrid!=NULL)
00135         elems[index].prevGrid->release();
00136     elems[index].prevGrid = elems[index].grid;
00137     elems[index].grid = grid;
00138     elems[index].prevRotation = elems[index].rotation;
00139     elems[index].rotation = rotation;
00140     elems[index].prevTranslation = elems[index].translation;
00141     elems[index].translation = translation;
00142     if (!elems[index].isTransformed)
00143     {
00144         Matrix3 I; I.identity();
00145         if (!(rotation == I) || !(translation == Vector3()))
00146             elems[index].isTransformed = true;
00147     }
00148     elems[index].prevDt = dt;
00149     modified = true;
00150 }
00151 
00153 void RigidDistanceGridCollisionModel::computeBoundingTree(int maxDepth)
00154 {
00155     CubeModel* cubeModel = this->createPrevious<CubeModel>();
00156     
00157     if (!modified && !isMoving() && !cubeModel->empty()) return; // No need to recompute BBox if immobile
00158     
00159     updateGrid();
00160     
00161     cubeModel->resize(size);
00162     for (int i=0; i<size; i++)
00163     {
00164         //static_cast<DistanceGridCollisionElement*>(elems[i])->recalcBBox();
00165         Vector3 emin, emax;
00166         if (rigid)
00167         {
00168             const RigidTypes::Coord& xform = (*rigid->getX())[i];
00169             elems[i].translation = xform.getCenter();
00170             xform.getOrientation().toMatrix(elems[i].rotation);
00171             elems[i].isTransformed = true;
00172         }
00173         if (elems[i].isTransformed)
00174         {
00175             //std::cout << "Grid "<<i<<" transformation: <"<<elems[i].rotation<<"> x + <"<<elems[i].translation<<">"<<std::endl;
00176             Vector3 corner = elems[i].translation + elems[i].rotation * elems[i].grid->getBBCorner(0);
00177             emin = corner;
00178             emax = emin;
00179             for (int j=1; j<8; j++)
00180             {
00181                 corner = elems[i].translation + elems[i].rotation * elems[i].grid->getBBCorner(j);
00182                 for(int c=0; c<3; c++)
00183                     if (corner[c] < emin[c]) emin[c] = corner[c];
00184                     else if (corner[c] > emax[c]) emax[c] = corner[c];
00185             }
00186         }
00187         else
00188         {
00189             emin = elems[i].grid->getBBMin();
00190             emax = elems[i].grid->getBBMax();
00191         }
00192         cubeModel->setParentOf(i, emin, emax); // define the bounding box of the current element
00193         //std::cout << "Grid "<<i<<" within  <"<<emin<<">-<"<<emax<<">"<<std::endl;
00194     }
00195     cubeModel->computeBoundingTree(maxDepth);
00196     modified = false;
00197 }
00198 
00199 void RigidDistanceGridCollisionModel::updateGrid()
00200 {
00201 }
00202 
00203 void RigidDistanceGridCollisionModel::draw()
00204 {
00205     if (!isActive()) return;
00206     if (getContext()->getShowCollisionModels())
00207     {
00208         if (getContext()->getShowWireFrame())
00209             glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00210         glDisable(GL_LIGHTING);
00211     glColor4fv(getColor4f());
00212         glPointSize(3);
00213         for (unsigned int i=0;i<elems.size();i++)
00214         {
00215             draw(i);
00216         }
00217         glPointSize(1);
00218         if (getContext()->getShowWireFrame())
00219             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00220     }
00221     if (getPrevious()!=NULL)
00222         getPrevious()->draw();
00223 }
00224 
00225 void RigidDistanceGridCollisionModel::draw(int index)
00226 {
00227     if (elems[index].isTransformed)
00228     {
00229         glPushMatrix();
00230         // float m[16];
00231         // (*rigid->getX())[index].writeOpenGlMatrix( m );
00232         // glMultMatrixf(m);
00233         Matrix4 m;
00234         m.identity();
00235         m = elems[index].rotation;
00236         m.transpose();
00237         m[3] = Vector4(elems[index].translation,1.0);
00238 
00239         helper::gl::glMultMatrix(m.ptr());
00240     }
00241 
00242     DistanceGrid* grid = getGrid(index);
00243     DistanceGrid::Coord corners[8];
00244     for(unsigned int i=0; i<8; i++)
00245     corners[i] = grid->getCorner(i);
00246     //glEnable(GL_BLEND);
00247     //glDepthMask(0);
00248     if (!isSimulated())
00249     glColor4f(0.25f, 0.25f, 0.25f, 0.1f);
00250     else
00251     glColor4f(0.5f, 0.5f, 0.5f, 0.1f);
00252     glBegin(GL_LINES);
00253     {
00254     helper::gl::glVertexT(corners[0]); helper::gl::glVertexT(corners[4]);
00255     helper::gl::glVertexT(corners[1]); helper::gl::glVertexT(corners[5]);
00256     helper::gl::glVertexT(corners[2]); helper::gl::glVertexT(corners[6]);
00257     helper::gl::glVertexT(corners[3]); helper::gl::glVertexT(corners[7]);
00258     helper::gl::glVertexT(corners[0]); helper::gl::glVertexT(corners[2]);
00259     helper::gl::glVertexT(corners[1]); helper::gl::glVertexT(corners[3]);
00260     helper::gl::glVertexT(corners[4]); helper::gl::glVertexT(corners[6]);
00261     helper::gl::glVertexT(corners[5]); helper::gl::glVertexT(corners[7]);
00262     helper::gl::glVertexT(corners[0]); helper::gl::glVertexT(corners[1]);
00263     helper::gl::glVertexT(corners[2]); helper::gl::glVertexT(corners[3]);
00264     helper::gl::glVertexT(corners[4]); helper::gl::glVertexT(corners[5]);
00265     helper::gl::glVertexT(corners[6]); helper::gl::glVertexT(corners[7]);
00266     }
00267     glEnd();
00268     glDisable(GL_BLEND);
00269     glDepthMask(1);
00270     for(unsigned int i=0; i<8; i++)
00271     corners[i] = grid->getBBCorner(i);
00272     //glEnable(GL_BLEND);
00273     //glDepthMask(0);
00274 
00275     if (!isSimulated())
00276     glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
00277     else
00278     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00279     glBegin(GL_LINES);
00280     {
00281     helper::gl::glVertexT(corners[0]); helper::gl::glVertexT(corners[4]);
00282     helper::gl::glVertexT(corners[1]); helper::gl::glVertexT(corners[5]);
00283     helper::gl::glVertexT(corners[2]); helper::gl::glVertexT(corners[6]);
00284     helper::gl::glVertexT(corners[3]); helper::gl::glVertexT(corners[7]);
00285     helper::gl::glVertexT(corners[0]); helper::gl::glVertexT(corners[2]);
00286     helper::gl::glVertexT(corners[1]); helper::gl::glVertexT(corners[3]);
00287     helper::gl::glVertexT(corners[4]); helper::gl::glVertexT(corners[6]);
00288     helper::gl::glVertexT(corners[5]); helper::gl::glVertexT(corners[7]);
00289     helper::gl::glVertexT(corners[0]); helper::gl::glVertexT(corners[1]);
00290     helper::gl::glVertexT(corners[2]); helper::gl::glVertexT(corners[3]);
00291     helper::gl::glVertexT(corners[4]); helper::gl::glVertexT(corners[5]);
00292     helper::gl::glVertexT(corners[6]); helper::gl::glVertexT(corners[7]);
00293     }
00294     glEnd();
00295 
00296     const SReal mindist = (SReal)( -(grid->getPMax()-grid->getPMin()).norm()*0.1);
00297     const SReal maxdist = (SReal)(  (grid->getPMax()-grid->getPMin()).norm()*0.025);
00298 
00299     if (grid->meshPts.empty())
00300     {
00301         glBegin(GL_POINTS);
00302         {
00303             for (int z=0, ind=0; z<grid->getNz(); z++)
00304             for (int y=0; y<grid->getNy(); y++)
00305             for (int x=0; x<grid->getNx(); x++, ind++)
00306             {
00307                 DistanceGrid::Coord p = grid->coord(x,y,z);
00308                 SReal d = (*grid)[ind];
00309                 if (d < mindist || d > maxdist) continue;
00310                 d /= maxdist;
00311                 if (d<0)
00312                     glColor3d(1+d*0.25, 0, 1+d);
00313                 else
00314                     glColor3d(0, 1-d*0.25, 1-d);
00315         helper::gl::glVertexT(p);
00316             }
00317         }
00318         glEnd();
00319     }
00320     else
00321     {
00322         glColor3d(1, 1 ,1);
00323         glBegin(GL_POINTS);
00324         for (unsigned int i=0; i<grid->meshPts.size();i++)
00325         {
00326             DistanceGrid::Coord p = grid->meshPts[i];
00327         helper::gl::glVertexT(p);
00328         }
00329         glEnd();
00330         glBegin(GL_LINES);
00331         for (unsigned int i=0; i<grid->meshPts.size();i++)
00332         {
00333             DistanceGrid::Coord p = grid->meshPts[i];
00334             glColor3d(1, 1 ,1);
00335             DistanceGrid::Coord grad = grid->grad(p);
00336             grad.normalize();
00337             for (int j = -2; j <= 2; j++)
00338             {
00339                 DistanceGrid::Coord p2 = p + grad * (j*maxdist/2);
00340                 SReal d = grid->eval(p2);
00341                 //if (rabs(d) > maxdist) continue;
00342                 d /= maxdist;
00343                 if (d<0)
00344                     glColor3d(1+d*0.25, 0, 1+d);
00345                 else
00346           glColor3d(0, 1-d*0.25, 1-d);
00347         helper::gl::glVertexT(p2);
00348                 if (j>-2 && j < 2)
00349           helper::gl::glVertexT(p2);
00350             }
00351         }
00352         glEnd();
00353     }
00354     if (elems[index].isTransformed)
00355     {
00356         glPopMatrix();
00357     }
00358 }
00359 
00363 
00364 FFDDistanceGridCollisionModel::FFDDistanceGridCollisionModel()
00365 : filename( initData( &filename, "filename", "load distance grid from specified file"))
00366 , scale( initData( &scale, 1.0, "scale", "scaling factor for input file"))
00367 , box( initData( &box, "box", "Field bounding box defined by xmin,ymin,zmin, xmax,ymax,zmax") )
00368 , nx( initData( &nx, 64, "nx", "number of values on X axis") )
00369 , ny( initData( &ny, 64, "ny", "number of values on Y axis") )
00370 , nz( initData( &nz, 64, "nz", "number of values on Z axis") )
00371 , dumpfilename( initData( &dumpfilename, "dumpfilename","write distance grid to specified file"))
00372 , usePoints( initData( &usePoints, true, "usePoints", "use mesh vertices for collision detection"))
00373 {
00374     ffd = NULL;
00375         ffdGrid = NULL;
00376 }
00377 
00378 FFDDistanceGridCollisionModel::~FFDDistanceGridCollisionModel() 
00379 {
00380     //for (unsigned int i=0; i<elems.size(); i++)
00381     //    if (elems[i].grid!=NULL) elems[i].grid->release();
00382     if (elems.size()>0 && elems[0].grid!=NULL) elems[0].grid->release();
00383 }
00384 
00385 void FFDDistanceGridCollisionModel::init()
00386 {
00387     std::cout << "> FFDDistanceGridCollisionModel::init()"<<std::endl;
00388     this->core::CollisionModel::init();
00389     ffd = dynamic_cast< core::componentmodel::behavior::MechanicalState<Vec3Types>* > (getContext()->getMechanicalState());
00390     ffdGrid = dynamic_cast< topology::RegularGridTopology* > (getContext()->getMeshTopology());
00391     if (!ffd || !ffdGrid)
00392     {
00393         std::cerr << "ERROR: FFDDistanceGridCollisionModel requires a Vec3-based deformable model with associated RegularGridTopology.\n";
00394         return;
00395     }
00396 
00397     DistanceGrid* grid = NULL;
00398     if (filename.getValue().empty())
00399     {
00400         std::cerr << "ERROR: FFDDistanceGridCollisionModel requires an input filename.\n";
00401         return;
00402     }
00403     std::cout << "FFDDistanceGridCollisionModel: creating "<<nx.getValue()<<"x"<<ny.getValue()<<"x"<<nz.getValue()<<" DistanceGrid from file "<<filename.getValue();
00404     if (scale.getValue()!=1.0) std::cout<<" scale="<<scale.getValue();
00405     if (box.getValue()[0][0]<box.getValue()[1][0]) std::cout<<" bbox=<"<<box.getValue()[0]<<">-<"<<box.getValue()[0]<<">";
00406     std::cout << std::endl;
00407     grid = DistanceGrid::loadShared(filename.getValue(), scale.getValue(), nx.getValue(),ny.getValue(),nz.getValue(),box.getValue()[0],box.getValue()[1]);
00408     if (grid && !dumpfilename.getValue().empty())
00409     {
00410         std::cout << "FFDDistanceGridCollisionModel: dump grid to "<<dumpfilename.getValue()<<std::endl;
00411         grid->save(dumpfilename.getValue());
00412     }
00414     int nbp = grid->meshPts.size();
00415 #ifdef SOFA_NEW_HEXA
00416     elems.resize(ffdGrid->getNbHexas());
00417     std::cout << "FFDDistanceGridCollisionModel: placing "<<nbp<<" points in "<<ffdGrid->getNbHexas()<<" cubes."<<std::endl;
00418 #else
00419     elems.resize(ffdGrid->getNbHexas());
00420     std::cout << "FFDDistanceGridCollisionModel: placing "<<nbp<<" points in "<<ffdGrid->getNbCubes()<<" cubes."<<std::endl;
00421 #endif
00422     for (int i=0; i<nbp; i++)
00423     {
00424         Vec3Types::Coord p0 = grid->meshPts[i];
00425         Vector3 bary;
00426         int elem = ffdGrid->findCube(p0,bary[0],bary[1],bary[2]);
00427         if (elem == -1) continue;
00428         if ((unsigned)elem >= elems.size())
00429         {
00430             std::cerr << "ERROR (FFDDistanceGridCollisionModel): point "<<i<<" "<<p0<<" in invalid cube "<<elem<<std::endl;
00431         }
00432         else
00433         {
00434             DeformedCube::Point p;
00435             p.index = i;
00436             p.bary = bary;
00437             elems[elem].points.push_back(p);
00438         }
00439     }
00441 
00442 #ifdef SOFA_NEW_HEXA
00443     std::cout << "FFDDistanceGridCollisionModel: initializing "<<ffdGrid->getNbHexas()<<" cubes."<<std::endl;
00444     int c=0;
00445     for (int e=0; e<ffdGrid->getNbHexas(); e++)
00446 #else
00447     std::cout << "FFDDistanceGridCollisionModel: initializing "<<ffdGrid->getNbCubes()<<" cubes."<<std::endl;
00448     int c=0;
00449     for (int e=0; e<ffdGrid->getNbCubes(); e++)
00450 #endif
00451     {
00452         if (ffdGrid->isCubeActive( e ))
00453         {
00454             if (c != e)
00455                 elems[c].points.swap(elems[e].points); // move the list of points to the new 
00456             elems[c].elem = e;
00457 #ifdef SOFA_NEW_HEXA
00458             core::componentmodel::topology::BaseMeshTopology::Hexa cube = ffdGrid->getHexaCopy(e);
00459 #else
00460             core::componentmodel::topology::BaseMeshTopology::Cube cube = ffdGrid->getCubeCopy(e);
00461 #endif
00462             elems[c].initP0 = ffdGrid->getPoint(cube[0]);
00463             elems[c].initDP = ffdGrid->getPoint(cube[7])-elems[c].initP0;
00464             elems[c].invDP[0] = 1/elems[c].initDP[0];
00465             elems[c].invDP[1] = 1/elems[c].initDP[1];
00466             elems[c].invDP[2] = 1/elems[c].initDP[2];
00467             elems[c].grid = grid;
00468             ++c;
00469         }
00470     }
00471     resize(c);
00472     std::cout << "FFDDistanceGridCollisionModel: "<<c<<" active cubes."<<std::endl;
00473     std::cout << "< FFDDistanceGridCollisionModel::init()"<<std::endl;
00474 }
00475 
00476 void FFDDistanceGridCollisionModel::resize(int s)
00477 {
00478     this->core::CollisionModel::resize(s);
00479     elems.resize(s);
00480 }
00481 
00482 void FFDDistanceGridCollisionModel::setGrid(DistanceGrid* surf, int index)
00483 {
00484     elems[index].grid = surf;
00485 }
00486 
00488 void FFDDistanceGridCollisionModel::computeBoundingTree(int maxDepth)
00489 {
00490     CubeModel* cubeModel = this->createPrevious<CubeModel>();
00491     
00492     if (!isMoving() && !cubeModel->empty()) return; // No need to recompute BBox if immobile
00493     
00494     updateGrid();
00495     
00496     cubeModel->resize(size);
00497     for (int i=0; i<size; i++)
00498     {
00499         //static_cast<DistanceGridCollisionElement*>(elems[i])->recalcBBox();
00500         Vector3 emin, emax;
00501         const DeformedCube& cube = getDeformCube(i);
00502         {
00503             emin = cube.corners[0];
00504             emax = emin;
00505             for (int j=1; j<8; j++)
00506             {
00507                 Vector3 corner = cube.corners[j];
00508                 for(int c=0; c<3; c++)
00509                     if (corner[c] < emin[c]) emin[c] = corner[c];
00510                     else if (corner[c] > emax[c]) emax[c] = corner[c];
00511             }
00512         }
00513         cubeModel->setParentOf(i, emin, emax); // define the bounding box of the current element
00514     }
00515     cubeModel->computeBoundingTree(maxDepth);
00516 }
00517 
00518 void FFDDistanceGridCollisionModel::updateGrid()
00519 {
00520     for (int index=0; index<size; index++)
00521     {
00522         DeformedCube& cube = getDeformCube( index );
00523 #ifdef SOFA_NEW_HEXA
00524         const sofa::helper::vector<core::componentmodel::topology::BaseMeshTopology::Hexa>& cubeCorners = ffdGrid->getHexas();
00525 #else
00526         const sofa::helper::vector<core::componentmodel::topology::BaseMeshTopology::Cube>& cubeCorners = ffdGrid->getCubes();
00527 #endif
00528         const Vec3Types::VecCoord& x = *ffd->getX();
00529         {
00530             int e = cube.elem;
00531             DistanceGrid::Coord center;
00532             for (int j=0; j<8; j++)
00533             {
00534                 cube.corners[j] = x[cubeCorners[e][j]];
00535                 center += cube.corners[j];
00536             }
00537             cube.center = center * 0.125f;
00538             SReal radius2 = 0.0f;
00539             for (int j=0; j<8; j++)
00540             {
00541                 SReal r2 = (cube.corners[j] - cube.center).norm2();
00542                 if (r2 > radius2) radius2 = r2;
00543             }
00544             cube.radius = rsqrt(radius2);
00545             cube.updateDeform();
00546             cube.pointsUpdated = false;
00547             cube.facesUpdated = false;
00548         }
00549     }
00550 }
00551 
00553 void FFDDistanceGridCollisionModel::DeformedCube::updateDeform()
00554 {
00555     Dx = corners[C100]-corners[C000];   // Dx = -C000+C100
00556     Dy = corners[C010]-corners[C000];   // Dy = -C000+C010
00557     Dz = corners[C001]-corners[C000];   // Dx = -C000+C001
00558     Dxy = corners[C110]-corners[C010]-Dx;  // Dxy = C000-C100-C010+C110 = C110-C010-Dx
00559     Dxz = corners[C101]-corners[C001]-Dx;  // Dxz = C000-C100-C001+C101 = C101-C001-Dx
00560     Dyz = corners[C011]-corners[C001]-Dy;  // Dyz = C000-C010-C001+C011 = C011-C001-Dy
00561     Dxyz = corners[C111]-corners[C101]-corners[C011]+corners[C001]-Dxy; // Dxyz = - C000 + C100 + C010 - C110 + C001 - C101 - C011 + C111 = C001 - C101 - C011 + C111 - Dxy
00562 }
00563 
00565 void FFDDistanceGridCollisionModel::DeformedCube::updatePoints()
00566 {
00567     if (!pointsUpdated)
00568     {
00569         deformedPoints.resize(points.size());
00570         for (unsigned int i=0; i<points.size(); i++)
00571         {
00572             deformedPoints[i] = deform(points[i].bary);
00573         }
00574         pointsUpdated = true;
00575     }
00576 }
00577 
00579 void FFDDistanceGridCollisionModel::DeformedCube::updateFaces()
00580 {
00581     if (!facesUpdated)
00582     {
00583         faces[FX0] = computePlane(C000,C010,C001,C011); faces[FX1] = computePlane(C100,C101,C110,C111);
00584         faces[FY0] = computePlane(C000,C001,C100,C101); faces[FY1] = computePlane(C010,C110,C011,C111);
00585         faces[FZ0] = computePlane(C000,C100,C010,C110); faces[FZ1] = computePlane(C001,C011,C101,C111);
00586         facesUpdated = true;
00587     }
00588 }
00589 
00590 FFDDistanceGridCollisionModel::DeformedCube::Plane FFDDistanceGridCollisionModel::DeformedCube::computePlane(int c00, int c10, int c01, int c11)
00591 {
00592     GCoord C4 = (corners[c00]+corners[c10]+corners[c01]+corners[c11]); //*0.25f;
00593     GCoord N = (corners[c11]-corners[c00]).cross(corners[c01]-corners[c10]);
00594     N.normalize();
00595     return Plane(N,N*C4*(-0.25f));
00596 }
00597 
00598 void FFDDistanceGridCollisionModel::draw()
00599 {
00600     if (!isActive()) return;
00601     if (getContext()->getShowCollisionModels())
00602     {
00603         if (getContext()->getShowWireFrame())
00604             glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00605         glDisable(GL_LIGHTING);
00606     glColor4fv(getColor4f());
00607         for (unsigned int i=0;i<elems.size();i++)
00608         {
00609             draw(i);
00610         }
00611         if (getContext()->getShowWireFrame())
00612             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00613     }
00614     if (getPrevious()!=NULL)
00615         getPrevious()->draw();
00616 }
00617 
00618 void FFDDistanceGridCollisionModel::draw(int index)
00619 {
00620     //DistanceGrid* grid = getGrid(index);
00621     DeformedCube& cube = getDeformCube( index );
00622     //glEnable(GL_BLEND);
00623     //glDepthMask(0);
00624     float cscale;
00625     if (!isSimulated())
00626         cscale = 0.5f;
00627     else
00628         cscale = 1.0f;
00629     if (cube.pointsUpdated && cube.facesUpdated)
00630         glColor4f(1.0f*cscale, 0.0f*cscale, 0.0f*cscale, 1.0f);
00631     else if (cube.pointsUpdated)
00632         glColor4f(1.0f*cscale, 0.5f*cscale, 0.0f*cscale, 1.0f);
00633     else if (cube.facesUpdated)
00634         glColor4f(0.5f*cscale, 1.0f*cscale, 0.0f*cscale, 1.0f);
00635     else
00636         glColor4f(0.0f*cscale, 1.0f*cscale, 0.5f*cscale, 1.0f);
00637     glBegin(GL_LINES);
00638     {
00639     helper::gl::glVertexT(cube.corners[0]); helper::gl::glVertexT(cube.corners[4]);
00640     helper::gl::glVertexT(cube.corners[1]); helper::gl::glVertexT(cube.corners[5]);
00641     helper::gl::glVertexT(cube.corners[2]); helper::gl::glVertexT(cube.corners[6]);
00642     helper::gl::glVertexT(cube.corners[3]); helper::gl::glVertexT(cube.corners[7]);
00643     helper::gl::glVertexT(cube.corners[0]); helper::gl::glVertexT(cube.corners[2]);
00644     helper::gl::glVertexT(cube.corners[1]); helper::gl::glVertexT(cube.corners[3]);
00645     helper::gl::glVertexT(cube.corners[4]); helper::gl::glVertexT(cube.corners[6]);
00646     helper::gl::glVertexT(cube.corners[5]); helper::gl::glVertexT(cube.corners[7]);
00647     helper::gl::glVertexT(cube.corners[0]); helper::gl::glVertexT(cube.corners[1]);
00648     helper::gl::glVertexT(cube.corners[2]); helper::gl::glVertexT(cube.corners[3]);
00649     helper::gl::glVertexT(cube.corners[4]); helper::gl::glVertexT(cube.corners[5]);
00650     helper::gl::glVertexT(cube.corners[6]); helper::gl::glVertexT(cube.corners[7]);
00651     }
00652     glEnd();
00653     glLineWidth(2);
00654     glPointSize(5);
00655     {
00656         for (int j=0; j<3; j++)
00657         {
00658             glBegin(GL_LINE_STRIP);
00659             for (int r=0;r<=16;r++)
00660             {
00661                 SReal c = cube.radius*(SReal)cos(r*M_PI/8);
00662                 SReal s = cube.radius*(SReal)sin(r*M_PI/8);
00663                 sofa::defaulttype::Vec<3, SReal> p = cube.center;
00664                 p[j] += c;
00665                 p[(j+1)%3] += s;
00666                 helper::gl::glVertexT(p);
00667             }
00668             glEnd();
00669         }
00670         glBegin(GL_POINTS);
00671         {
00672             helper::gl::glVertexT(cube.center);
00673         
00674         }
00675         glEnd();
00676     }
00677     glLineWidth(1);
00678     if (cube.pointsUpdated)
00679     {
00680         glPointSize(2);
00681         glColor4f(1.0f, 0.5f, 0.5f, 1.0f);
00682         glBegin(GL_POINTS);
00683         for (unsigned int j=0; j<cube.deformedPoints.size(); j++)
00684       helper::gl::glVertexT(cube.deformedPoints[j]);
00685         glEnd();
00686     }
00687     glPointSize(1);
00688 }
00689 
00693 
00694 DistanceGrid::DistanceGrid(int nx, int ny, int nz, Coord pmin, Coord pmax)
00695 : meshPts(new defaulttype::DefaultAllocator<Coord>), nbRef(1), dists(nx*ny*nz, new defaulttype::DefaultAllocator<SReal>), nx(nx), ny(ny), nz(nz), nxny(nx*ny), nxnynz(nx*ny*nz)
00696 , pmin(pmin), pmax(pmax)
00697 , cellWidth   ((pmax[0]-pmin[0])/(nx-1), (pmax[1]-pmin[1])/(ny-1),(pmax[2]-pmin[2])/(nz-1))
00698 , invCellWidth((nx-1)/(pmax[0]-pmin[0]), (ny-1)/(pmax[1]-pmin[1]),(nz-1)/(pmax[2]-pmin[2]))
00699 , cubeDim(0)
00700 {
00701 }
00702 
00703 DistanceGrid::DistanceGrid(int nx, int ny, int nz, Coord pmin, Coord pmax, defaulttype::ExtVectorAllocator<SReal>* alloc)
00704 : meshPts(new defaulttype::DefaultAllocator<Coord>), nbRef(1), dists(nx*ny*nz, alloc), nx(nx), ny(ny), nz(nz), nxny(nx*ny), nxnynz(nx*ny*nz)
00705 , pmin(pmin), pmax(pmax)
00706 , cellWidth   ((pmax[0]-pmin[0])/(nx-1), (pmax[1]-pmin[1])/(ny-1),(pmax[2]-pmin[2])/(nz-1))
00707 , invCellWidth((nx-1)/(pmax[0]-pmin[0]), (ny-1)/(pmax[1]-pmin[1]),(nz-1)/(pmax[2]-pmin[2]))
00708 , cubeDim(0)
00709 {
00710 }
00711 
00712 DistanceGrid::~DistanceGrid()
00713 {
00714     std::map<DistanceGridParams, DistanceGrid*>& shared = getShared();
00715     std::map<DistanceGridParams, DistanceGrid*>::iterator it = shared.begin();
00716     while (it != shared.end() && it->second != this) ++it;
00717     if (it != shared.end())
00718         shared.erase(it); // remove this grid from the list of already loaded grids
00719 }
00720 
00722 DistanceGrid* DistanceGrid::addRef()
00723 {
00724     ++nbRef;
00725     return this;
00726 }
00727 
00729 bool DistanceGrid::release()
00730 {
00731     if (--nbRef != 0)
00732         return false;
00733     delete this;
00734     return true;
00735 }
00736 
00737 DistanceGrid* DistanceGrid::load(const std::string& filename, double scale, int nx, int ny, int nz, Coord pmin, Coord pmax)
00738 {
00739     if (filename == "#cube")
00740     {
00741         float dim = (float)scale;
00742         int np = 5;
00743         Coord bbmin(-dim, -dim, -dim), bbmax(dim,dim,dim);
00744         std::cout << "bbox = <"<<bbmin<<">-<"<<bbmax<<">"<<std::endl;
00745         if (pmin[0]<=pmax[0])
00746         {
00747             pmin = bbmin;
00748             pmax = bbmax;
00749             Coord margin = (bbmax-bbmin)*0.1;
00750             pmin -= margin;
00751             pmax += margin;
00752         }
00753         else
00754         {
00755             for (int c=0; c<3; c++)
00756             {
00757                 if (bbmin[c] < pmin[c]) pmin[c] = bbmin[c];
00758                 if (bbmax[c] > pmax[c]) pmax[c] = bbmax[c];
00759             }
00760         }
00761         std::cout << "Creating cube distance grid in <"<<pmin<<">-<"<<pmax<<">"<<std::endl;
00762         DistanceGrid* grid = new DistanceGrid(nx, ny, nz, pmin, pmax);
00763         grid->calcCubeDistance(dim, np);
00764         std::cout << "Distance grid creation DONE."<<std::endl;
00765         return grid;
00766     }
00767     else if (filename.length()>4 && filename.substr(filename.length()-4) == ".raw")
00768     {
00769         DistanceGrid* grid = new DistanceGrid(nx, ny, nz, pmin, pmax);
00770         std::ifstream in(filename.c_str(), std::ios::in | std::ios::binary);
00771         in.read((char*)&(grid->dists[0]), grid->nxnynz*sizeof(SReal));
00772         if (scale != 1.0)
00773         {
00774             for (int i=0; i< grid->nxnynz; i++)
00775                 grid->dists[i] *= (float)scale;
00776         }
00777         grid->computeBBox();
00778         return grid;
00779     }
00780 //#ifdef SOFA_HAVE_FLOWVR
00781     else if (filename.length()>6 && filename.substr(filename.length()-6) == ".fmesh")
00782     {
00783         flowvr::render::Mesh mesh;
00784         if (!mesh.load(filename.c_str()))
00785         {
00786             std::cerr << "ERROR loading FlowVR mesh file "<<filename<<std::endl;
00787             return NULL;
00788         }
00789         //std::cout << "bbox = "<<mesh.bb<<std::endl;
00790         
00791         if (!mesh.getAttrib(flowvr::render::Mesh::MESH_DISTMAP))
00792         {
00793             std::cerr << "ERROR: FlowVR mesh "<<filename<<" does not contain distance information. Please use flowvr-distmap."<<std::endl;
00794             return NULL;
00795         }
00796         nx = mesh.distmap->nx;
00797         ny = mesh.distmap->ny;
00798         nz = mesh.distmap->nz;
00799         ftl::Vec3f fpmin = ftl::transform(mesh.distmap->mat,ftl::Vec3f(0,0,0))*(float)scale;
00800     ftl::Vec3f fpmax = ftl::transform(mesh.distmap->mat,ftl::Vec3f((float)(nx-1),(float)(ny-1),(float)(nz-1)))*(float)scale;
00801         pmin = Coord(fpmin.ptr());
00802         pmax = Coord(fpmax.ptr());
00803         std::cout << "Copying "<<nx<<"x"<<ny<<"x"<<nz<<" distance grid in <"<<pmin<<">-<"<<pmax<<">"<<std::endl;
00804         DistanceGrid* grid = new DistanceGrid(nx, ny, nz, pmin, pmax);
00805         for (int i=0; i< grid->nxnynz; i++)
00806             grid->dists[i] = mesh.distmap->data[i]*scale;
00807 
00808         if (mesh.getAttrib(flowvr::render::Mesh::MESH_POINTS_GROUP))
00809         {
00810             int nbpos = 0;
00811             for (int i=0;i<mesh.nbg();i++)
00812             {
00813                 if (mesh.getGP0(i) >= 0)
00814                     ++nbpos;
00815             }
00816             std::cout << "Copying "<<nbpos<<" mesh vertices."<<std::endl;
00817             grid->meshPts.resize(nbpos);
00818             int p = 0;
00819             for (int i=0;i<mesh.nbg();i++)
00820             {
00821                 int p0 = mesh.getGP0(i);
00822                 if (p0 >= 0)
00823                     grid->meshPts[p++] = Coord(mesh.getPP(p0).ptr())*scale;
00824             }
00825         }
00826         else
00827         {
00828             int nbpos = mesh.nbp();
00829             std::cout << "Copying "<<nbpos<<" mesh vertices."<<std::endl;
00830             grid->meshPts.resize(nbpos);
00831             for (int i=0;i<nbpos;i++)
00832                 grid->meshPts[i] = Coord(mesh.getPP(i).ptr())*scale;
00833         }
00834         grid->computeBBox();
00835         std::cout << "Distance grid creation DONE."<<std::endl;
00836         return grid;
00837     }
00838 //#endif
00839     else if (filename.length()>4 && filename.substr(filename.length()-4) == ".obj")
00840     {
00841         sofa::helper::io::Mesh* mesh = sofa::helper::io::Mesh::Create(filename);
00842         const sofa::helper::vector<Vector3> & vertices = mesh->getVertices();
00843 
00844         std::cout << "Computing bbox."<<std::endl;
00845         Coord bbmin, bbmax;
00846         if (!vertices.empty())
00847         {
00848             bbmin = vertices[0];
00849             bbmax = bbmin;
00850             for(unsigned int i=1;i<vertices.size();i++)
00851             {
00852                 for (int c=0; c<3; c++)
00853                     if (vertices[i][c] < bbmin[c]) bbmin[c] = (SReal)vertices[i][c];
00854                     else if (vertices[i][c] > bbmax[c]) bbmax[c] = (SReal)vertices[i][c];
00855             }
00856             bbmin *= scale;
00857             bbmax *= scale;
00858         }
00859         std::cout << "bbox = <"<<bbmin<<">-<"<<bbmax<<">"<<std::endl;
00860 
00861         if (pmin[0]<=pmax[0])
00862         {
00863             pmin = bbmin;
00864             pmax = bbmax;
00865             Coord margin = (bbmax-bbmin)*0.1;
00866             pmin -= margin;
00867             pmax += margin;
00868         }
00869         else if (!vertices.empty())
00870         {
00871             for (int c=0; c<3; c++)
00872             {
00873                 if (bbmin[c] < pmin[c]) pmin[c] = bbmin[c];
00874                 if (bbmax[c] > pmax[c]) pmax[c] = bbmax[c];
00875             }
00876         }
00877         std::cout << "Creating distance grid in <"<<pmin<<">-<"<<pmax<<">"<<std::endl;
00878         DistanceGrid* grid = new DistanceGrid(nx, ny, nz, pmin, pmax);
00879         std::cout << "Copying "<<vertices.size()<<" mesh vertices."<<std::endl;
00880         grid->meshPts.resize(vertices.size());
00881         for(unsigned int i=0;i<vertices.size();i++)
00882             grid->meshPts[i] = vertices[i]*scale;
00883         std::cout << "Computing distance field."<<std::endl;
00884         grid->calcDistance(mesh, scale);
00885         grid->computeBBox();
00886         std::cout << "Distance grid creation DONE."<<std::endl;
00887         delete mesh;
00888         return grid;
00889     }
00890     else
00891     {
00892         std::cerr << "Unknown extension: "<<filename<<std::endl;
00893         return NULL;
00894     }
00895 }
00896 
00897 bool DistanceGrid::save(const std::string& filename)
00898 {
00900     if (filename.length()>4 && filename.substr(filename.length()-4) == ".raw")
00901     {
00902     std::ofstream out(filename.c_str(), std::ios::out | std::ios::binary);
00903     out.write((char*)&(dists[0]), nxnynz*sizeof(SReal));
00904     }
00905     else
00906     {
00907     std::cerr << " DistanceGrid::save(): Unsupported extension: "<<filename<<std::endl;
00908     return false;
00909     }
00910     return true;
00911 }
00912 
00913 
00914 template<int U, int V>
00915 bool pointInTriangle(const DistanceGrid::Coord& p, const DistanceGrid::Coord& p0, const DistanceGrid::Coord& p1, const DistanceGrid::Coord& p2)
00916 {
00917     SReal u0 = p [U] - p0[U], v0 = p [V] - p0[V];
00918     SReal u1 = p1[U] - p0[U], v1 = p1[V] - p0[V];
00919     SReal u2 = p2[U] - p0[U], v2 = p2[V] - p0[V];
00920     SReal alpha, beta;
00921     //return true;
00922     if (u1 == 0)
00923     {
00924         beta = u0/u2;
00925         if ( beta < 0 || beta > 1 ) return false;
00926     alpha = (v0 - beta*v2)/v1;
00927     if ( alpha < 0 || (alpha+beta) > 1 ) return false;
00928     }
00929     else
00930     {
00931         beta = (v0*u1 - u0*v1)/(v2*u1 - u2*v1);
00932         if ( beta < 0 || beta > 1 ) return false;
00933     alpha = (u0 - beta*u2)/u1;
00934     if ( alpha < 0 || (alpha+beta) > 1 ) return false;
00935     }
00936     return true;
00937 }
00938 
00939 void DistanceGrid::computeBBox()
00940 {
00941     if (!meshPts.empty())
00942     {
00943         bbmin = meshPts[0];
00944         bbmax = bbmin;
00945         for(unsigned int i=1;i<meshPts.size();i++)
00946         {
00947             for (int c=0; c<3; c++)
00948                 if (meshPts[i][c] < bbmin[c]) bbmin[c] = (SReal)meshPts[i][c];
00949                 else if (meshPts[i][c] > bbmax[c]) bbmax[c] = (SReal)meshPts[i][c];
00950         }
00951     }
00952     else
00953     {
00954         bbmin = pmin;
00955         bbmax = pmax;
00957     }
00958 }
00959 
00960 
00963 void DistanceGrid::calcCubeDistance(SReal dim, int np)
00964 {
00965     cubeDim = dim;
00966     if (np > 1)
00967     {
00968         int nbp = np*np*np - (np-2)*(np-2)*(np-2);
00969         //std::cout << "Copying "<<nbp<<" cube vertices."<<std::endl;
00970         meshPts.resize(nbp);
00971         
00972         for (int i=0,z=0; z<np; z++)
00973         for (int y=0; y<np; y++)
00974         for (int x=0; x<np; x++)
00975             if (z==0 || z==np-1 || y==0 || y==np-1 || x==0 || x==np-1)
00976                 meshPts[i++] = Coord(x*dim*2/(np-1) - dim, y*dim*2/(np-1) - dim, z*dim*2/(np-1) - dim);
00977     }
00978 
00979     //std::cout << "Computing distance field."<<std::endl;
00980 
00981     SReal dim2 = dim; //*0.75f; // add some 'roundness' to the cubes corner
00982 
00983     for (int i=0,z=0; z<nz; z++)
00984     for (int y=0; y<ny; y++)
00985     for (int x=0; x<nx; x++,i++)
00986     {
00987         Coord p = coord(x,y,z);
00988         Coord s = p;
00989         bool out = false;
00990         for (int c=0;c<3;c++)
00991         {
00992                  if (s[c] < -dim2) { s[c] = -dim2; out = true; }
00993             else if (s[c] >  dim2) { s[c] =  dim2; out = true; }
00994         }
00995         SReal d;
00996         if (out)
00997             d = (p - s).norm();
00998         else
00999             d = rmax(rmax(rabs(s[0]),rabs(s[1])),rabs(s[2])) - dim2;
01000         dists[i] = d - (dim-dim2);
01001     }
01002     //computeBBox();
01003     bbmin = Coord(-dim,-dim,-dim);
01004     bbmax = Coord( dim, dim, dim);
01005 }
01006 
01008 void DistanceGrid::calcDistance(sofa::helper::io::Mesh* mesh, double scale)
01009 {
01010     fmm_status.resize(nxnynz);
01011     fmm_heap.resize(nxnynz);
01012     fmm_heap_size = 0;
01013     std::cout << "FMM: Init."<<std::endl;
01014 
01015     std::fill(fmm_status.begin(), fmm_status.end(), FMM_FAR);
01016     std::fill(dists.begin(), dists.end(), maxDist());
01017 
01018     const sofa::helper::vector<Vector3> & vertices = mesh->getVertices();
01019     const sofa::helper::vector<sofa::helper::vector<sofa::helper::vector<int> > > & facets = mesh->getFacets();
01020 
01021     // Initialize distance of edges crossing triangles
01022     std::cout << "FMM: Initialize distance of edges crossing triangles."<<std::endl;
01023 
01024     for (unsigned int i=0; i<facets.size(); i++)
01025     {
01026     const sofa::helper::vector<int>& pts = facets[i][0];
01027     const int pt0 = 0;
01028     const Coord p0 = vertices[pts[pt0]]*scale;
01029     for (unsigned int pt2=2; pt2<pts.size(); pt2++)
01030     {
01031         const int pt1 = pt2-1;
01032         const Coord p1 = vertices[pts[pt1]]*scale;
01033         const Coord p2 = vertices[pts[pt2]]*scale;
01034         Coord bbmin = p0, bbmax = p0;
01035         for (int c=0; c<3; c++)
01036         if (p1[c] < bbmin[c]) bbmin[c] = p1[c];
01037         else if (p1[c] > bbmax[c]) bbmax[c] = p1[c];
01038         for (int c=0; c<3; c++)
01039         if (p2[c] < bbmin[c]) bbmin[c] = p2[c];
01040         else if (p2[c] > bbmax[c]) bbmax[c] = p2[c];
01041 
01042         Coord normal = (p1-p0).cross(p2-p0);
01043         normal.normalize();
01044         SReal d = -(p0*normal);
01045         int nedges = 0;
01046         int ix0 = ix(bbmin)-1; if (ix0 < 0) ix0 = 0;
01047         int iy0 = iy(bbmin)-1; if (iy0 < 0) iy0 = 0;
01048         int iz0 = iz(bbmin)-1; if (iz0 < 0) iz0 = 0;
01049         int ix1 = ix(bbmax)+2; if (ix1 >= nx) ix1 = nx-1;
01050         int iy1 = iy(bbmax)+2; if (iy1 >= ny) iy1 = ny-1;
01051         int iz1 = iz(bbmax)+2; if (iz1 >= nz) iz1 = nz-1;
01052         for (int z=iz0; z<iz1; z++)
01053         for (int y=iy0; y<iy1; y++)
01054         for (int x=ix0; x<ix1; x++)
01055         {
01056         Coord pos = coord(x,y,z);
01057         int ind = index(x,y,z);
01058         SReal dist = pos*normal + d;
01059         //if (rabs(dist) > cellWidth) continue; // no edge from this point can cross the plane
01060         
01061         // X edge
01062         if (rabs(normal[0]) > 1e-6)
01063         {
01064             SReal dist1 = -dist / normal[0];
01065             int ind2 = ind+1;
01066             if (dist1 >= -0.01*cellWidth[0] && dist1 <= 1.01*cellWidth[0])
01067             { // edge crossed plane
01068             if (pointInTriangle<1,2>(pos,p0,p1,p2))
01069             { // edge crossed triangle
01070                             ++nedges;
01071                 SReal dist2 = cellWidth[0] - dist1;
01072                 if (normal[0]<0)
01073                 { // p1 is in outside, p2 inside
01074                 if (dist1 < (dists[ind]))
01075                 { // nearest triangle
01076                     dists[ind] = dist1;
01077                     fmm_status[ind] = FMM_KNOWN_OUT;
01078                 }               
01079                 if (dist2 < (dists[ind2]))
01080                 { // nearest triangle
01081                     dists[ind2] = dist2;
01082                     fmm_status[ind2] = FMM_KNOWN_IN;
01083                 }
01084                 }
01085                 else
01086                 { // p1 is in inside, p2 outside
01087                 if (dist1 < (dists[ind]))
01088                 { // nearest triangle
01089                     dists[ind] = dist1;
01090                     fmm_status[ind] = FMM_KNOWN_IN;
01091                 }               
01092                 if (dist2 < (dists[ind2]))
01093                 { // nearest triangle
01094                     dists[ind2] = dist2;
01095                     fmm_status[ind2] = FMM_KNOWN_OUT;
01096                 }
01097                 }
01098             }
01099             }
01100         }
01101         
01102         // Y edge
01103         if (rabs(normal[1]) > 1e-6)
01104         {
01105             SReal dist1 = -dist / normal[1];
01106             int ind2 = ind+nx;
01107             if (dist1 >= -0.01*cellWidth[1] && dist1 <= 1.01*cellWidth[1])
01108             { // edge crossed plane
01109             if (pointInTriangle<2,0>(pos,p0,p1,p2))
01110             { // edge crossed triangle
01111                             ++nedges;
01112                 SReal dist2 = cellWidth[1] - dist1;
01113                 if (normal[1]<0)
01114                 { // p1 is in outside, p2 inside
01115                 if (dist1 < (dists[ind]))
01116                 { // nearest triangle
01117                     dists[ind] = dist1;
01118                     fmm_status[ind] = FMM_KNOWN_OUT;
01119                 }               
01120                 if (dist2 < (dists[ind2]))
01121                 { // nearest triangle
01122                     dists[ind2] = dist2;
01123                     fmm_status[ind2] = FMM_KNOWN_IN;
01124                 }
01125                 }
01126                 else
01127                 { // p1 is in inside, p2 outside
01128                 if (dist1 < (dists[ind]))
01129                 { // nearest triangle
01130                     dists[ind] = dist1;
01131                     fmm_status[ind] = FMM_KNOWN_IN;
01132                 }               
01133                 if (dist2 < (dists[ind2]))
01134                 { // nearest triangle
01135                     dists[ind2] = dist2;
01136                     fmm_status[ind2] = FMM_KNOWN_OUT;
01137                 }
01138                 }
01139             }
01140             }
01141         }
01142         
01143         // Z edge
01144         if (rabs(normal[2]) > 1e-6)
01145         {
01146             SReal dist1 = -dist / normal[2];
01147             int ind2 = ind+nxny;
01148             if (dist1 >= -0.01*cellWidth[2] && dist1 <= 1.01*cellWidth[2])
01149             { // edge crossed plane
01150             if (pointInTriangle<0,1>(pos,p0,p1,p2))
01151             { // edge crossed triangle
01152                             ++nedges;
01153                 SReal dist2 = cellWidth[2] - dist1;
01154                 if (normal[2]<0)
01155                 { // p1 is in outside, p2 inside
01156                 if (dist1 < (dists[ind]))
01157                 { // nearest triangle
01158                     dists[ind] = dist1;
01159                     fmm_status[ind] = FMM_KNOWN_OUT;
01160                 }               
01161                 if (dist2 < (dists[ind2]))
01162                 { // nearest triangle
01163                     dists[ind2] = dist2;
01164                     fmm_status[ind2] = FMM_KNOWN_IN;
01165                 }
01166                 }
01167                 else
01168                 { // p1 is in inside, p2 outside
01169                 if (dist1 < (dists[ind]))
01170                 { // nearest triangle
01171                     dists[ind] = dist1;
01172                     fmm_status[ind] = FMM_KNOWN_IN;
01173                 }               
01174                 if (dist2 < (dists[ind2]))
01175                 { // nearest triangle
01176                     dists[ind2] = dist2;
01177                     fmm_status[ind2] = FMM_KNOWN_OUT;
01178                 }
01179                 }
01180             }
01181             }
01182         }
01183         }
01184             std::cout << "Triangle "<<pts[pt0]<<"-"<<pts[pt1]<<"-"<<pts[pt2]<<" crossed "<<nedges<<" edges within <"<<ix0<<" "<<iy0<<" "<<iz0<<">-<"<<ix1-1<<" "<<iy1-1<<" "<<iz1-1<<" "<<">."<<std::endl;
01185     }
01186     }
01187 
01188     // Update known points neighbors
01189     std::cout << "FMM: Update known points neighbors."<<std::endl;
01190 
01191     for (int z=0, ind=0; z<nz; z++)
01192     for (int y=0; y<ny; y++)
01193     for (int x=0; x<nx; x++, ind++)
01194     {
01195         if (fmm_status[ind] < FMM_FAR)
01196         {
01197         int ind2;
01198             SReal dist1 = dists[ind];
01199             SReal dist2 = dist1+cellWidth[0];
01200         // X-1
01201         if (x>0)
01202         {
01203         ind2 = ind-1;
01204         if (x>0 && fmm_status[ind2] >= FMM_FAR && (dists[ind2]) > dist2)
01205         {
01206             dists[ind2] = dist2;
01207             fmm_push(ind2);
01208         }
01209         }
01210         // X+1
01211         if (x<nx-1)
01212         {
01213         ind2 = ind+1;
01214         if (x>0 && fmm_status[ind2] >= FMM_FAR && (dists[ind2]) > dist2)
01215         {
01216             dists[ind2] = dist2;
01217             fmm_push(ind2);
01218         }
01219         }
01220             dist2 = dist1+cellWidth[1];
01221         // Y-1
01222         if (y>0)
01223         {
01224         ind2 = ind-nx;
01225         if (x>0 && fmm_status[ind2] >= FMM_FAR && (dists[ind2]) > dist2)
01226         {
01227             dists[ind2] = dist2;
01228             fmm_push(ind2);
01229         }
01230         }
01231         // Y+1
01232         if (y<ny-1)
01233         {
01234         ind2 = ind+nx;
01235         if (x>0 && fmm_status[ind2] >= FMM_FAR && (dists[ind2]) > dist2)
01236         {
01237             dists[ind2] = dist2;
01238             fmm_push(ind2);
01239         }
01240         }
01241             dist2 = dist1+cellWidth[2];
01242         // Z-1
01243         if (z>0)
01244         {
01245         ind2 = ind-nxny;
01246         if (x>0 && fmm_status[ind2] >= FMM_FAR && (dists[ind2]) > dist2)
01247         {
01248             dists[ind2] = dist2;
01249             fmm_push(ind2);
01250         }
01251         }
01252         // Z+1
01253         if (z<nz-1)
01254         {
01255         ind2 = ind+nxny;
01256         if (x>0 && fmm_status[ind2] >= FMM_FAR && (dists[ind2]) > dist2)
01257         {
01258             dists[ind2] = dist2;
01259             fmm_push(ind2);
01260         }
01261         }
01262         }
01263     }
01264 
01265     // March through the heap
01266     std::cout << "FMM: March through the heap." << std::endl;
01267     while (fmm_heap_size > 0)
01268     {
01269         int ind = fmm_pop();
01270     int nbin = 0, nbout = 0;
01271     int x = ind%nx;
01272     int y = (ind/nx)%ny;
01273     int z = ind/nxny;
01274 
01275     int ind2;
01276     SReal dist1 = dists[ind];
01277     SReal dist2 = dist1+cellWidth[0];
01278     // X-1
01279     if (x>0)
01280     {
01281         ind2 = ind-1;
01282         if (fmm_status[ind2] < FMM_FAR)
01283         {
01284         if (fmm_status[ind2] == FMM_KNOWN_IN) ++nbin; else ++nbout;
01285         }
01286         else if ((dists[ind2]) > dist2)
01287         {
01288         dists[ind2] = dist2;
01289         fmm_push(ind2); // create or update the corresponding entry in the heap
01290         }
01291     }
01292     // X+1
01293     if (x<nx-1)
01294     {
01295         ind2 = ind+1;
01296         if (fmm_status[ind2] < FMM_FAR)
01297         {
01298         if (fmm_status[ind2] == FMM_KNOWN_IN) ++nbin; else ++nbout;
01299         }
01300         else if ((dists[ind2]) > dist2)
01301         {
01302         dists[ind2] = dist2;
01303         fmm_push(ind2); // create or update the corresponding entry in the heap
01304         }
01305     }
01306         dist2 = dist1+cellWidth[1];
01307     // Y-1
01308     if (y>0)
01309     {
01310         ind2 = ind-nx;
01311         if (fmm_status[ind2] < FMM_FAR)
01312         {
01313         if (fmm_status[ind2] == FMM_KNOWN_IN) ++nbin; else ++nbout;
01314         }
01315         else if ((dists[ind2]) > dist2)
01316         {
01317         dists[ind2] = dist2;
01318         fmm_push(ind2); // create or update the corresponding entry in the heap
01319         }
01320     }
01321     // Y+1
01322     if (y<ny-1)
01323     {
01324         ind2 = ind+nx;
01325         if (fmm_status[ind2] < FMM_FAR)
01326         {
01327         if (fmm_status[ind2] == FMM_KNOWN_IN) ++nbin; else ++nbout;
01328         }
01329         else if ((dists[ind2]) > dist2)
01330         {
01331         dists[ind2] = dist2;
01332         fmm_push(ind2); // create or update the corresponding entry in the heap
01333         }
01334     }
01335         dist2 = dist1+cellWidth[2];
01336     // Z-1
01337     if (z>0)
01338     {
01339         ind2 = ind-nxny;
01340         if (fmm_status[ind2] < FMM_FAR)
01341         {
01342         if (fmm_status[ind2] == FMM_KNOWN_IN) ++nbin; else ++nbout;
01343         }
01344         else if ((dists[ind2]) > dist2)
01345         {
01346         dists[ind2] = dist2;
01347         fmm_push(ind2); // create or update the corresponding entry in the heap
01348         }
01349     }
01350     // Z+1
01351     if (z<nz-1)
01352     {
01353         ind2 = ind+nxny;
01354         if (fmm_status[ind2] < FMM_FAR)
01355         {
01356         if (fmm_status[ind2] == FMM_KNOWN_IN) ++nbin; else ++nbout;
01357         }
01358         else if ((dists[ind2]) > dist2)
01359         {
01360         dists[ind2] = dist2;
01361         fmm_push(ind2); // create or update the corresponding entry in the heap
01362         }
01363     }
01364     if (nbin && nbout)
01365     {
01366         std::cerr << "FMM WARNING: in/out conflict at cell "<<x<<" "<<y<<" "<<z<<" ( "<<nbin<<" in, "<<nbout<<" out), dist = "<<dists[ind]<<std::endl;
01367     }
01368     if (nbin > nbout)
01369         fmm_status[ind] = FMM_KNOWN_IN;
01370     else
01371         fmm_status[ind] = FMM_KNOWN_OUT;
01372     }
01373 
01374     // Finalize distances
01375     std::cout << "FMM: Finalize distances."<<std::endl;
01376     int nbin = 0;
01377     for (int z=0, ind=0; z<nz; z++)
01378     for (int y=0; y<ny; y++)
01379     for (int x=0; x<nx; x++, ind++)
01380     {
01381     if (fmm_status[ind] == FMM_KNOWN_IN)
01382     {
01383         dists[ind] = -dists[ind];
01384         ++nbin;
01385     }
01386     else if (fmm_status[ind] != FMM_KNOWN_OUT)
01387     {
01388         //std::cerr << "FMM ERROR: cell "<<x<<" "<<y<<" "<<z<<" not computed. dist="<<dists[ind]<<std::endl;
01389     }
01390     }
01391     std::cout << "FMM: DONE. "<< nbin << " points inside ( " << (nbin*100)/size() <<" % )" << std::endl;
01392 }
01393 
01394 inline void DistanceGrid::fmm_swap(int entry1, int entry2)
01395 {
01396     int ind1 = fmm_heap[entry1];
01397     int ind2 = fmm_heap[entry2];
01398     fmm_heap[entry1] = ind2;
01399     fmm_heap[entry2] = ind1;
01400     fmm_status[ind1] = entry2 + FMM_FRONT0;
01401     fmm_status[ind2] = entry1 + FMM_FRONT0;
01402 }
01403 
01404 int DistanceGrid::fmm_pop()
01405 {
01406     int res = fmm_heap[0];
01407 #ifdef FMM_VERBOSE
01408     std::cout << "fmm_pop -> <"<<(res%nx)<<','<<((res/nx)%ny)<<','<<(res/nxny)<<">="<<dists[res]<<std::endl;
01409 #endif
01410     --fmm_heap_size;
01411     if (fmm_heap_size>0)
01412     {
01413         fmm_swap(0, fmm_heap_size);
01414         int i=0;
01415         SReal phi = (dists[fmm_heap[i]]);
01416         while (i*2+1 < fmm_heap_size)
01417         {
01418             SReal phi1 = (dists[fmm_heap[i*2+1]]);
01419             if (i*2+2 < fmm_heap_size)
01420             {
01421                 SReal phi2 = (dists[fmm_heap[i*2+2]]);
01422                 if (phi1 < phi)
01423                 {
01424                     if (phi1 < phi2)
01425                     {
01426                         fmm_swap(i, i*2+1);
01427                         i = i*2+1;
01428                     }
01429                     else
01430                     {
01431                         fmm_swap(i, i*2+2);
01432                         i = i*2+2;
01433                     }
01434                 }
01435                 else if (phi2 < phi)
01436                 {
01437                     fmm_swap(i, i*2+2);
01438                     i = i*2+2;
01439                 }
01440                 else break;
01441             }
01442             else if (phi1 < phi)
01443             {
01444                 fmm_swap(i, i*2+1);
01445                 i = i*2+1;
01446             }
01447             else break;
01448         }
01449     }
01450 #ifdef FMM_VERBOSE
01451     std::cout << "fmm_heap = [";
01452     for (int i=0;i<fmm_heap_size;i++)
01453         std::cout << " <"<<(fmm_heap[i]%nx)<<','<<((fmm_heap[i]/nx)%ny)<<','<<(fmm_heap[i]/nxny)<<">="<<dists[fmm_heap[i]];
01454     std::cout << std::endl;
01455 #endif
01456     //fmm_status[res] = FMM_KNOWN;
01457     return res;
01458 }
01459 
01460 void DistanceGrid::fmm_push(int index)
01461 {
01462     SReal phi = (dists[index]);
01463     int i;
01464     if (fmm_status[index] >= FMM_FRONT0)
01465     {
01466         i = fmm_status[index] - FMM_FRONT0;
01467 #ifdef FMM_VERBOSE
01468         std::cout << "fmm update <"<<(index%nx)<<','<<((index/nx)%ny)<<','<<(index/nxny)<<">="<<dists[index]<<" from entry "<<i<<std::endl;
01469 #endif
01470         while (i>0 && phi < (dists[fmm_heap[(i-1)/2]]))
01471         {
01472             fmm_swap(i,(i-1)/2);
01473             i = (i-1)/2;
01474         }
01475         while (i*2+1 < fmm_heap_size)
01476         {
01477             SReal phi1 = (dists[fmm_heap[i*2+1]]);
01478             if (i*2+2 < fmm_heap_size)
01479             {
01480                 SReal phi2 = (dists[fmm_heap[i*2+2]]);
01481                 if (phi1 < phi)
01482                 {
01483                     if (phi1 < phi2)
01484                     {
01485                         fmm_swap(i, i*2+1);
01486                         i = i*2+1;
01487                     }
01488                     else
01489                     {
01490                         fmm_swap(i, i*2+2);
01491                         i = i*2+2;
01492                     }
01493                 }
01494                 else if (phi2 < phi)
01495                 {
01496                     fmm_swap(i, i*2+2);
01497                     i = i*2+2;
01498                 }
01499                 else break;
01500             }
01501             else if (phi1 < phi)
01502             {
01503                 fmm_swap(i, i*2+1);
01504                 i = i*2+1;
01505             }
01506             else break;
01507         }
01508     }
01509     else
01510     {
01511 #ifdef FMM_VERBOSE
01512         std::cout << "fmm push <"<<(index%nx)<<','<<((index/nx)%ny)<<','<<(index/nxny)<<">="<<dists[index]<<std::endl;
01513 #endif
01514         i = fmm_heap_size;
01515         ++fmm_heap_size;
01516         fmm_heap[i] = index;
01517         fmm_status[index] = i;
01518         while (i>0 && phi < (dists[fmm_heap[(i-1)/2]]))
01519         {
01520             fmm_swap(i,(i-1)/2);
01521             i = (i-1)/2;
01522         }
01523     }
01524 #ifdef FMM_VERBOSE
01525     std::cout << "fmm_heap = [";
01526     for (int i=0;i<fmm_heap_size;i++)
01527         std::cout << " <"<<(fmm_heap[i]%nx)<<','<<((fmm_heap[i]/nx)%ny)<<','<<(fmm_heap[i]/nxny)<<">="<<dists[fmm_heap[i]];
01528     std::cout << std::endl;
01529 #endif
01530 }
01531 
01532 DistanceGrid* DistanceGrid::loadShared(const std::string& filename, double scale, int nx, int ny, int nz, Coord pmin, Coord pmax)
01533 {
01534     DistanceGridParams params;
01535     params.filename = filename;
01536     params.scale = scale;
01537     params.nx = nx;
01538     params.ny = ny;
01539     params.nz = nz;
01540     params.pmin = pmin;
01541     params.pmax = pmax;
01542     std::map<DistanceGridParams, DistanceGrid*>& shared = getShared();
01543     std::map<DistanceGridParams, DistanceGrid*>::iterator it = shared.find(params);
01544     if (it != shared.end())
01545         return it->second->addRef();
01546     else
01547     {
01548         return shared[params] = load(filename, scale, nx, ny, nz, pmin, pmax);
01549     }
01550 }
01551 
01552 std::map<DistanceGrid::DistanceGridParams, DistanceGrid*>& DistanceGrid::getShared()
01553 {
01554     static std::map<DistanceGridParams, DistanceGrid*> instance;
01555     return instance;
01556 }
01557 
01558 } // namespace collision
01559 
01560 } // namespace component
01561 
01562 } // namespace sofa

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