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 #ifndef SOFA_GPU_CUDA_CUDADISTANCEGRIDCOLLISIONMODEL_H
00026 #define SOFA_GPU_CUDA_CUDADISTANCEGRIDCOLLISIONMODEL_H
00027
00028 #include "CudaTypes.h"
00029
00030 #include <sofa/core/CollisionModel.h>
00031 #include <sofa/component/MechanicalObject.h>
00032 #include <sofa/defaulttype/Vec3Types.h>
00033 #include <sofa/defaulttype/RigidTypes.h>
00034 #include <sofa/helper/io/Mesh.h>
00035 #include <sofa/core/componentmodel/topology/BaseMeshTopology.h>
00036
00037 namespace sofa
00038 {
00039
00040 namespace gpu
00041 {
00042
00043 namespace cuda
00044 {
00045
00046 using namespace sofa::defaulttype;
00047
00048
00049 class CudaDistanceGrid
00050 {
00051 public:
00052 typedef float Real;
00053 static Real maxDist() { return (Real)1e10; }
00054 typedef Vec3f Coord;
00055
00056 typedef CudaVector<Real> VecReal;
00057 typedef CudaVector<Coord> VecCoord;
00058
00059 CudaDistanceGrid(int nx, int ny, int nz, Coord pmin, Coord pmax);
00060
00061 protected:
00062 ~CudaDistanceGrid();
00063
00064 public:
00065
00067 static CudaDistanceGrid* load(const std::string& filename, double scale=1.0, int nx=64, int ny=64, int nz=64, Coord pmin = Coord(), Coord pmax = Coord());
00068
00070 static CudaDistanceGrid* loadShared(const std::string& filename, double scale=1.0, int nx=64, int ny=64, int nz=64, Coord pmin = Coord(), Coord pmax = Coord());
00071
00073 CudaDistanceGrid* addRef();
00074
00076 bool release();
00077
00079 bool save(const std::string& filename);
00080
00082 void calcDistance();
00083
00086 void calcCubeDistance(Real dim=1, int np=5);
00087
00089 void computeBBox();
00090
00091 int getNx() const { return nx; }
00092 int getNy() const { return ny; }
00093 int getNz() const { return nz; }
00094 const Coord& getCellWidth() const { return cellWidth; }
00095 const Coord& getInvCellWidth() const { return invCellWidth; }
00096 const VecReal& getDists() const { return dists; }
00097 VecReal& getDists() { return dists; }
00098
00099 int size() const { return nxnynz; }
00100
00101 const Coord& getBBMin() const { return bbmin; }
00102 const Coord& getBBMax() const { return bbmax; }
00103 void setBBMin(const Coord& val) { bbmin = val; }
00104 void setBBMax(const Coord& val) { bbmax = val; }
00105 Coord getBBCorner(int i) const { return Coord((i&1)?bbmax[0]:bbmin[0],(i&2)?bbmax[1]:bbmin[1],(i&4)?bbmax[2]:bbmin[2]); }
00106 bool inBBox(const Coord& p, Real margin=0.0f) const
00107 {
00108 for (int c=0;c<3;++c)
00109 if (p[c] < bbmin[c]-margin || p[c] > bbmax[c]+margin) return false;
00110 return true;
00111 }
00112
00113 const Coord& getPMin() const { return pmin; }
00114 const Coord& getPMax() const { return pmax; }
00115 Coord getCorner(int i) const { return Coord((i&1)?pmax[0]:pmin[0],(i&2)?pmax[1]:pmin[1],(i&4)?pmax[2]:pmin[2]); }
00116
00117 bool isCube() const { return cubeDim != 0; }
00118 Real getCubeDim() const { return cubeDim; }
00119
00120 bool inGrid(const Coord& p) const
00121 {
00122 Coord epsilon = cellWidth*0.1;
00123 for (int c=0;c<3;++c)
00124 if (p[c] < pmin[c]+epsilon[c] || p[c] > pmax[c]-epsilon[c]) return false;
00125 return true;
00126 }
00127
00128 Coord clamp(Coord p) const
00129 {
00130 for (int c=0;c<3;++c)
00131 if (p[c] < pmin[c]) p[c] = pmin[c];
00132 else if (p[c] > pmax[c]) p[c] = pmax[c];
00133 return p;
00134 }
00135
00136 int ix(const Coord& p) const
00137 {
00138 return helper::rfloor((p[0]-pmin[0])*invCellWidth[0]);
00139 }
00140
00141 int iy(const Coord& p) const
00142 {
00143 return helper::rfloor((p[1]-pmin[1])*invCellWidth[1]);
00144 }
00145
00146 int iz(const Coord& p) const
00147 {
00148 return helper::rfloor((p[2]-pmin[2])*invCellWidth[2]);
00149 }
00150
00151 int index(const Coord& p, Coord& coefs) const
00152 {
00153 coefs[0] = (p[0]-pmin[0])*invCellWidth[0];
00154 coefs[1] = (p[1]-pmin[1])*invCellWidth[1];
00155 coefs[2] = (p[2]-pmin[2])*invCellWidth[2];
00156 int x = helper::rfloor(coefs[0]);
00157 if (x==-1) x=0; else if (x==nx-1) x=nx-2;
00158 coefs[0] -= x;
00159 int y = helper::rfloor(coefs[1]);
00160 if (y==-1) y=0; else if (y==ny-1) y=ny-2;
00161 coefs[1] -= y;
00162 int z = helper::rfloor(coefs[2]);
00163 if (z==-1) z=0; else if (z==nz-1) z=nz-2;
00164 coefs[2] -= z;
00165 return x+nx*(y+ny*(z));
00166 }
00167
00168 int index(const Coord& p) const
00169 {
00170 Coord coefs;
00171 return index(p, coefs);
00172 }
00173
00174 int index(int x, int y, int z)
00175 {
00176 return x+nx*(y+ny*(z));
00177 }
00178
00179 Coord coord(int x, int y, int z)
00180 {
00181 return pmin+Coord(x*cellWidth[0], y*cellWidth[1], z*cellWidth[2]);
00182 }
00183
00184 Real operator[](int index) const { return dists[index]; }
00185 Real& operator[](int index) { return dists[index]; }
00186
00187 static Real interp(Real coef, Real a, Real b)
00188 {
00189 return a+coef*(b-a);
00190 }
00191
00192 Real interp(int index, const Coord& coefs) const
00193 {
00194 return interp(coefs[2],interp(coefs[1],interp(coefs[0],dists[index ],dists[index+1 ]),
00195 interp(coefs[0],dists[index +nx ],dists[index+1+nx ])),
00196 interp(coefs[1],interp(coefs[0],dists[index +nxny],dists[index+1 +nxny]),
00197 interp(coefs[0],dists[index +nx+nxny],dists[index+1+nx+nxny])));
00198 }
00199
00200 Real interp(const Coord& p) const
00201 {
00202 Coord coefs;
00203 int i = index(p, coefs);
00204 return interp(i, coefs);
00205 }
00206
00207 Coord grad(int index, const Coord& coefs) const
00208 {
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 const Real dist000 = dists[index ];
00222 const Real dist100 = dists[index+1 ];
00223 const Real dist010 = dists[index +nx ];
00224 const Real dist110 = dists[index+1+nx ];
00225 const Real dist001 = dists[index +nxny];
00226 const Real dist101 = dists[index+1 +nxny];
00227 const Real dist011 = dists[index +nx+nxny];
00228 const Real dist111 = dists[index+1+nx+nxny];
00229 return Coord(
00230 interp(coefs[2],interp(coefs[1],dist100-dist000,dist110-dist010),interp(coefs[1],dist101-dist001,dist111-dist011)),
00231 interp(coefs[2],interp(coefs[0],dist010-dist000,dist110-dist100),interp(coefs[0],dist011-dist001,dist111-dist101)),
00232 interp(coefs[1],interp(coefs[0],dist001-dist000,dist101-dist100),interp(coefs[0],dist011-dist010,dist111-dist110)));
00233 }
00234
00235 Coord grad(const Coord& p) const
00236 {
00237 Coord coefs;
00238 int i = index(p, coefs);
00239 return grad(i, coefs);
00240 }
00241
00242 Real eval(const Coord& x) const
00243 {
00244 Real d;
00245 if (inGrid(x))
00246 {
00247 d = interp(x);
00248 }
00249 else
00250 {
00251 Coord xclamp = clamp(x);
00252 d = interp(xclamp);
00253 d = helper::rsqrt((x-xclamp).norm2() + d*d);
00254 }
00255 return d;
00256 }
00257
00258 Real quickeval(const Coord& x) const
00259 {
00260 Real d;
00261 if (inGrid(x))
00262 {
00263 d = dists[index(x)] - cellWidth[0];
00264 }
00265 else
00266 {
00267 Coord xclamp = clamp(x);
00268 d = dists[index(xclamp)] - cellWidth[0];
00269 d = helper::rsqrt((x-xclamp).norm2() + d*d);
00270 }
00271 return d;
00272 }
00273
00274 Real eval2(const Coord& x) const
00275 {
00276 Real d2;
00277 if (inGrid(x))
00278 {
00279 Real d = interp(x);
00280 d2 = d*d;
00281 }
00282 else
00283 {
00284 Coord xclamp = clamp(x);
00285 Real d = interp(xclamp);
00286 d2 = ((x-xclamp).norm2() + d*d);
00287 }
00288 return d2;
00289 }
00290
00291 Real quickeval2(const Coord& x) const
00292 {
00293 Real d2;
00294 if (inGrid(x))
00295 {
00296 Real d = dists[index(x)] - cellWidth[0];
00297 d2 = d*d;
00298 }
00299 else
00300 {
00301 Coord xclamp = clamp(x);
00302 Real d = dists[index(xclamp)] - cellWidth[0];
00303 d2 = ((x-xclamp).norm2() + d*d);
00304 }
00305 return d2;
00306 }
00307
00308
00309 CudaVector<Coord> meshPts;
00310 sofa::core::componentmodel::topology::BaseMeshTopology::SeqTriangles meshTriangles;
00311 sofa::core::componentmodel::topology::BaseMeshTopology::SeqQuads meshQuads;
00312
00313 protected:
00314 int nbRef;
00315 VecReal dists;
00316 const int nx,ny,nz, nxny, nxnynz;
00317 const Coord pmin, pmax;
00318 const Coord cellWidth, invCellWidth;
00319 Coord bbmin, bbmax;
00320
00321 Real cubeDim;
00322
00323
00324
00325
00326 struct CudaDistanceGridParams
00327 {
00328 std::string filename;
00329 double scale;
00330 int nx,ny,nz;
00331 Coord pmin,pmax;
00332 bool operator==(const CudaDistanceGridParams& v) const
00333 {
00334 if (!(filename == v.filename)) return false;
00335 if (!(scale == v.scale )) return false;
00336 if (!(nx == v.nx )) return false;
00337 if (!(ny == v.ny )) return false;
00338 if (!(nz == v.nz )) return false;
00339 if (!(pmin[0] == v.pmin[0] )) return false;
00340 if (!(pmin[1] == v.pmin[1] )) return false;
00341 if (!(pmin[2] == v.pmin[2] )) return false;
00342 if (!(pmax[0] == v.pmax[0] )) return false;
00343 if (!(pmax[1] == v.pmax[1] )) return false;
00344 if (!(pmax[2] == v.pmax[2] )) return false;
00345 return true;
00346 }
00347 bool operator<(const CudaDistanceGridParams& v) const
00348 {
00349 if (filename < v.filename) return true;
00350 if (filename > v.filename) return false;
00351 if (scale < v.scale ) return true;
00352 if (scale > v.scale ) return false;
00353 if (nx < v.nx ) return false;
00354 if (nx > v.nx ) return true;
00355 if (ny < v.ny ) return false;
00356 if (ny > v.ny ) return true;
00357 if (nz < v.nz ) return false;
00358 if (nz > v.nz ) return true;
00359 if (pmin[0] < v.pmin[0] ) return false;
00360 if (pmin[0] > v.pmin[0] ) return true;
00361 if (pmin[1] < v.pmin[1] ) return false;
00362 if (pmin[1] > v.pmin[1] ) return true;
00363 if (pmin[2] < v.pmin[2] ) return false;
00364 if (pmin[2] > v.pmin[2] ) return true;
00365 if (pmax[0] < v.pmax[0] ) return false;
00366 if (pmax[0] > v.pmax[0] ) return true;
00367 if (pmax[1] < v.pmax[1] ) return false;
00368 if (pmax[1] > v.pmax[1] ) return true;
00369 if (pmax[2] < v.pmax[2] ) return false;
00370 if (pmax[2] > v.pmax[2] ) return true;
00371 return false;
00372 }
00373 bool operator>(const CudaDistanceGridParams& v) const
00374 {
00375 if (filename > v.filename) return true;
00376 if (filename < v.filename) return false;
00377 if (scale > v.scale ) return true;
00378 if (scale < v.scale ) return false;
00379 if (nx > v.nx ) return false;
00380 if (nx < v.nx ) return true;
00381 if (ny > v.ny ) return false;
00382 if (ny < v.ny ) return true;
00383 if (nz > v.nz ) return false;
00384 if (nz < v.nz ) return true;
00385 if (pmin[0] > v.pmin[0] ) return false;
00386 if (pmin[0] < v.pmin[0] ) return true;
00387 if (pmin[1] > v.pmin[1] ) return false;
00388 if (pmin[1] < v.pmin[1] ) return true;
00389 if (pmin[2] > v.pmin[2] ) return false;
00390 if (pmin[2] < v.pmin[2] ) return true;
00391 if (pmax[0] > v.pmax[0] ) return false;
00392 if (pmax[0] < v.pmax[0] ) return true;
00393 if (pmax[1] > v.pmax[1] ) return false;
00394 if (pmax[1] < v.pmax[1] ) return true;
00395 if (pmax[2] > v.pmax[2] ) return false;
00396 if (pmax[2] < v.pmax[2] ) return true;
00397 return false;
00398 }
00399 };
00400 static std::map<CudaDistanceGridParams, CudaDistanceGrid*>& getShared();
00401
00402 };
00406
00407 class CudaRigidDistanceGridCollisionModel;
00408
00409 class CudaRigidDistanceGridCollisionElement : public core::TCollisionElementIterator<CudaRigidDistanceGridCollisionModel>
00410 {
00411 public:
00412 CudaRigidDistanceGridCollisionElement(CudaRigidDistanceGridCollisionModel* model, int index);
00413
00414 explicit CudaRigidDistanceGridCollisionElement(const core::CollisionElementIterator& i);
00415
00416 CudaDistanceGrid* getGrid();
00417
00418 bool isTransformed();
00419 const Matrix3& getRotation();
00420 const Vector3& getTranslation();
00421
00422 void setGrid(CudaDistanceGrid* surf);
00423
00427 CudaDistanceGrid* getPrevGrid();
00428 const Matrix3& getPrevRotation();
00429 const Vector3& getPrevTranslation();
00430 double getPrevDt();
00432
00434 void setNewState(double dt, CudaDistanceGrid* grid, const Matrix3& rotation, const Vector3& translation);
00435 };
00436
00437 class CudaRigidDistanceGridCollisionModel : public core::CollisionModel
00438 {
00439 protected:
00440
00441 class ElementData
00442 {
00443 public:
00444 Matrix3 rotation;
00445 Vector3 translation;
00446 CudaDistanceGrid* grid;
00447
00451 CudaDistanceGrid* prevGrid;
00452 Matrix3 prevRotation;
00453 Vector3 prevTranslation;
00454 double prevDt;
00455
00456
00457 bool isTransformed;
00458 ElementData() : grid(NULL), prevGrid(NULL), prevDt(0.0), isTransformed(false) { rotation.identity(); prevRotation.identity(); }
00459 };
00460
00461 std::vector<ElementData> elems;
00462 bool modified;
00463
00464
00465 Data< std::string > filename;
00466 Data< double > scale;
00467 Data< helper::fixed_array<CudaDistanceGrid::Coord,2> > box;
00468 Data< int > nx;
00469 Data< int > ny;
00470 Data< int > nz;
00471 Data< std::string > dumpfilename;
00472
00473 core::componentmodel::behavior::MechanicalState<RigidTypes>* rigid;
00474
00475 void updateGrid();
00476 public:
00477 typedef Rigid3Types InDataTypes;
00478 typedef Vec3Types DataTypes;
00479 typedef CudaRigidDistanceGridCollisionElement Element;
00480
00481 Data< bool > usePoints;
00482
00483 CudaRigidDistanceGridCollisionModel();
00484
00485 ~CudaRigidDistanceGridCollisionModel();
00486
00487 core::componentmodel::behavior::MechanicalState<InDataTypes>* getRigidModel() { return rigid; }
00488 core::componentmodel::behavior::MechanicalState<InDataTypes>* getMechanicalState() { return rigid; }
00489
00490 void init();
00491
00492 CudaDistanceGrid* getGrid(int index=0)
00493 {
00494 return elems[index].grid;
00495 }
00496 bool isTransformed(int index=0)
00497 {
00498 return elems[index].isTransformed;
00499 }
00500 const Matrix3& getRotation(int index=0)
00501 {
00502 return elems[index].rotation;
00503 }
00504 const Vector3& getTranslation(int index=0)
00505 {
00506 return elems[index].translation;
00507 }
00508
00509 void setGrid(CudaDistanceGrid* surf, int index=0);
00510
00511 CudaDistanceGrid* getPrevGrid(int index=0)
00512 {
00513 return elems[index].prevGrid;
00514 }
00515 const Matrix3& getPrevRotation(int index=0)
00516 {
00517 return elems[index].prevRotation;
00518 }
00519 const Vector3& getPrevTranslation(int index=0)
00520 {
00521 return elems[index].prevTranslation;
00522 }
00523 double getPrevDt(int index=0)
00524 {
00525 return elems[index].prevDt;
00526 }
00527
00529 void setNewState(int index, double dt, CudaDistanceGrid* grid, const Matrix3& rotation, const Vector3& translation);
00530
00532
00534 void setNewState(double dt, CudaDistanceGrid* grid, const Matrix3& rotation, const Vector3& translation);
00535
00536
00537
00538 void resize(int size);
00539
00541 void computeBoundingTree(int maxDepth=0);
00542
00543 void draw(int index);
00544
00545 void draw();
00546 };
00547
00548 inline CudaRigidDistanceGridCollisionElement::CudaRigidDistanceGridCollisionElement(CudaRigidDistanceGridCollisionModel* model, int index)
00549 : core::TCollisionElementIterator<CudaRigidDistanceGridCollisionModel>(model, index)
00550 {}
00551
00552 inline CudaRigidDistanceGridCollisionElement::CudaRigidDistanceGridCollisionElement(const core::CollisionElementIterator& i)
00553 : core::TCollisionElementIterator<CudaRigidDistanceGridCollisionModel>(static_cast<CudaRigidDistanceGridCollisionModel*>(i.getCollisionModel()), i.getIndex())
00554 {
00555 }
00556
00557 inline CudaDistanceGrid* CudaRigidDistanceGridCollisionElement::getGrid() { return model->getGrid(index); }
00558 inline void CudaRigidDistanceGridCollisionElement::setGrid(CudaDistanceGrid* surf) { return model->setGrid(surf, index); }
00559
00560 inline bool CudaRigidDistanceGridCollisionElement::isTransformed() { return model->isTransformed(index); }
00561 inline const Matrix3& CudaRigidDistanceGridCollisionElement::getRotation() { return model->getRotation(index); }
00562 inline const Vector3& CudaRigidDistanceGridCollisionElement::getTranslation() { return model->getTranslation(index); }
00563
00564 inline CudaDistanceGrid* CudaRigidDistanceGridCollisionElement::getPrevGrid() { return model->getPrevGrid(index); }
00565 inline const Matrix3& CudaRigidDistanceGridCollisionElement::getPrevRotation() { return model->getPrevRotation(index); }
00566 inline const Vector3& CudaRigidDistanceGridCollisionElement::getPrevTranslation() { return model->getPrevTranslation(index); }
00567 inline double CudaRigidDistanceGridCollisionElement::getPrevDt() { return model->getPrevDt(index); }
00568
00569 inline void CudaRigidDistanceGridCollisionElement::setNewState(double dt, CudaDistanceGrid* grid, const Matrix3& rotation, const Vector3& translation)
00570 {
00571 return model->setNewState(dt, grid, rotation, translation);
00572 }
00573
00574 }
00575
00576 }
00577
00578 }
00579
00580 #endif