DefaultCollisionGroupManager.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/DefaultCollisionGroupManager.h>
00026 #include <sofa/core/CollisionModel.h>
00027 #include <sofa/helper/system/config.h>
00028 #include <sofa/helper/FnDispatcher.h>
00029 #include <sofa/helper/FnDispatcher.inl>
00030 #include <sofa/component/collision/DefaultCollisionGroupManager.h>
00031 #include <sofa/component/odesolver/EulerSolver.h>
00032 #include <sofa/component/odesolver/RungeKutta4Solver.h>
00033 #include <sofa/component/odesolver/CGImplicitSolver.h>
00034 #include <sofa/component/odesolver/StaticSolver.h>
00035 #include <sofa/component/odesolver/EulerImplicitSolver.h>
00036 #include <sofa/component/linearsolver/CGLinearSolver.h>
00037 #include <sofa/core/ObjectFactory.h>
00038 #include <string.h>
00039 #include <sofa/simulation/tree/GNode.h>
00040 
00041 
00042 namespace sofa
00043 {
00044 
00045 namespace component
00046 {
00047 
00048 namespace collision
00049 {
00050 
00051 using namespace sofa::defaulttype;
00052 using namespace sofa::helper;
00053 using namespace core::componentmodel::behavior;
00054 using namespace core::componentmodel::collision;
00055 
00056 SOFA_DECL_CLASS(DefaultCollisionGroupManager);
00057 
00058 int DefaultCollisionGroupManagerClass = core::RegisterObject("Responsible for gathering colliding objects in the same group, for consistent time integration")
00059 .add< DefaultCollisionGroupManager >()
00060 .addAlias("CollisionGroup")
00061 ;
00062 
00063 typedef std::pair<OdeSolver*,LinearSolver*> SolverSet;
00064 
00065 class SolverMerger
00066 {
00067 public:
00068     static SolverSet merge(core::componentmodel::behavior::OdeSolver* solver1, core::componentmodel::behavior::OdeSolver* solver2);
00069 
00070 protected:
00071     
00072     FnDispatcher<core::componentmodel::behavior::OdeSolver, SolverSet> solverDispatcher;
00073 
00074     SolverMerger ();
00075 };
00076 
00077 DefaultCollisionGroupManager::DefaultCollisionGroupManager()
00078 {
00079 }
00080 
00081 DefaultCollisionGroupManager::~DefaultCollisionGroupManager()
00082 {
00083 }
00084 
00085 simulation::tree::GNode* DefaultCollisionGroupManager::buildCollisionGroup() {
00086     return new simulation::tree::GNode;
00087 }
00088 
00089 void DefaultCollisionGroupManager::createGroups(core::objectmodel::BaseContext* scene, const sofa::helper::vector<Contact*>& contacts)
00090 {
00091     int groupIndex = 1;
00092     simulation::tree::GNode* groot = dynamic_cast<simulation::tree::GNode*>(scene);
00093     if (groot==NULL)
00094     {
00095         std::cerr << "DefaultCollisionGroupManager only support graph-based scenes.\n";
00096         return;
00097     }
00098     
00099     simulation::tree::GNode* node = groot;
00100     if (node && !node->getLogTime()) node=NULL; // Only use node for time logging
00101     simulation::tree::GNode::ctime_t t0 = 0;
00102 
00103     if (node) t0 = node->startTime();
00104 
00105     // Map storing group merging history
00106     std::map<simulation::tree::GNode*, simulation::tree::GNode*> mergedGroups;
00107     sofa::helper::vector<simulation::tree::GNode*> contactGroup;
00108     sofa::helper::vector<simulation::tree::GNode*> removedGroup;
00109     contactGroup.reserve(contacts.size());
00110     for(sofa::helper::vector<Contact*>::const_iterator cit = contacts.begin(); cit != contacts.end(); cit++)
00111     {
00112         Contact* contact = *cit;
00113         simulation::tree::GNode* group1 = getIntegrationNode(contact->getCollisionModels().first);
00114         simulation::tree::GNode* group2 = getIntegrationNode(contact->getCollisionModels().second);
00115         simulation::tree::GNode* group = NULL;
00116         if (group1==NULL || group2==NULL)
00117         {
00118         }
00119         else if (group1 == group2)
00120         {
00121             // same group, no new group necessary
00122             group = group1;
00123         }
00124         else if (group1->getParent()!=NULL && group1->getParent() == group2->getParent())
00125         {
00126             // we can merge the groups
00127             // if solvers are compatible...
00128             SolverSet solver = SolverMerger::merge(group1->solver[0], group2->solver[0]);
00129             if (solver.first!=NULL)
00130             {
00131                 simulation::tree::GNode* parent = group1->parent;
00132                 bool group1IsColl = groupSet.find(group1)!=groupSet.end();
00133                 bool group2IsColl = groupSet.find(group2)!=groupSet.end();
00134                 if (!group1IsColl && !group2IsColl)
00135                 {
00136                     char groupName[32];
00137                     snprintf(groupName,sizeof(groupName),"collision%d",groupIndex++);
00138                     // create a new group
00139                     group = buildCollisionGroup();
00140                     group->setName(groupName);
00141                     parent->addChild(group); 
00142                     
00143                     core::objectmodel::Context *current_context = dynamic_cast< core::objectmodel::Context *>(parent->getContext());
00144                     group->copyVisualContext( (*current_context));
00145 
00146                     group->updateSimulationContext();
00147                     group->moveChild(group1);
00148                     group->moveChild(group2);
00149                     groupSet.insert(group);
00150                 }
00151                 else if (group1IsColl)
00152                 {
00153                     group = group1;
00154                     // merge group2 in group1
00155                     if (!group2IsColl)
00156                     {
00157                         group->moveChild(group2);
00158                     }
00159                     else
00160                     {
00161                         // merge groups and remove group2
00162                         SolverSet solver2;
00163                         solver2.first = group2->solver[0];
00164                         group2->removeObject(solver2.first);
00165                         if (!group2->linearSolver.empty())
00166                         {
00167                         solver2.second = group2->linearSolver[0];
00168                         group2->removeObject(solver2.second);
00169                         }
00170                         else
00171                         solver2.second = NULL;
00172                         while(!group2->object.empty())
00173                             group->moveObject(*group2->object.begin());
00174                         while(!group2->child.empty())
00175                             group->moveChild(*group2->child.begin());
00176                         parent->removeChild(group2);
00177                         groupSet.erase(group2);
00178                         mergedGroups[group2] = group;
00179                         delete solver2.first;
00180                         if (solver2.second) delete solver2.second;
00181                         // BUGFIX(2007-06-23 Jeremie A): we can't remove group2 yet, to make sure the keys in mergedGroups are unique.
00182                         removedGroup.push_back(group2);
00183                         //delete group2;
00184                     }
00185                 }
00186                 else
00187                 {
00188                     // group1 is not a collision group while group2 is
00189                     group = group2;
00190                     group->moveChild(group1);
00191                 }
00192                                 if (!group->solver.empty())
00193                 {
00194                     OdeSolver* solver2 = group->solver[0];
00195                     group->removeObject(solver2);
00196                     delete solver2;
00197                 }
00198                                 if (!group->linearSolver.empty())
00199                 {
00200                     LinearSolver* solver2 = group->linearSolver[0];
00201                     group->removeObject(solver2);
00202                     delete solver2;
00203                 }
00204                 group->addObject(solver.first);
00205                 if (solver.second)
00206                     group->addObject(solver.second);
00207             }
00208         }
00209         contactGroup.push_back(group);
00210     }
00211     
00212     if (node) t0 = node->endTime(t0, "collision/groups", this);
00213     
00214     // now that the groups are final, attach contacts' response
00215     for(unsigned int i=0;i<contacts.size();i++)
00216     {
00217         Contact* contact = contacts[i];
00218         simulation::tree::GNode* group = contactGroup[i];
00219         while (group!=NULL && mergedGroups.find(group)!=mergedGroups.end())
00220             group = mergedGroups[group];
00221         if (group!=NULL)
00222             contact->createResponse(group);
00223         else
00224             contact->createResponse(scene);
00225     }
00226     
00227     if (node) t0 = node->endTime(t0, "collision/contacts", this);
00228     
00229     // delete removed groups
00230     for (sofa::helper::vector<simulation::tree::GNode*>::iterator it = removedGroup.begin(); it!=removedGroup.end(); ++it)
00231         delete *it;
00232     removedGroup.clear();
00233     
00234     // finally recreate group vector
00235     groups.clear();
00236     for (std::set<simulation::tree::GNode*>::iterator it = groupSet.begin(); it!=groupSet.end(); ++it)
00237         groups.push_back(*it);
00238     //if (!groups.empty())
00239     //  std::cout << groups.size()<<" collision groups created."<<std::endl;
00240 }
00241 
00242 void DefaultCollisionGroupManager::clearGroups(core::objectmodel::BaseContext* /*scene*/)
00243 {
00244     for (std::set<simulation::tree::GNode*>::iterator it = groupSet.begin(); it!=groupSet.end(); ++it)
00245     {
00246         simulation::tree::GNode* group = *it;
00247         simulation::tree::GNode* parent = group->parent;
00248         while(!group->child.empty())
00249             parent->moveChild(*group->child.begin());
00250         while(!group->object.empty())
00251         {
00252             core::objectmodel::BaseObject* obj = *group->object.begin();
00253             group->removeObject(obj);
00254             delete obj;
00255         }
00256         parent->removeChild(group);
00257         delete group;
00258     }
00259 
00260     groupSet.clear();
00261     groups.clear();
00262 }
00263 
00264 simulation::tree::GNode* DefaultCollisionGroupManager::getIntegrationNode(core::CollisionModel* model)
00265 {
00266     simulation::tree::GNode* node = dynamic_cast<simulation::tree::GNode*>(model->getContext());
00267     simulation::tree::GNode* lastSolver = NULL;
00268     while (node!=NULL)
00269     {
00270         if (!node->solver.empty()) lastSolver = node;
00271         node = node->parent;
00272     }
00273     return lastSolver;
00274 }
00275 
00276 // Sylvere F. : change the name of function, because under Visual C++ it doesn't compile
00277 
00278 // Jeremie A. : put the methods inside a namespace instead of a class,
00279 // for g++ 3.4 compatibility
00280 
00281 namespace SolverMergers
00282 {
00283 
00284 // First the easy cases...
00285 
00286 SolverSet createSolverEulerEuler(odesolver::EulerSolver& solver1, odesolver::EulerSolver& /*solver2*/)
00287 {
00288     return SolverSet(new odesolver::EulerSolver(solver1), NULL);
00289 }
00290 
00291 SolverSet createSolverRungeKutta4RungeKutta4(odesolver::RungeKutta4Solver& solver1, odesolver::RungeKutta4Solver& /*solver2*/)
00292 {
00293     return SolverSet(new odesolver::RungeKutta4Solver(solver1), NULL);
00294 }
00295 
00296 SolverSet createSolverCGImplicitCGImplicit(odesolver::CGImplicitSolver& solver1, odesolver::CGImplicitSolver& solver2)
00297 {
00298     odesolver::CGImplicitSolver* solver = new odesolver::CGImplicitSolver;
00299     solver->f_maxIter.setValue( solver1.f_maxIter.getValue() > solver2.f_maxIter.getValue() ? solver1.f_maxIter.getValue() : solver2.f_maxIter.getValue() );
00300     solver->f_tolerance.setValue( solver1.f_tolerance.getValue() < solver2.f_tolerance.getValue() ? solver1.f_tolerance.getValue() : solver2.f_tolerance.getValue());
00301     solver->f_smallDenominatorThreshold.setValue( solver1.f_smallDenominatorThreshold.getValue() < solver2.f_smallDenominatorThreshold.getValue() ? solver1.f_smallDenominatorThreshold.getValue() : solver2.f_smallDenominatorThreshold.getValue());
00302     
00303     solver->f_rayleighStiffness.setValue( solver1.f_rayleighStiffness.getValue() < solver2.f_rayleighStiffness.getValue() ? solver1.f_rayleighStiffness.getValue() : solver2.f_rayleighStiffness.getValue() );
00304     
00305     solver->f_rayleighMass.setValue( solver1.f_rayleighMass.getValue() < solver2.f_rayleighMass.getValue() ? solver1.f_rayleighMass.getValue() : solver2.f_rayleighMass.getValue() );
00306     solver->f_velocityDamping.setValue( solver1.f_velocityDamping.getValue() > solver2.f_velocityDamping.getValue() ? solver1.f_velocityDamping.getValue() : solver2.f_velocityDamping.getValue());
00307     return SolverSet(solver, NULL);
00308 }
00309 
00310 typedef linearsolver::CGLinearSolver<simulation::GraphScatteredMatrix,simulation::GraphScatteredVector> DefaultCGLinearSolver;
00311 
00312 LinearSolver* createLinearSolver(OdeSolver* solver1, OdeSolver* solver2)
00313 {
00314     DefaultCGLinearSolver* lsolver = new DefaultCGLinearSolver;
00315     DefaultCGLinearSolver* lsolver1 = NULL; if (solver1!=NULL) solver1->getContext()->get(lsolver1, core::objectmodel::BaseContext::SearchDown);
00316     DefaultCGLinearSolver* lsolver2 = NULL; if (solver2!=NULL) solver2->getContext()->get(lsolver2, core::objectmodel::BaseContext::SearchDown);
00317     unsigned int maxIter = 0;
00318     double tolerance = 1.0e10;
00319     double smallDenominatorThreshold = 1.0e10;
00320     if (lsolver1)
00321     {
00322     if (lsolver1->f_maxIter.getValue() > maxIter) maxIter = lsolver1->f_maxIter.getValue();
00323     if (lsolver1->f_tolerance.getValue() < tolerance) tolerance = lsolver1->f_tolerance.getValue();
00324     if (lsolver1->f_smallDenominatorThreshold.getValue() > smallDenominatorThreshold) smallDenominatorThreshold = lsolver1->f_smallDenominatorThreshold.getValue();
00325     }
00326     if (lsolver2)
00327     {
00328     if (lsolver2->f_maxIter.getValue() > maxIter) maxIter = lsolver2->f_maxIter.getValue();
00329     if (lsolver2->f_tolerance.getValue() < tolerance) tolerance = lsolver2->f_tolerance.getValue();
00330     if (lsolver2->f_smallDenominatorThreshold.getValue() > smallDenominatorThreshold) smallDenominatorThreshold = lsolver2->f_smallDenominatorThreshold.getValue();
00331     }
00332     if (maxIter > 0) lsolver->f_maxIter.setValue( maxIter );
00333     if (tolerance < 1.0e10) lsolver->f_tolerance.setValue( tolerance );
00334     if (smallDenominatorThreshold < 1.0e10) lsolver->f_smallDenominatorThreshold.setValue( smallDenominatorThreshold );
00335     return lsolver;
00336 }
00337 
00338 SolverSet createSolverEulerImplicitEulerImplicit(odesolver::EulerImplicitSolver& solver1, odesolver::EulerImplicitSolver& solver2)
00339 {
00340     odesolver::EulerImplicitSolver* solver = new odesolver::EulerImplicitSolver;
00341     solver->f_rayleighStiffness.setValue( solver1.f_rayleighStiffness.getValue() < solver2.f_rayleighStiffness.getValue() ? solver1.f_rayleighStiffness.getValue() : solver2.f_rayleighStiffness.getValue() );
00342     
00343     solver->f_rayleighMass.setValue( solver1.f_rayleighMass.getValue() < solver2.f_rayleighMass.getValue() ? solver1.f_rayleighMass.getValue() : solver2.f_rayleighMass.getValue() );
00344     solver->f_velocityDamping.setValue( solver1.f_velocityDamping.getValue() > solver2.f_velocityDamping.getValue() ? solver1.f_velocityDamping.getValue() : solver2.f_velocityDamping.getValue());
00345     return SolverSet(solver, createLinearSolver(&solver1, &solver2));
00346 }
00347 
00348 SolverSet createSolverStaticSolver(odesolver::StaticSolver& solver1, odesolver::StaticSolver& solver2)
00349 {
00350     return SolverSet(new odesolver::StaticSolver(solver1), createLinearSolver(&solver1, &solver2));
00351 }
00352 
00353 // Then the other, with the policy of taking the more precise solver
00354 
00355 SolverSet createSolverRungeKutta4Euler(odesolver::RungeKutta4Solver& solver1, odesolver::EulerSolver& /*solver2*/)
00356 {
00357     return SolverSet(new odesolver::RungeKutta4Solver(solver1), NULL);
00358 }
00359 
00360 SolverSet createSolverCGImplicitEuler(odesolver::CGImplicitSolver& solver1, odesolver::EulerSolver& /*solver2*/)
00361 {
00362     return SolverSet(new odesolver::CGImplicitSolver(solver1), NULL);
00363 }
00364 
00365 SolverSet createSolverCGImplicitRungeKutta4(odesolver::CGImplicitSolver& solver1, odesolver::RungeKutta4Solver& /*solver2*/)
00366 {
00367     return SolverSet(new odesolver::CGImplicitSolver(solver1), NULL);
00368 }
00369 
00370 SolverSet createSolverEulerImplicitEuler(odesolver::EulerImplicitSolver& solver1, odesolver::EulerSolver& /*solver2*/)
00371 {
00372     return SolverSet(new odesolver::EulerImplicitSolver(solver1), createLinearSolver(&solver1, NULL));
00373 }
00374 
00375 SolverSet createSolverEulerImplicitRungeKutta4(odesolver::EulerImplicitSolver& solver1, odesolver::RungeKutta4Solver& /*solver2*/)
00376 {
00377     return SolverSet(new odesolver::EulerImplicitSolver(solver1), createLinearSolver(&solver1, NULL));
00378 }
00379 
00380 SolverSet createSolverEulerImplicitCGImplicit(odesolver::EulerImplicitSolver& solver1, odesolver::CGImplicitSolver& /*solver2*/)
00381 {
00382     return SolverSet(new odesolver::EulerImplicitSolver(solver1), createLinearSolver(&solver1, NULL));
00383 }
00384 
00385 } // namespace SolverMergers
00386 
00387 
00388 using namespace SolverMergers;
00389 
00390 SolverSet SolverMerger::merge(core::componentmodel::behavior::OdeSolver* solver1, core::componentmodel::behavior::OdeSolver* solver2)
00391 {
00392     static SolverMerger instance;
00393     return instance.solverDispatcher.go(*solver1, *solver2);
00394 }
00395 
00396 SolverMerger::SolverMerger()
00397 {
00398     solverDispatcher.add<odesolver::EulerSolver,odesolver::EulerSolver,createSolverEulerEuler,false>();
00399     solverDispatcher.add<odesolver::RungeKutta4Solver,odesolver::RungeKutta4Solver,createSolverRungeKutta4RungeKutta4,false>();
00400     solverDispatcher.add<odesolver::CGImplicitSolver,odesolver::CGImplicitSolver,createSolverCGImplicitCGImplicit,false>();
00401     solverDispatcher.add<odesolver::EulerImplicitSolver,odesolver::EulerImplicitSolver,createSolverEulerImplicitEulerImplicit,false>();
00402     solverDispatcher.add<odesolver::RungeKutta4Solver,odesolver::EulerSolver,createSolverRungeKutta4Euler,true>();
00403     solverDispatcher.add<odesolver::CGImplicitSolver,odesolver::EulerSolver,createSolverCGImplicitEuler,true>();
00404     solverDispatcher.add<odesolver::CGImplicitSolver,odesolver::RungeKutta4Solver,createSolverCGImplicitRungeKutta4,true>();
00405     solverDispatcher.add<odesolver::EulerImplicitSolver,odesolver::EulerSolver,createSolverEulerImplicitEuler,true>();
00406     solverDispatcher.add<odesolver::EulerImplicitSolver,odesolver::RungeKutta4Solver,createSolverEulerImplicitRungeKutta4,true>();
00407     solverDispatcher.add<odesolver::EulerImplicitSolver,odesolver::CGImplicitSolver,createSolverEulerImplicitCGImplicit,true>();
00408     solverDispatcher.add<odesolver::StaticSolver,odesolver::StaticSolver,createSolverStaticSolver,true>();
00409 }
00410 
00411 }// namespace collision
00412 
00413 } // namespace component
00414 
00415 } // namespace Sofa

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