BruteForceDetection.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #include <sofa/component/collision/BruteForceDetection.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/core/ObjectFactory.h>
00032 #include <sofa/simulation/common/Node.h>
00033 #include <map>
00034 #include <queue>
00035 #include <stack>
00036 
00037 #include <sofa/helper/system/gl.h>
00038 #include <sofa/helper/system/glut.h>
00039 
00040 namespace sofa
00041 {
00042 
00043 namespace component
00044 {
00045 
00046 namespace collision
00047 {
00048 
00049 using namespace sofa::defaulttype;
00050 using namespace sofa::helper;
00051 using namespace collision;
00052 
00053 SOFA_DECL_CLASS(BruteForce)
00054 
00055 int BruteForceDetectionClass = core::RegisterObject("Collision detection using extensive pair-wise tests")
00056 .add< BruteForceDetection >()
00057 ;
00058 
00059 using namespace core::objectmodel;
00060 
00061 BruteForceDetection::BruteForceDetection()
00062 : bDraw(initData(&bDraw, false, "draw", "enable/disable display of results"))
00063 {
00064 }
00065 
00066 void BruteForceDetection::addCollisionModel(core::CollisionModel *cm)
00067 {
00068     if (cm->empty())
00069         return;
00070     if (cm->isSimulated() && cm->getLast()->canCollideWith(cm->getLast()))
00071     { // self collision
00072         //std::cout << "Test broad phase Self "<<cm->getLast()->getName()<<std::endl;
00073         bool swapModels = false;
00074         core::componentmodel::collision::ElementIntersector* intersector = intersectionMethod->findIntersector(cm, cm, swapModels);
00075         if (intersector != NULL)
00076             if (intersector->canIntersect(cm->begin(), cm->begin()))
00077             {
00078                 //std::cout << "Broad phase Self "<<cm->getLast()->getName()<<std::endl;
00079                 cmPairs.push_back(std::make_pair(cm, cm));
00080             }
00081     }
00082     for (sofa::helper::vector<core::CollisionModel*>::iterator it = collisionModels.begin(); it != collisionModels.end(); ++it)
00083     {
00084         core::CollisionModel* cm2 = *it;
00085         if (!cm->isSimulated() && !cm2->isSimulated())
00086             continue;
00087         if (!cm->canCollideWith(cm2))
00088             continue;
00089         if (!cm->getLast()->canCollideWith(cm2->getLast()))
00090             continue;
00091         bool swapModels = false;
00092         core::componentmodel::collision::ElementIntersector* intersector = intersectionMethod->findIntersector(cm, cm2, swapModels);
00093         if (intersector == NULL)
00094             continue;
00095         
00096         core::CollisionModel* cm1 = (swapModels?cm2:cm);
00097         cm2 = (swapModels?cm:cm2);
00098         
00099         // // Here we assume multiple root elements are present in both models
00100         // bool collisionDetected = false;
00101         // core::CollisionElementIterator begin1 = cm->begin();
00102         // core::CollisionElementIterator end1 = cm->end();
00103         // core::CollisionElementIterator begin2 = cm2->begin();
00104         // core::CollisionElementIterator end2 = cm2->end();
00105         // for (core::CollisionElementIterator it1 = begin1; it1 != end1; ++it1)
00106         // {
00107         //     for (core::CollisionElementIterator it2 = begin2; it2 != end2; ++it2)
00108         //     {
00109         //         //if (!it1->canCollideWith(it2)) continue;
00110         //         if (intersector->canIntersect(it1, it2))
00111         //         {
00112         //             collisionDetected = true;
00113         //             break;
00114         //         }
00115         //     }
00116         //     if (collisionDetected) break;
00117         // }
00118         // if (collisionDetected)
00119         
00120         // Here we assume a single root element is present in both models
00121         if (intersector->canIntersect(cm1->begin(), cm2->begin()))
00122         {
00123             //std::cout << "Broad phase "<<cm1->getLast()->getName()<<" - "<<cm2->getLast()->getName()<<std::endl;
00124             cmPairs.push_back(std::make_pair(cm1, cm2));
00125         }
00126     }
00127     collisionModels.push_back(cm);
00128 }
00129 
00130 class MirrorIntersector : public core::componentmodel::collision::ElementIntersector
00131 {
00132 public:
00133     core::componentmodel::collision::ElementIntersector* intersector;
00134     
00136     virtual bool canIntersect(core::CollisionElementIterator elem1, core::CollisionElementIterator elem2)
00137     {
00138         return intersector->canIntersect(elem2, elem1);
00139     }
00140     
00143     virtual int beginIntersect(core::CollisionModel* model1, core::CollisionModel* model2, core::componentmodel::collision::DetectionOutputVector*& contacts)
00144     {
00145         return intersector->beginIntersect(model2, model1, contacts);
00146     }
00147     
00149     virtual int intersect(core::CollisionElementIterator elem1, core::CollisionElementIterator elem2, core::componentmodel::collision::DetectionOutputVector* contacts)
00150     {
00151         return intersector->intersect(elem2, elem1, contacts);
00152     }
00153     
00155     virtual int endIntersect(core::CollisionModel* model1, core::CollisionModel* model2, core::componentmodel::collision::DetectionOutputVector* contacts)
00156     {
00157         return intersector->endIntersect(model2, model1, contacts);
00158     }
00159     
00160     virtual std::string name() const
00161     {
00162         return intersector->name() + std::string("<SWAP>");
00163     }
00164     
00165 };
00166     
00167 void BruteForceDetection::addCollisionPair(const std::pair<core::CollisionModel*, core::CollisionModel*>& cmPair)
00168 {
00169     typedef std::pair< std::pair<core::CollisionElementIterator,core::CollisionElementIterator>, std::pair<core::CollisionElementIterator,core::CollisionElementIterator> > TestPair;
00170 
00171     core::CollisionModel *cm1 = cmPair.first; //->getNext();
00172     core::CollisionModel *cm2 = cmPair.second; //->getNext();
00173     
00174     //int size0 = elemPairs.size();
00175     //std::cout << "Narrow phase "<<cm1->getLast()->getName()<<" - "<<cm2->getLast()->getName()<<std::endl;
00176 
00177     if (!cm1->isSimulated() && !cm2->isSimulated())
00178         return;
00179 
00180     if (cm1->empty() || cm2->empty())
00181         return;
00182 
00183     core::CollisionModel *finalcm1 = cm1->getLast();
00184     core::CollisionModel *finalcm2 = cm2->getLast();
00185     //std::cout << "Final phase "<<gettypename(typeid(*finalcm1))<<" - "<<gettypename(typeid(*finalcm2))<<std::endl;
00186     bool swapModels = false;
00187     core::componentmodel::collision::ElementIntersector* finalintersector = intersectionMethod->findIntersector(finalcm1, finalcm2, swapModels);
00188     if (finalintersector == NULL)
00189         return;
00190     if (swapModels)
00191     {
00192         core::CollisionModel* tmp;
00193         tmp = cm1; cm1 = cm2; cm2 = tmp;
00194         tmp = finalcm1; finalcm1 = finalcm2; finalcm2 = tmp;
00195     }
00196     
00197     const bool self = (finalcm1->getContext() == finalcm2->getContext());
00198     //if (self)
00199     //    std::cout << "SELF: Final intersector " << finalintersector->name() << " for "<<finalcm1->getName()<<" - "<<finalcm2->getName()<<std::endl;
00200     
00201     sofa::core::componentmodel::collision::DetectionOutputVector*& outputs = outputsMap[std::make_pair(finalcm1, finalcm2)];
00202 
00203     finalintersector->beginIntersect(finalcm1, finalcm2, outputs);
00204     
00205     if (finalcm1 == cm1 || finalcm2 == cm2)
00206     {
00207         // The last model also contains the root element -> it does not only contains the final level of the tree
00208         finalcm1 = NULL;
00209         finalcm2 = NULL;
00210         finalintersector = NULL;
00211     }
00212     simulation::Node* node = dynamic_cast<simulation::Node*>(getContext());
00213     if (node && !node->getLogTime()) node=NULL; // Only use node for time logging
00214     simulation::Node::ctime_t t0=0, t=0;
00215     simulation::Node::ctime_t ft=0;
00216 
00217     std::queue< TestPair > externalCells;
00218     
00219     std::pair<core::CollisionElementIterator,core::CollisionElementIterator> internalChildren1 = cm1->begin().getInternalChildren();
00220     std::pair<core::CollisionElementIterator,core::CollisionElementIterator> internalChildren2 = cm2->begin().getInternalChildren();
00221     std::pair<core::CollisionElementIterator,core::CollisionElementIterator> externalChildren1 = cm1->begin().getExternalChildren();
00222     std::pair<core::CollisionElementIterator,core::CollisionElementIterator> externalChildren2 = cm2->begin().getExternalChildren();
00223     if (internalChildren1.first != internalChildren1.second)
00224     {
00225         if (internalChildren2.first != internalChildren2.second)
00226             externalCells.push(std::make_pair(internalChildren1,internalChildren2));
00227         if (externalChildren2.first != externalChildren2.second)
00228             externalCells.push(std::make_pair(internalChildren1,externalChildren2));
00229     }
00230     if (externalChildren1.first != externalChildren1.second)
00231     {
00232         if (internalChildren2.first != internalChildren2.second)
00233             externalCells.push(std::make_pair(externalChildren1,internalChildren2));
00234         if (externalChildren2.first != externalChildren2.second)
00235             externalCells.push(std::make_pair(externalChildren1,externalChildren2));
00236     }
00237     //externalCells.push(std::make_pair(std::make_pair(cm1->begin(),cm1->end()),std::make_pair(cm2->begin(),cm2->end())));
00238 
00239     //core::componentmodel::collision::ElementIntersector* intersector = intersectionMethod->findIntersector(cm1, cm2);
00240     core::componentmodel::collision::ElementIntersector* intersector = NULL;
00241     MirrorIntersector mirror;
00242     cm1 = NULL; // force later init of intersector
00243     cm2 = NULL;
00244 
00245     while (!externalCells.empty())
00246     {
00247         TestPair root = externalCells.front();
00248         externalCells.pop();
00249 
00250         if (cm1 != root.first.first.getCollisionModel() || cm2 != root.second.first.getCollisionModel())
00251         {
00252             cm1 = root.first.first.getCollisionModel();
00253             cm2 = root.second.first.getCollisionModel();
00254             intersector = intersectionMethod->findIntersector(cm1, cm2, swapModels);
00255             if (intersector == NULL)
00256             {
00257                 std::cout << "BruteForceDetection: Error finding intersector " << intersectionMethod->getName() << " for "<<gettypename(typeid(*cm1))<<" - "<<gettypename(typeid(*cm2))<<std::endl;
00258             }
00259             //else std::cout << "BruteForceDetection: intersector " << intersector->name() << " for " << intersectionMethod->getName() << " for "<<gettypename(typeid(*cm1))<<" - "<<gettypename(typeid(*cm2))<<std::endl;
00260             if (swapModels)
00261             {
00262                 mirror.intersector = intersector; intersector = &mirror;
00263             }
00264         }
00265         if (intersector == NULL)
00266             continue;
00267         std::stack< TestPair > internalCells;
00268         internalCells.push(root);
00269         
00270         simulation::Node::ctime_t it=0,it0=0;
00271 
00272         if (node) it0 = node->startTime();
00273         while (!internalCells.empty())
00274         {
00275             TestPair current = internalCells.top();
00276             internalCells.pop();
00277 
00278             core::CollisionElementIterator begin1 = current.first.first;
00279             core::CollisionElementIterator end1 = current.first.second;
00280             core::CollisionElementIterator begin2 = current.second.first;
00281             core::CollisionElementIterator end2 = current.second.second;
00282 
00283             if (begin1.getCollisionModel() == finalcm1 && begin2.getCollisionModel() == finalcm2)
00284             {
00285                 // Final collision pairs
00286                 if (node) t0 = node->startTime();
00287                 for (core::CollisionElementIterator it1 = begin1; it1 != end1; ++it1)
00288                 {
00289                     for (core::CollisionElementIterator it2 = begin2; it2 != end2; ++it2)
00290                     {
00291                         if (!self || it1.canCollideWith(it2))
00292                             intersector->intersect(it1,it2,outputs);
00293                     }
00294                 }
00295             }
00296             else
00297             {
00298                 for (core::CollisionElementIterator it1 = begin1; it1 != end1; ++it1)
00299                 {
00300                     for (core::CollisionElementIterator it2 = begin2; it2 != end2; ++it2)
00301                     {
00302                         //if (self && !it1.canCollideWith(it2)) continue;
00303                         //if (!it1->canCollideWith(it2)) continue;
00304     
00305                         bool b = intersector->canIntersect(it1,it2);
00306                         if (b)
00307                         {
00308                             // Need to test recursively
00309                             // Note that an element cannot have both internal and external children
00310 
00311                             TestPair newInternalTests(it1.getInternalChildren(),it2.getInternalChildren());
00312                             TestPair newExternalTests(it1.getExternalChildren(),it2.getExternalChildren());
00313                             if (newInternalTests.first.first != newInternalTests.first.second)
00314                             {
00315                                 if (newInternalTests.second.first != newInternalTests.second.second)
00316                                 {
00317                                     internalCells.push(newInternalTests);
00318                                 }
00319                                 else
00320                                 {
00321                                     newInternalTests.second.first = it2;
00322                                     newInternalTests.second.second = it2;
00323                                     ++newInternalTests.second.second;
00324                                     internalCells.push(newInternalTests);
00325                                 }
00326                             }
00327                             else
00328                             {
00329                                 if (newInternalTests.second.first != newInternalTests.second.second)
00330                                 {
00331                                     newInternalTests.first.first = it1;
00332                                     newInternalTests.first.second = it1;
00333                                     ++newInternalTests.first.second;
00334                                     internalCells.push(newInternalTests);
00335                                 }
00336                                 else
00337                                 {
00338                                     // end of both internal tree of elements.
00339                                     // need to test external children
00340                                     if (newExternalTests.first.first != newExternalTests.first.second)
00341                                     {
00342                                         if (newExternalTests.second.first != newExternalTests.second.second)
00343                                         {
00344                                             if (newExternalTests.first.first.getCollisionModel() == finalcm1 && newExternalTests.second.first.getCollisionModel() == finalcm2)
00345                                             {
00346                                                 core::CollisionElementIterator begin1 = newExternalTests.first.first;
00347                                                 core::CollisionElementIterator end1 = newExternalTests.first.second;
00348                                                 core::CollisionElementIterator begin2 = newExternalTests.second.first;
00349                                                 core::CollisionElementIterator end2 = newExternalTests.second.second;
00350                                                 if (node) t0 = node->startTime();
00351                                                 for (core::CollisionElementIterator it1 = begin1; it1 != end1; ++it1)
00352                                                 {
00353                                                     for (core::CollisionElementIterator it2 = begin2; it2 != end2; ++it2)
00354                                                     {
00355                                                         //if (!it1->canCollideWith(it2)) continue;
00356                                                         // Final collision pair
00357                                                         if (!self || it1.canCollideWith(it2))
00358                                                             finalintersector->intersect(it1,it2,outputs);
00359                                                     }
00360                                                 }
00361                                                 if (node) ft += node->startTime() - t0;
00362                                             }
00363                                             else
00364                                                 externalCells.push(newExternalTests);
00365                                         }
00366                                         else
00367                                         {
00368                                             // only first element has external children
00369                                             // test them against the second element
00370                                             newExternalTests.second.first = it2;
00371                                             newExternalTests.second.second = it2;
00372                                             ++newExternalTests.second.second;
00373                                             externalCells.push(std::make_pair(newExternalTests.first, newInternalTests.second));
00374                                         }
00375                                     }
00376                                     else if (newExternalTests.second.first != newExternalTests.second.second)
00377                                     {
00378                                         // only first element has external children
00379                                         // test them against the first element
00380                                         newExternalTests.first.first = it1;
00381                                         newExternalTests.first.second = it1;
00382                                         ++newExternalTests.first.second;
00383                                         externalCells.push(std::make_pair(newExternalTests.first, newExternalTests.second));
00384                                     }
00385                                     else
00386                                     {
00387                                         // No child -> final collision pair
00388                                         if (!self || it1.canCollideWith(it2))
00389                                             intersector->intersect(it1,it2, outputs);
00390                                     }
00391                                 }
00392                             }
00393                         }
00394                     }
00395                 }
00396             }
00397         }
00398         if (node)
00399         {
00400             it += node->startTime() - it0 - ft;
00401             std::string name = "collision/";
00402             name += intersector->name();
00403             node->addTime(it, name, intersectionMethod);
00404             t += it;
00405         }
00406     }
00407     if (node && finalintersector!=NULL)
00408     {
00409         std::string name = "collision/";
00410         name += finalintersector->name();
00411         node->addTime(ft, name, intersectionMethod);
00412         t += ft;
00413         node->addTime(t, "collision", intersectionMethod, this);
00414     }
00415     //std::cout << "Narrow phase "<<cm1->getLast()->getName()<<"("<<gettypename(typeid(*cm1->getLast()))<<") - "<<cm2->getLast()->getName()<<"("<<gettypename(typeid(*cm2->getLast()))<<"): "<<elemPairs.size()-size0<<" contacts."<<std::endl;
00416 }
00417 
00418 void BruteForceDetection::draw()
00419 {
00420     if (!bDraw.getValue()) return;
00421 /*
00422     glDisable(GL_LIGHTING);
00423     glColor3f(1.0, 0.0, 1.0);
00424     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00425     glLineWidth(3);
00426     glPointSize(5);
00427 
00428     for (DetectionOutputMap::iterator it = outputsMap.begin(); it!=outputsMap.end(); it++)
00429     {
00430         core::componentmodel::collision::DetectionOutputVector& outputs = it->second;
00431         for (core::componentmodel::collision::DetectionOutputVector::iterator it2 = outputs.begin(); it2!=outputs.end(); it2++)
00432         {
00433             it2->elem.first.draw();
00434             it2->elem.second.draw();
00435         }
00436     }
00437     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00438     glLineWidth(1);
00439     glPointSize(1);
00440 */
00441 }
00442 
00443 } // namespace collision
00444 
00445 } // namespace component
00446 
00447 } // namespace sofa
00448 

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