CudaCollisionDetection.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 "CudaCollisionDetection.h"
00026 #include <sofa/core/ObjectFactory.h>
00027 
00028 namespace sofa
00029 {
00030 
00031 namespace gpu
00032 {
00033 
00034 namespace cuda
00035 {
00036 
00037 extern "C"
00038 {
00039 void CudaCollisionDetection_runTests(unsigned int nbTests, unsigned int maxPoints, const void* tests, void* nresults);
00040 }
00041 
00042 SOFA_DECL_CLASS(CudaCollisionDetection)
00043 
00044 int CudaCollisionDetectionClass = core::RegisterObject("GPU-based collision detection using CUDA")
00045 .add< CudaCollisionDetection >()
00046 ;
00047 
00048 void CudaCollisionDetection::beginNarrowPhase()
00049 {
00050     Inherit::beginNarrowPhase();
00051     for (TestMap::iterator it = tests.begin(), itend = tests.end(); it != itend; ++it)
00052         if (it->second.index >= 0)
00053             it->second.index = -1;
00054         else
00055             --it->second.index;
00056 }
00057 
00058 void CudaCollisionDetection::addCollisionPair( const std::pair<core::CollisionModel*, core::CollisionModel*>& cmPair )
00059 {
00060     core::CollisionModel *finalcm1 = cmPair.first->getLast();
00061     core::CollisionModel *finalcm2 = cmPair.second->getLast();
00062 
00063     Entry& entry = tests[std::make_pair(finalcm1, finalcm2)];
00064     if (entry.test == NULL)
00065     {
00066         entry.test = createTest(finalcm1, finalcm2);
00067     }
00068     entry.index = 0; // active pair
00069     //Inherit::addCollisionPair( cmPair );
00070 }
00071 
00072 void CudaCollisionDetection::endNarrowPhase()
00073 {
00074     // first clean up old pairs
00075     for (TestMap::iterator it = tests.begin(), itend = tests.end(); it != itend;)
00076         if (it->second.index < -100)
00077         {
00078             TestMap::iterator it2 = it;
00079             ++it;
00080             tests.erase(it2);
00081         }
00082         else ++it;
00083 
00084     // compute number of tests
00085     int ntests = 0;
00086     for (TestMap::iterator it = tests.begin(), itend = tests.end(); it != itend; ++it)
00087         if (it->second.index >= 0)
00088         {
00089             Test* test = it->second.test;
00090             if (test->useGPU())
00091             {
00092                 it->second.index = ntests;
00093                 ntests += test->init();
00094             }
00095         }
00096     //if (ntests>0)
00097     //std::cout << "CudaCollisionDetection: Launching "<<ntests<<"/"<<tests.size()<<" tests on GPU..."<<std::endl;
00098 
00099     if (ntests > 0)
00100     {
00101         // resize vectors
00102         gputests.fastResize(ntests);
00103         gpuresults.fastResize(ntests);
00104 
00105         // init tests
00106         for (TestMap::iterator it = tests.begin(), itend = tests.end(); it != itend; ++it)
00107             if (it->second.index >= 0)
00108             {
00109                 Test* test = it->second.test;
00110                 if (test->useGPU())
00111                 {
00112                     test->fillInfo(&gputests[it->second.index]);
00113                 }
00114             }
00115 
00116         // Launch GPU test
00117         int maxPoints = 0;
00118         for (int t=0;t<ntests;t++)
00119             if (gputests[t].nbPoints > maxPoints)
00120                 maxPoints = gputests[t].nbPoints;
00121         CudaCollisionDetection_runTests(ntests, maxPoints, gputests.deviceRead(), gpuresults.deviceWrite());
00122 
00123     }
00124 
00125     // compute CPU-side collisions
00126     for (TestMap::iterator it = tests.begin(), itend = tests.end(); it != itend; ++it)
00127         if (it->second.index >= 0)
00128         {
00129             Test* test = it->second.test;
00130             if (!test->useGPU())
00131             {
00132                 //core::CollisionModel* model1 = it->first.first;
00133                 //core::CollisionModel* model2 = it->first.second;
00134                 //for (core::CollisionElementIterator e1 = model1->begin(); e1 != model1->end(); ++e1)
00135                 //    for (core::CollisionElementIterator e2 = model2->begin(); e2 != model2->end(); ++e2)
00136                 //        Inherit::addCollisionPair( std::make_pair(e1, e2) );
00137                 core::CollisionModel *cm1 = it->first.first->getFirst(); //->getNext();
00138                 core::CollisionModel *cm2 = it->first.second->getFirst(); //->getNext();
00139                 Inherit::addCollisionPair( std::make_pair(cm1, cm2) );
00140             }
00141         }
00142 
00143     if (ntests > 0)
00144     {
00145         // gather gpu results
00146         const int* results = (const int*)gpuresults.hostRead();
00147         int total = 0;
00148         for (int i=0;i<ntests;i++)
00149             total += gpuresults[i];
00150         std::cout << "CudaCollisionDetection: GPU tests found "<<total<<" contacts."<<std::endl;
00151 
00152         for (TestMap::iterator it = tests.begin(), itend = tests.end(); it != itend; ++it)
00153             if (it->second.index >= 0)
00154             {
00155                 Test* test = it->second.test;
00156                 if (test->useGPU())
00157                 {
00158                     GPUOutputVector* tresults = &it->second.test->results;
00159                     this->outputsMap[it->first] = tresults;
00160                     int newIndex = 0;
00161                     for (unsigned int t=0;t<tresults->nbTests();t++)
00162                     {
00163                         tresults->wtest(t).curSize = results[it->second.index + t];
00164                         tresults->wtest(t).newIndex = newIndex;
00165                         newIndex += tresults->rtest(t).curSize;
00166                     }
00167                     //test->fillContacts(this->outputsMap[it->first], results+it->second.index);
00168                 }
00169             }
00170     }
00171 
00172     //Inherit::endNarrowPhase();
00173 
00174     DetectionOutputMap::iterator it = outputsMap.begin();
00175     while(it!=outputsMap.end())
00176     {
00177         if (!it->second || it->second->empty())
00178         {
00179             DetectionOutputMap::iterator it2 = it;
00180             ++it2;
00181             if (!dynamic_cast<GPUOutputVector*>(it->second))
00182                 delete it->second;
00183             outputsMap.erase(it);
00184             it = it2;
00185         }
00186         else
00187         {
00188             ++it;
00189         }
00190     }
00191 }
00192 
00193 
00194 CudaCollisionDetection::Test* CudaCollisionDetection::createTest(core::CollisionModel* model1, core::CollisionModel* model2)
00195 {
00196     if (CudaRigidDistanceGridCollisionModel* rigid1 = dynamic_cast<CudaRigidDistanceGridCollisionModel*>(model1))
00197     {
00198         if (CudaRigidDistanceGridCollisionModel* rigid2 = dynamic_cast<CudaRigidDistanceGridCollisionModel*>(model2))
00199             return new RigidRigidTest(rigid1, rigid2);
00200         else if (CudaSphereModel* sphere2 = dynamic_cast<CudaSphereModel*>(model2))
00201             return new SphereRigidTest(sphere2, rigid1);
00202         else if (CudaPointModel* point2 = dynamic_cast<CudaPointModel*>(model2))
00203             return new PointRigidTest(point2, rigid1);
00204     }
00205     else if (CudaSphereModel* sphere1 = dynamic_cast<CudaSphereModel*>(model1))
00206     {
00207         if (CudaRigidDistanceGridCollisionModel* rigid2 = dynamic_cast<CudaRigidDistanceGridCollisionModel*>(model2))
00208             return new SphereRigidTest(sphere1, rigid2);
00209     }
00210     else if (CudaPointModel* point1 = dynamic_cast<CudaPointModel*>(model1))
00211     {
00212         if (CudaRigidDistanceGridCollisionModel* rigid2 = dynamic_cast<CudaRigidDistanceGridCollisionModel*>(model2))
00213             return new PointRigidTest(point1, rigid2);
00214     }
00215     std::cout << "CudaCollisionDetection::CPUTest "<<model1->getClassName()<<" - "<<model2->getClassName()<<std::endl;
00216     return new CPUTest;
00217 }
00218 
00219 
00220 CudaCollisionDetection::RigidRigidTest::RigidRigidTest( CudaRigidDistanceGridCollisionModel* model1, CudaRigidDistanceGridCollisionModel* model2 )
00221 : model1(model1), model2(model2)
00222 {
00223     std::cout << "CudaCollisionDetection::RigidRigidTest "<<model1->getClassName()<<" - "<<model2->getClassName()<<std::endl;
00224 }
00225 
00227 int CudaCollisionDetection::RigidRigidTest::init()
00228 {
00229     results.clear();
00230     if (!model1->isActive() || !model2->isActive()) return 0;
00231     bool useP1 = model1->usePoints.getValue();
00232     bool useP2 = model2->usePoints.getValue();
00233     if (!useP1 && !useP2) return 0;
00234     int i0 = model1->getSize();
00235     for (CudaRigidDistanceGridCollisionElement e1 = CudaRigidDistanceGridCollisionElement(model1->begin()); e1!=model1->end();++e1)
00236         for (CudaRigidDistanceGridCollisionElement e2 = CudaRigidDistanceGridCollisionElement(model2->begin()); e2!=model2->end();++e2)
00237         {
00238             CudaDistanceGrid* g1 = e1.getGrid();
00239             CudaDistanceGrid* g2 = e2.getGrid();
00240             if (g1 && g2)
00241             {
00242                 if (useP1 && !g1->meshPts.empty()) results.addTest(std::make_pair(e1.getIndex(), i0+e2.getIndex()), g1->meshPts.size());
00243                 if (useP2 && !g2->meshPts.empty()) results.addTest(std::make_pair(i0+e2.getIndex(), e1.getIndex()), g2->meshPts.size());
00244             }
00245         }
00246     return results.nbTests();
00247 }
00248 
00250 void CudaCollisionDetection::RigidRigidTest::fillInfo(GPUTest* tests)
00251 {
00252     if (results.nbTests()==0) return;
00253     GPUContact* gresults = (GPUContact*)results.results.deviceWrite();
00254     int i0 = model1->getSize();
00255     for (unsigned int i=0;i<results.nbTests();i++)
00256     {
00257         const GPUOutputVector::TestEntry& e = results.rtest(i);
00258         GPUTest& test = tests[i];
00259         CudaRigidDistanceGridCollisionElement elem1((e.elems.first  < i0)?model1:model2,(e.elems.first  < i0)?e.elems.first :e.elems.first -i0);
00260         CudaRigidDistanceGridCollisionElement elem2((e.elems.second < i0)?model1:model2,(e.elems.second < i0)?e.elems.second:e.elems.second-i0);
00261         const CudaVector<Vec3f>& p1 = elem1.getGrid()->meshPts;
00262         CudaDistanceGrid& g2 = *elem2.getGrid();
00263         test.nbPoints = p1.size();
00264         test.result = gresults + e.firstIndex;
00265         test.points = p1.deviceRead();
00266         test.radius = NULL;
00267         test.gridnx = g2.getNx();
00268         test.gridny = g2.getNy();
00269         test.gridnz = g2.getNz();
00270         test.gridbbmin = g2.getBBMin();
00271         test.gridbbmax = g2.getBBMax();
00272         test.gridp0 = g2.getPMin();
00273         test.gridinvdp = g2.getInvCellWidth();
00274         test.grid = g2.getDists().deviceRead();
00275         test.margin = 0;
00276         test.rotation = elem2.getRotation().multTranspose(elem1.getRotation());
00277         test.translation = elem2.getRotation().multTranspose(elem1.getTranslation()-elem2.getTranslation());        
00278     }
00279 }
00280 /*
00282 void CudaCollisionDetection::RigidRigidTest::fillInfo(GPUTest& test, CudaVector<GPUContact>& gpucontacts, CudaRigidDistanceGridCollisionElement elem1, CudaRigidDistanceGridCollisionElement elem2)
00283 {
00284     const CudaVector<Vec3f>& p1 = elem1.getGrid()->meshPts;
00285     CudaDistanceGrid& g2 = *elem2.getGrid();
00286     test.nbPoints = p1.size();
00287     gpucontacts.fastResize(test.nbPoints);
00288     test.result = gpucontacts.deviceWrite();
00289     test.points = p1.deviceRead();
00290     test.radius = NULL;
00291     test.gridnx = g2.getNx();
00292     test.gridny = g2.getNy();
00293     test.gridnz = g2.getNz();
00294     test.gridbbmin = g2.getBBMin();
00295     test.gridbbmax = g2.getBBMax();
00296     test.gridp0 = g2.getPMin();
00297     test.gridinvdp = g2.getInvCellWidth();
00298     test.grid = g2.getDists().deviceRead();
00299     test.margin = 0;
00300     test.rotation = elem2.getRotation().multTranspose(elem1.getRotation());
00301     test.translation = elem2.getRotation().multTranspose(elem1.getTranslation()-elem2.getTranslation());
00302     gpucontacts.fastResize(test.nbPoints);
00303     test.result = gpucontacts.deviceWrite();
00304 }
00305 */
00306 /*
00308 void CudaCollisionDetection::RigidRigidTest::fillContacts(DetectionOutputVector& contacts, const int* nresults)
00309 {
00310     if (!model1->isActive() || !model2->isActive()) return;
00311     bool useP1 = model1->usePoints.getValue();
00312     bool useP2 = model2->usePoints.getValue();
00313     if (!useP1 && !useP2) return;
00314 
00315     int n = 0;
00316     for (CudaRigidDistanceGridCollisionElement e1 = CudaRigidDistanceGridCollisionElement(model1->begin()); e1!=model1->end();++e1)
00317         for (CudaRigidDistanceGridCollisionElement e2 = CudaRigidDistanceGridCollisionElement(model2->begin()); e2!=model2->end();++e2)
00318         {
00319             CudaDistanceGrid* g1 = e1.getGrid();
00320             CudaDistanceGrid* g2 = e2.getGrid();
00321             if (g1 && g2)
00322             {
00323                 if (useP1 && !g1->meshPts.empty())
00324                 {
00325                     if (n < (int)results.size() && results[n])
00326                         fillContacts(contacts, nresults[n], *results[n], e1, e2, false);
00327                     ++n;
00328                 }
00329                 if (useP2 && !g2->meshPts.empty())
00330                 {
00331                     if (n < (int)results.size() && results[n])
00332                         fillContacts(contacts, nresults[n], *results[n], e2, e1, true);
00333                     ++n;
00334                 }
00335             }
00336         }
00337 }
00338 
00339 void CudaCollisionDetection::RigidRigidTest::fillContacts(DetectionOutputVector& contacts, int nresults, CudaVector<GPUContact>& gpucontacts, CudaRigidDistanceGridCollisionElement elem1, CudaRigidDistanceGridCollisionElement elem2, bool invert)
00340 {
00341     if (!nresults) return;
00342     const CudaVector<Vec3f>& p1 = elem1.getGrid()->meshPts;
00343     CudaDistanceGrid& g2 = *elem2.getGrid();
00344     gpucontacts.fastResize(nresults);
00345     const GPUContact* gpuc = gpucontacts.hostRead();
00346     int c0 = contacts.size();
00347     contacts.resize(c0 + nresults);
00348     if (!invert)
00349     {
00350         for (int i=0; i<nresults; i++, gpuc++)
00351         {
00352             core::componentmodel::collision::DetectionOutput& detection = contacts[c0+i];
00353             detection.elem = std::make_pair(elem1, elem2);
00354             detection.distance = gpuc->distance;
00355             detection.normal = gpuc->normal;
00356             detection.point[0] = p1[gpuc->p1];
00357             detection.point[1] = gpuc->p2;
00358             detection.id = gpuc->p1;
00359         }
00360     }
00361     else
00362     {
00363         int id0 = g2.meshPts.size();
00364         for (int i=0; i<nresults; i++, gpuc++)
00365         {
00366             core::componentmodel::collision::DetectionOutput& detection = contacts[c0+i];
00367             detection.elem = std::make_pair(elem2, elem1);
00368             detection.distance = gpuc->distance;
00369             detection.normal = -gpuc->normal;
00370             detection.point[1] = p1[gpuc->p1];
00371             detection.point[0] = gpuc->p2;
00372             detection.id = id0+gpuc->p1;
00373         }
00374     }
00375 }
00376 */
00377 
00378 CudaCollisionDetection::SphereRigidTest::SphereRigidTest( CudaSphereModel* model1, CudaRigidDistanceGridCollisionModel* model2 )
00379 : model1(model1), model2(model2)
00380 {
00381     std::cout << "CudaCollisionDetection::SphereRigidTest "<<model1->getClassName()<<" - "<<model2->getClassName()<<std::endl;
00382 }
00383 
00384 
00386 int CudaCollisionDetection::SphereRigidTest::init()
00387 {
00388     results.clear();
00389     if (!model1->isActive() || !model2->isActive()) return 0;
00390     const CudaVector<Vec3f>& p1 = *model1->getMechanicalState()->getX();
00391     if (p1.empty()) return 0;
00392 
00393     for (CudaRigidDistanceGridCollisionElement e2 = CudaRigidDistanceGridCollisionElement(model2->begin()); e2!=model2->end();++e2)
00394     {
00395         CudaDistanceGrid* g2 = e2.getGrid();
00396         if (g2)
00397             results.addTest(std::make_pair(0, e2.getIndex()), p1.size());
00398     }
00399     return results.nbTests();
00400 }
00401 
00403 void CudaCollisionDetection::SphereRigidTest::fillInfo(GPUTest* tests)
00404 {
00405     if (results.nbTests()==0) return;
00406     GPUContact* gresults = (GPUContact*)results.results.deviceWrite();
00407     const CudaVector<Vec3f>& p1 = *model1->getMechanicalState()->getX();
00408     for (unsigned int i=0;i<results.nbTests();i++)
00409     {
00410         const GPUOutputVector::TestEntry& e = results.rtest(i);
00411         GPUTest& test = tests[i];
00412         //CudaRigidDistanceGridCollisionElement elem1((e.elems.first  < i0)?model1:model2,(e.elems.first  < i0)?e.elems.first :e.elems.first -i0);
00413         CudaRigidDistanceGridCollisionElement elem2(model2, e.elems.second);
00414         CudaDistanceGrid* g2 = elem2.getGrid();
00415         test.nbPoints = p1.size();
00416         test.result = gresults + e.firstIndex;
00417         test.points = p1.deviceRead();
00418         test.radius = model1->getR().deviceRead();
00419         test.grid = g2->getDists().deviceRead();
00420         test.gridnx = g2->getNx();
00421         test.gridny = g2->getNy();
00422         test.gridnz = g2->getNz();
00423         test.gridbbmin = g2->getBBMin();
00424         test.gridbbmax = g2->getBBMax();
00425         test.gridp0 = g2->getPMin();
00426         test.gridinvdp = g2->getInvCellWidth();
00427         test.margin = 0; //model1->getRadius(0);
00428         test.rotation.transpose(Mat3x3f(elem2.getRotation()));
00429         test.translation = test.rotation*(-elem2.getTranslation());
00430     }
00431 }
00432 
00433 /*
00435 void CudaCollisionDetection::SphereRigidTest::fillContacts(DetectionOutputVector& contacts, const int* nresults)
00436 {
00437     if (!model1->isActive() || !model2->isActive()) return;
00438     const CudaVector<Vec3f>& p1 = *model1->getMechanicalState()->getX();
00439     if (p1.empty()) return;
00440 
00441     int n = 0;
00442     for (CudaRigidDistanceGridCollisionElement elem2 = CudaRigidDistanceGridCollisionElement(model2->begin()); elem2!=model2->end(); ++elem2)
00443     {
00444         CudaDistanceGrid* g2 = elem2.getGrid();
00445         if (g2)
00446         {
00447             if (n < (int)results.size() && results[n])
00448             {
00449                 CudaVector<GPUContact>& gpucontacts = *results[n];
00450                 int nr = nresults[n];
00451                 if (nr)
00452                 {
00453                     gpucontacts.fastResize(nr);
00454                     const GPUContact* gpuc = gpucontacts.hostRead();
00455                     int c0 = contacts.size();
00456                     contacts.resize(c0 + nr);
00457                     for (int i=0; i<nr; i++, gpuc++)
00458                     {
00459                         core::componentmodel::collision::DetectionOutput& detection = contacts[c0+i];
00460                         detection.elem = std::make_pair(CudaSphere(model1, gpuc->p1), elem2);
00461                         detection.distance = gpuc->distance;
00462                         detection.normal = gpuc->normal;
00463                         detection.point[0] = p1[gpuc->p1];
00464                         detection.point[1] = gpuc->p2;
00465                         detection.id = gpuc->p1;
00466                         std::cout << "GPU c"<<i<<": p1 = "<<gpuc->p1<<"  p2 = "<<gpuc->p2<<"  normal = "<<gpuc->normal<<"  distance = "<<gpuc->distance<<"\n";
00467                     }
00468                 }
00469             }
00470             ++n;
00471         }
00472     }
00473 }
00474 */
00475 
00476 CudaCollisionDetection::PointRigidTest::PointRigidTest( CudaPointModel* model1, CudaRigidDistanceGridCollisionModel* model2 )
00477 : model1(model1), model2(model2)
00478 {
00479     std::cout << "CudaCollisionDetection::PointRigidTest "<<model1->getClassName()<<" - "<<model2->getClassName()<<std::endl;
00480 }
00481 
00483 int CudaCollisionDetection::PointRigidTest::init()
00484 {
00485     results.clear();
00486     if (!model1->isActive() || !model2->isActive()) return 0;
00487     for (CudaPoint e1 = CudaPoint(model1->begin()); e1!=model1->end();++e1)
00488         for (CudaRigidDistanceGridCollisionElement e2 = CudaRigidDistanceGridCollisionElement(model2->begin()); e2!=model2->end();++e2)
00489         {
00490             //CudaDistanceGrid* g1 = e1.getGrid();
00491             CudaDistanceGrid* g2 = e2.getGrid();
00492             if (g2)
00493                 results.addTest(std::make_pair(e1.getIndex(), e2.getIndex()), e1.getSize());
00494         }
00495     return results.nbTests();
00496 }
00497 
00499 void CudaCollisionDetection::PointRigidTest::fillInfo(GPUTest* tests)
00500 {
00501     if (results.nbTests()==0) return;
00502     GPUContact* gresults = (GPUContact*)results.results.deviceWrite();
00503     for (unsigned int i=0;i<results.nbTests();i++)
00504     {
00505         const GPUOutputVector::TestEntry& e = results.rtest(i);
00506         GPUTest& test = tests[i];
00507         CudaPoint elem1(model1, e.elems.first);
00508         CudaRigidDistanceGridCollisionElement elem2(model2,e.elems.second);
00509         const CudaVector<Vec3f>& p1 = *model1->getMechanicalState()->getX();
00510         CudaDistanceGrid& g2 = *elem2.getGrid();
00511         test.nbPoints = elem1.getSize();
00512         test.result = gresults + e.firstIndex;
00513         test.points = p1.deviceRead(elem1.i0());
00514         test.radius = NULL;
00515         test.gridnx = g2.getNx();
00516         test.gridny = g2.getNy();
00517         test.gridnz = g2.getNz();
00518         test.gridbbmin = g2.getBBMin();
00519         test.gridbbmax = g2.getBBMax();
00520         test.gridp0 = g2.getPMin();
00521         test.gridinvdp = g2.getInvCellWidth();
00522         test.grid = g2.getDists().deviceRead();
00523         test.margin = 0;
00524         test.rotation.transpose(elem2.getRotation());
00525         test.translation = elem2.getRotation().multTranspose(-elem2.getTranslation());
00526     }
00527 }
00528 
00529 } // namespace cuda
00530 
00531 } // namespace gpu
00532 
00533 } // namespace sofa

Generated on Sun Nov 23 03:57:23 2008 for Sofa by  doxygen 1.5.7.1