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/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
00033 #include <flowvr/render/mesh.h>
00034
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
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;
00158
00159 updateGrid();
00160
00161 cubeModel->resize(size);
00162 for (int i=0; i<size; i++)
00163 {
00164
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
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);
00193
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
00231
00232
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
00247
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
00273
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
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
00381
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);
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;
00493
00494 updateGrid();
00495
00496 cubeModel->resize(size);
00497 for (int i=0; i<size; i++)
00498 {
00499
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);
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];
00556 Dy = corners[C010]-corners[C000];
00557 Dz = corners[C001]-corners[C000];
00558 Dxy = corners[C110]-corners[C010]-Dx;
00559 Dxz = corners[C101]-corners[C001]-Dx;
00560 Dyz = corners[C011]-corners[C001]-Dy;
00561 Dxyz = corners[C111]-corners[C101]-corners[C011]+corners[C001]-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]);
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
00621 DeformedCube& cube = getDeformCube( index );
00622
00623
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);
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
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
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
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
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
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
00980
00981 SReal dim2 = dim;
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
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
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
01060
01061
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 {
01068 if (pointInTriangle<1,2>(pos,p0,p1,p2))
01069 {
01070 ++nedges;
01071 SReal dist2 = cellWidth[0] - dist1;
01072 if (normal[0]<0)
01073 {
01074 if (dist1 < (dists[ind]))
01075 {
01076 dists[ind] = dist1;
01077 fmm_status[ind] = FMM_KNOWN_OUT;
01078 }
01079 if (dist2 < (dists[ind2]))
01080 {
01081 dists[ind2] = dist2;
01082 fmm_status[ind2] = FMM_KNOWN_IN;
01083 }
01084 }
01085 else
01086 {
01087 if (dist1 < (dists[ind]))
01088 {
01089 dists[ind] = dist1;
01090 fmm_status[ind] = FMM_KNOWN_IN;
01091 }
01092 if (dist2 < (dists[ind2]))
01093 {
01094 dists[ind2] = dist2;
01095 fmm_status[ind2] = FMM_KNOWN_OUT;
01096 }
01097 }
01098 }
01099 }
01100 }
01101
01102
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 {
01109 if (pointInTriangle<2,0>(pos,p0,p1,p2))
01110 {
01111 ++nedges;
01112 SReal dist2 = cellWidth[1] - dist1;
01113 if (normal[1]<0)
01114 {
01115 if (dist1 < (dists[ind]))
01116 {
01117 dists[ind] = dist1;
01118 fmm_status[ind] = FMM_KNOWN_OUT;
01119 }
01120 if (dist2 < (dists[ind2]))
01121 {
01122 dists[ind2] = dist2;
01123 fmm_status[ind2] = FMM_KNOWN_IN;
01124 }
01125 }
01126 else
01127 {
01128 if (dist1 < (dists[ind]))
01129 {
01130 dists[ind] = dist1;
01131 fmm_status[ind] = FMM_KNOWN_IN;
01132 }
01133 if (dist2 < (dists[ind2]))
01134 {
01135 dists[ind2] = dist2;
01136 fmm_status[ind2] = FMM_KNOWN_OUT;
01137 }
01138 }
01139 }
01140 }
01141 }
01142
01143
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 {
01150 if (pointInTriangle<0,1>(pos,p0,p1,p2))
01151 {
01152 ++nedges;
01153 SReal dist2 = cellWidth[2] - dist1;
01154 if (normal[2]<0)
01155 {
01156 if (dist1 < (dists[ind]))
01157 {
01158 dists[ind] = dist1;
01159 fmm_status[ind] = FMM_KNOWN_OUT;
01160 }
01161 if (dist2 < (dists[ind2]))
01162 {
01163 dists[ind2] = dist2;
01164 fmm_status[ind2] = FMM_KNOWN_IN;
01165 }
01166 }
01167 else
01168 {
01169 if (dist1 < (dists[ind]))
01170 {
01171 dists[ind] = dist1;
01172 fmm_status[ind] = FMM_KNOWN_IN;
01173 }
01174 if (dist2 < (dists[ind2]))
01175 {
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
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
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
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
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
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
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
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
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
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);
01290 }
01291 }
01292
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);
01304 }
01305 }
01306 dist2 = dist1+cellWidth[1];
01307
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);
01319 }
01320 }
01321
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);
01333 }
01334 }
01335 dist2 = dist1+cellWidth[2];
01336
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);
01348 }
01349 }
01350
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);
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
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
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
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 }
01559
01560 }
01561
01562 }