00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
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
00185 grid[i][j][k].eraseAll(timeStamp);
00186 grid[i][j][k].add(this, it, collisionElems, phase);
00187 }
00188 }
00189 }
00190
00191
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
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();
00219 CollisionModel *cm2 = cmPair.second->getNext();
00220
00221 if (cm1->isStatic() && cm2->isStatic())
00222 return;
00223
00224 if (cm1->empty() || cm2->empty())
00225 return;
00226
00227
00228
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
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
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
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
00442 }
00443
00444 }
00445
00446 }
00447
00448 }
00449