VoxelGrid.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/VoxelGrid.h>
00026 #include <sofa/component/collision/Sphere.h>
00027 #include <sofa/component/collision/Triangle.h>
00028 #include <sofa/component/collision/Line.h>
00029 #include <sofa/component/collision/Point.h>
00030 #include <sofa/helper/FnDispatcher.h>
00031 #include <sofa/simulation/tree/xml/ObjectFactory.h>
00032 #include <map>
00033 #include <sofa/helper/system/gl.h>
00034 #include <sofa/helper/system/glut.h>
00035 
00036 
00037 /* for debugging the collision method */
00038 #ifdef _WIN32
00039 #include <windows.h>
00040 #endif
00041 
00042 namespace sofa
00043 {
00044 
00045 namespace helper
00046 {
00047     void create(VoxelGrid*& obj, simulation::tree::xml::ObjectDescription* arg)
00048     {
00049         obj = new VoxelGrid(
00050         Vector3(atof(arg->getAttribute("minx",arg->getAttribute("min","-20.0"))),
00051             atof(arg->getAttribute("miny",arg->getAttribute("min","-20.0"))),
00052             atof(arg->getAttribute("minz",arg->getAttribute("min","-20.0")))),
00053         Vector3(atof(arg->getAttribute("maxx",arg->getAttribute("max","20.0"))),
00054             atof(arg->getAttribute("maxy",arg->getAttribute("max","20.0"))),
00055             atof(arg->getAttribute("maxz",arg->getAttribute("max","20.0")))),
00056         Vector3(atof(arg->getAttribute("nx",arg->getAttribute("n","5.0"))),
00057             atof(arg->getAttribute("ny",arg->getAttribute("n","5.0"))),
00058             atof(arg->getAttribute("nz",arg->getAttribute("n","5.0")))),
00059         atoi(arg->getAttribute("draw","0"))!=0
00060         );
00061     }
00062     
00063     SOFA_DECL_CLASS(VoxelGrid)
00064     
00065     Creator<simulation::tree::xml::ObjectFactory, VoxelGrid> VoxelGridClass("VoxelGridDetection");
00066 }
00067 namespace component
00068 {
00069 
00070 namespace collision
00071 {
00072 
00073 using namespace sofa::defaulttype;
00074 using namespace core::objectmodel;
00075 
00076 void VoxelGrid::posToIdx (const Vector3& pos, Vector3 &indices)
00077 {
00078     int i;
00079     Vector3 nbSubdivisions;
00080 
00081     for (i = 0; i < 3; i++) 
00082         nbSubdivisions[i] = (maxVect[i] - minVect[i]) / step[i];
00083 
00084     indices[0] = (int)((pos[0] - minVect[0]) / step[0]);
00085     if (indices[0] < 0) indices[0] = 0;
00086     if (indices[0] >= nbSubdivisions[0]) indices[0] = nbSubdivisions[0] - 1;
00087     
00088     indices[1] = (int)((pos[1] - minVect[1]) / step[1]);
00089     if (indices[1] < 0) indices[1] = 0;
00090     if (indices[1] >= nbSubdivisions[1]) indices[1] = nbSubdivisions[1] - 1;
00091     
00092     indices[2] = (int)((pos[2] - minVect[2]) / step[2]);
00093     if (indices[2] < 0) indices[2] = 0;
00094     if (indices[2] >= nbSubdivisions[2]) indices[2] = nbSubdivisions[2] - 1;
00095 }
00096 
00097 void VoxelGrid::createVoxelGrid (const Vector3& minAxis, const Vector3& maxAxis, const Vector3 &nbSubdivision)
00098 {
00099     int i, j, k;
00100     
00101     timeStamp = -1;
00102     minVect = minAxis;
00103     maxVect = maxAxis;
00104     //nbSubDiv = nbSubdivision;
00105     Vector3 minCell, maxCell;
00106 
00107     for (i = 0; i < 3; i++) 
00108         step[i] = (maxVect[i] - minVect[i]) / nbSubdivision[i];
00109     
00110     grid = new GridCell**[(int) nbSubdivision[0]];
00111     for (i = 0; i < (int)nbSubdivision[0]; i++) 
00112     {
00113         grid[i] = new GridCell*[(int)nbSubdivision[1]];
00114         for (j = 0; j < (int)nbSubdivision[1]; j++) {
00115             grid[i][j] = new GridCell[(int)nbSubdivision[2]];
00116             for (k = 0; k < (int)nbSubdivision[2]; k++) {
00117                 minCell[0] = minVect[0] + step[0] * i;
00118                 minCell[1] = minVect[1] + step[1] * j;
00119                 minCell[2] = minVect[2] + step[2] * k;
00120                 maxCell[0] = minCell[0] + step[0];
00121                 maxCell[1] = minCell[1] + step[1];
00122                 maxCell[2] = minCell[2] + step[2];
00123                 grid[i][j][k].setMinMax(minCell, maxCell);      
00124             }
00125         }
00126     }
00127 }
00128 
00129 static std::map<CollisionModel*,int> timestamps;
00130 
00131 int gettimestamp(CollisionModel* cm)
00132 {
00133     std::map<CollisionModel*,int>::iterator it = timestamps.find(cm);
00134     if (it == timestamps.end()) return -1;
00135     else return it->second;
00136 }
00137 
00138 int settimestamp(CollisionModel* cm, int t)
00139 {
00140     timestamps[cm] = t;
00141     return t;
00142 }
00143 
00144 void VoxelGrid::addCollisionModel(CollisionModel *cm)
00145 {
00146     add(cm,0);
00147 }
00148 
00149 void VoxelGrid::add(CollisionModel *cm, int phase)
00150 {
00151     if (!cm->isStatic() || gettimestamp(cm) < 0)
00152     {
00153     //const sofa::helper::vector<CollisionElementIterator>& vectElems = cm->getCollisionElements();
00154     CollisionElementIterator it = cm->begin();
00155     CollisionElementIterator itEnd = cm->end();
00156 
00157     const bool proximity  = intersectionMethod->useProximity();
00158     const double distance = intersectionMethod->getAlarmDistance();
00159 
00160     sofa::helper::vector<CollisionElementIterator> collisionElems;
00161     Vector3 minBBox, maxBBox;
00162     Vector3 ijk, lmn;
00163     bool collisionDetected = false;
00164 
00165     for (; it != itEnd; it++)
00166     {
00167         minBBox = it->getBBoxMin();
00168         maxBBox = it->getBBoxMax();
00169         if (proximity)
00170         {
00171             maxBBox[0] += distance;
00172             maxBBox[1] += distance;
00173             maxBBox[2] += distance;
00174         }
00175         
00176         posToIdx (minBBox, ijk);
00177         posToIdx (maxBBox, lmn);
00178 
00179         core::CollisionModel::clearAllVisits();
00180         
00181         for(int i = (int) ijk[0]; i <= (int)lmn[0]; i++ ){
00182             for(int j = (int) ijk[1] ; j <= (int) lmn[1]; j++ ){
00183                 for(int k = (int) ijk[2] ; k <= (int) lmn[2]; k++ ){
00184                     //if (grid[i][j][k].timeStamp != timeStamp)
00185                     grid[i][j][k].eraseAll(timeStamp);
00186                     grid[i][j][k].add(this, it, collisionElems, phase);
00187                 }
00188             }
00189         }
00190 
00191         // get the collision pair or self collision pair for this model
00192         sofa::helper::vector<CollisionElementIterator>::const_iterator itCollis = collisionElems.begin();
00193         sofa::helper::vector<CollisionElementIterator>::const_iterator itCollisEnd = collisionElems.end();
00194         
00195         for (; itCollis != itCollisEnd; itCollis++)
00196         {
00197             //if ((*it)->canCollideWith(*itCollis))
00198             {
00199                 collisionDetected = true;
00200                 cmPairs.push_back(std::pair<CollisionModel*, CollisionModel*>(it->getCollisionModel(), itCollis->getCollisionModel()));
00201                 elemPairs.push_back(std::pair<CollisionElementIterator, CollisionElementIterator> (it, *itCollis));
00202             }
00203         }
00204         collisionElems.clear();
00205     }
00206 
00207     if (cm->isStatic())
00208         settimestamp(cm, 0);
00209     }
00210 }
00211 
00212 void VoxelGrid::addCollisionPair(const std::pair<CollisionModel*, CollisionModel*>& cmPair)
00213 {
00214     timeLogger = dynamic_cast<simulation::tree::GNode*>(getContext());
00215     if (timeLogger && !timeLogger->getLogTime()) timeLogger=NULL;
00216     timeInter = 0;
00217 
00218     CollisionModel *cm1 = cmPair.first->getNext(); //cmPair->getCollisionModel(0);
00219     CollisionModel *cm2 = cmPair.second->getNext(); //getCollisionModel(1);
00220 
00221     if (cm1->isStatic() && cm2->isStatic())
00222         return;
00223 
00224     if (cm1->empty() || cm2->empty())
00225         return;
00226 
00227     //const sofa::helper::vector<CollisionElementIterator>& vectElems1 = cm1->getCollisionElements();
00228     //const sofa::helper::vector<CollisionElementIterator>& vectElems2 = cm2->getCollisionElements();
00229 
00230     if (!intersectionMethod->isSupported(cm1, cm2))
00231         return;
00232 
00233     if (gettimestamp(cm1) < timeStamp)
00234         add(cm1,1);
00235     settimestamp(cm1, timeStamp);
00236     if (gettimestamp(cm2) < timeStamp)
00237         add(cm2,1);
00238     settimestamp(cm2, timeStamp);
00239     if (timeLogger)
00240     {
00241         timeLogger->addTime(timeInter, "collision", intersectionMethod, this);
00242         timeLogger = NULL;
00243     }
00244 }
00245 
00246 void VoxelGrid::draw()
00247 {
00248     if (!bDraw) return;
00249     Vector3 nbSubdiv;
00250     int i;
00251 
00252     for (i = 0; i < 3; i++) 
00253         nbSubdiv[i] = (maxVect[i] - minVect[i]) / step[i];
00254 
00255     glDisable(GL_LIGHTING);
00256     glColor3f (0.0, 0.25, 0.25);
00257     
00258     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00259     
00260     glBegin(GL_QUADS);
00261     glVertex3d (minVect[0], minVect[1], minVect[2]);
00262     glVertex3d (minVect[0], maxVect[1], minVect[2]);
00263     glVertex3d (maxVect[0], maxVect[1], minVect[2]);
00264     glVertex3d (maxVect[0], minVect[1], minVect[2]);
00265 
00266     glVertex3d (minVect[0], minVect[1], minVect[2]);
00267     glVertex3d (minVect[0], maxVect[1], minVect[2]);
00268     glVertex3d (minVect[0], maxVect[1], maxVect[2]);
00269     glVertex3d (minVect[0], minVect[1], maxVect[2]);
00270 
00271     glVertex3d (maxVect[0], minVect[1], minVect[2]);
00272     glVertex3d (maxVect[0], maxVect[1], minVect[2]);
00273     glVertex3d (maxVect[0], maxVect[1], maxVect[2]);
00274     glVertex3d (maxVect[0], minVect[1], maxVect[2]);
00275 
00276     glVertex3d (minVect[0], maxVect[1], maxVect[2]);
00277     glVertex3d (maxVect[0], maxVect[1], maxVect[2]);
00278     glVertex3d (maxVect[0], minVect[1], maxVect[2]);
00279     glVertex3d (minVect[0], minVect[1], maxVect[2]);
00280 
00281     glEnd();
00282     
00283     for(i = 0; i < (int) nbSubdiv[0]; i++)
00284     {
00285         for(int j = 0 ; j < (int) nbSubdiv[1]; j++){
00286             for(int k = 0 ; k < (int) nbSubdiv[2]; k++){
00287                 grid[i][j][k].draw(timeStamp);
00288             }
00289         }
00290     }   
00291     sofa::helper::vector<std::pair<CollisionElementIterator, CollisionElementIterator> >::iterator it = elemPairs.begin();
00292     sofa::helper::vector<std::pair<CollisionElementIterator, CollisionElementIterator> >::iterator itEnd = elemPairs.end();
00293     if (elemPairs.size() >= 1)
00294     {
00295         glDisable(GL_LIGHTING);
00296         glColor3f(1.0, 0.0, 1.0);
00297         glLineWidth(3);
00298         //std::cout << "Size : " << elemPairs.size() << std::endl;
00299         for (; it != itEnd; it++)
00300         {   
00301             it->first->draw();
00302             it->second->draw();
00303         }
00304         glLineWidth(1);
00305     }
00306     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00307 }
00308 
00309 void GridCell::add(VoxelGrid* grid, CollisionElementIterator collisionElem, sofa::helper::vector<CollisionElementIterator> &vectCollis, int phase)
00310 {
00311     Intersection* intersectionMethod = grid->getIntersectionMethod();
00312     const bool proximity  = intersectionMethod->useProximity();
00313     const double distance = intersectionMethod->getAlarmDistance();
00314 
00315     Vector3 minBBox1, maxBBox1;
00316     //Vector3 minBBox2, maxBBox2;
00317     minBBox1 = collisionElem.getBBoxMin();
00318     maxBBox1 = collisionElem.getBBoxMax();
00319 
00320     simulation::tree::GNode::ctime_t t0 = 0;
00321 
00322     {
00323         sofa::helper::vector < CollisionElementIterator >   ::iterator it    = collisElems.begin();
00324         sofa::helper::vector < CollisionElementIterator >   ::iterator itEnd = collisElems.end();
00325     
00326         if (proximity)
00327         {
00328             minBBox1[0] -= distance;
00329             minBBox1[1] -= distance;
00330             minBBox1[2] -= distance;
00331             maxBBox1[0] += distance;
00332             maxBBox1[1] += distance;
00333             maxBBox1[2] += distance;
00334         }
00335     
00336         for (; it < itEnd; it++)
00337         {
00338             if (!collisionElem.canCollideWith(*it)) continue;
00339             if (it->visited()) continue;
00340             it->setVisited();
00341             const double* minBBox2 = it->getBBoxMin();
00342             const double* maxBBox2 = it->getBBoxMax();
00343             if (minBBox1[0] > maxBBox2[0] || minBBox2[0] > maxBBox1[0]
00344             || minBBox1[1] > maxBBox2[1] || minBBox2[1] > maxBBox1[1]
00345             || minBBox1[2] > maxBBox2[2] || minBBox2[2] > maxBBox1[2]) continue;
00346     
00347             if (grid->timeLogger) t0 = grid->timeLogger->startTime();
00348             bool b = intersectionMethod->canIntersect(collisionElem, (*it));
00349             if (grid->timeLogger) grid->timeInter += grid->timeLogger->startTime() - t0;
00350             if (b)
00351                 vectCollis.push_back(*it);
00352         }
00353     }
00354     {
00355         sofa::helper::vector < CollisionElementIterator >::iterator it = collisElemsImmobile[phase].begin();
00356         sofa::helper::vector < CollisionElementIterator >::iterator itEnd = collisElemsImmobile[phase].end();
00357         for (; it < itEnd; it++)
00358         {
00359             if (!collisionElem.canCollideWith(*it)) continue;
00360             if ((*it)->visited()) continue;
00361             (*it)->setVisited();
00362             const double* minBBox2 = it->getBBoxMin();
00363             const double* maxBBox2 = it->getBBoxMax();
00364             if (minBBox1[0] > maxBBox2[0] || minBBox2[0] > maxBBox1[0]
00365             || minBBox1[1] > maxBBox2[1] || minBBox2[1] > maxBBox1[1]
00366             || minBBox1[2] > maxBBox2[2] || minBBox2[2] > maxBBox1[2]) continue;
00367 
00368             if (grid->timeLogger) t0 = grid->timeLogger->startTime();
00369             bool b = intersectionMethod->canIntersect(collisionElem, (*it));
00370             if (grid->timeLogger) grid->timeInter += grid->timeLogger->startTime() - t0;
00371             if (b)
00372                 vectCollis.push_back(*it);
00373         }
00374     }
00375     if (collisionElem->getCollisionModel()->isStatic())
00376     {
00377         collisElemsImmobile[phase].push_back(collisionElem);
00378     }
00379     else
00380     {
00381         collisElems.push_back(collisionElem);
00382     }
00383 }
00384 
00385 void GridCell::eraseAll(int timeStampMethod)
00386 {
00387     if (timeStampMethod != timeStamp) 
00388     {
00389         timeStamp = timeStampMethod;
00390         collisElems.clear();
00391     }
00392 }
00393 
00394 GridCell::GridCell(void)
00395 {
00396     timeStamp = 0;
00397 }
00398 
00399 void GridCell::setMinMax(const Vector3 &minimum, const Vector3 &maximum)
00400 {
00401     minCell = minimum;
00402     maxCell = maximum;
00403 }
00404 
00405 void GridCell::draw (int timeStampMethod)
00406 {
00407     if (timeStampMethod != timeStamp || (collisElems.empty() && collisElemsImmobile[1].empty()))
00408     {
00409         return;
00410         glColor3f (0.0, 0.25, 0.25);
00411     }
00412     else
00413     {
00414         glColor3f (0.0, 1.0, 1.0);
00415     }
00416     
00417     //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00418     
00419     glBegin(GL_QUADS);
00420     glVertex3d (minCell[0], minCell[1], minCell[2]);
00421     glVertex3d (minCell[0], maxCell[1], minCell[2]);
00422     glVertex3d (maxCell[0], maxCell[1], minCell[2]);
00423     glVertex3d (maxCell[0], minCell[1], minCell[2]);
00424 
00425     glVertex3d (minCell[0], minCell[1], minCell[2]);
00426     glVertex3d (minCell[0], maxCell[1], minCell[2]);
00427     glVertex3d (minCell[0], maxCell[1], maxCell[2]);
00428     glVertex3d (minCell[0], minCell[1], maxCell[2]);
00429 
00430     glVertex3d (maxCell[0], minCell[1], minCell[2]);
00431     glVertex3d (maxCell[0], maxCell[1], minCell[2]);
00432     glVertex3d (maxCell[0], maxCell[1], maxCell[2]);
00433     glVertex3d (maxCell[0], minCell[1], maxCell[2]);
00434 
00435     glVertex3d (minCell[0], maxCell[1], maxCell[2]);
00436     glVertex3d (maxCell[0], maxCell[1], maxCell[2]);
00437     glVertex3d (maxCell[0], minCell[1], maxCell[2]);
00438     glVertex3d (minCell[0], minCell[1], maxCell[2]);
00439 
00440     glEnd();
00441     //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00442 }
00443 
00444 } // namespace collision
00445 
00446 } // namespace component
00447 
00448 } // namespace sofa
00449 

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