diff --git a/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt b/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt
index cc503bf09d6..b59238f8a65 100644
--- a/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt
+++ b/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt
@@ -6,10 +6,12 @@ set(SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR "src/sofa/component/coll
set(HEADER_FILES
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/config.h.in
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/init.h
+ ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BaseSubCollisionPipeline.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BVHNarrowPhase.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceBroadPhase.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceDetection.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CollisionPM.h
+ ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CompositeCollisionPipeline.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DSAPBox.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CollisionPipeline.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DirectSAP.h
@@ -19,20 +21,24 @@ set(HEADER_FILES
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/MirrorIntersector.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceDetection.h
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceNarrowPhase.h
+ ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/SubCollisionPipeline.h
)
set(SOURCE_FILES
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/init.cpp
+ ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BaseSubCollisionPipeline.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BVHNarrowPhase.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceBroadPhase.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceDetection.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DSAPBox.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CollisionPipeline.cpp
+ ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CompositeCollisionPipeline.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DirectSAP.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DirectSAPNarrowPhase.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/IncrSAP.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceDetection.cpp
${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceNarrowPhase.cpp
+ ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/SubCollisionPipeline.cpp
)
sofa_find_package(Sofa.Simulation.Core REQUIRED)
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.cpp
new file mode 100644
index 00000000000..60f226299f3
--- /dev/null
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.cpp
@@ -0,0 +1,77 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+#include
+
+#include
+#include
+
+namespace sofa::component::collision::detection::algorithm
+{
+
+BaseSubCollisionPipeline::BaseSubCollisionPipeline()
+: sofa::core::objectmodel::BaseObject()
+{
+
+}
+
+void BaseSubCollisionPipeline::doBwdInit()
+{
+
+}
+
+void BaseSubCollisionPipeline::doDraw(const core::visual::VisualParams* vparams)
+{
+ SOFA_UNUSED(vparams);
+
+}
+
+void BaseSubCollisionPipeline::init()
+{
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Loading);
+
+ doInit();
+}
+
+std::set< std::string > BaseSubCollisionPipeline::getResponseList()
+{
+ std::set< std::string > listResponse;
+ for (const auto& [key, creatorPtr] : *core::collision::Contact::Factory::getInstance())
+ {
+ listResponse.insert(key);
+ }
+ return listResponse;
+}
+
+void BaseSubCollisionPipeline::draw(const core::visual::VisualParams* vparams)
+{
+ const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle();
+
+ doDraw(vparams);
+}
+
+void BaseSubCollisionPipeline::handleEvent(sofa::core::objectmodel::Event* e)
+{
+ doHandleEvent(e);
+}
+
+} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.h
new file mode 100644
index 00000000000..f1ff039fcf2
--- /dev/null
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+#include
+
+#include
+
+#include
+#include
+
+namespace sofa::core
+{
+class CollisionModel;
+}
+
+namespace sofa::component::collision::detection::algorithm
+{
+
+class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API BaseSubCollisionPipeline : public sofa::core::objectmodel::BaseObject
+{
+public:
+ SOFA_ABSTRACT_CLASS(BaseSubCollisionPipeline, sofa::core::objectmodel::BaseObject);
+
+protected:
+ BaseSubCollisionPipeline();
+
+ virtual void doInit() = 0;
+ virtual void doBwdInit();
+ virtual void doHandleEvent(sofa::core::objectmodel::Event* e) = 0;
+ virtual void doDraw(const core::visual::VisualParams* vparams);
+
+public:
+ virtual void computeCollisionReset() = 0;
+ virtual void computeCollisionDetection() = 0;
+ virtual void computeCollisionResponse() = 0;
+
+ virtual std::vector getCollisionModels() = 0;
+
+ void init() override final;
+ void draw(const core::visual::VisualParams* vparams) override final;
+ void handleEvent(sofa::core::objectmodel::Event* e) override final;
+
+ static std::set< std::string > getResponseList();
+};
+
+} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp
index 4af2b8fb932..fe92271992c 100644
--- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp
@@ -66,33 +66,57 @@ CollisionPipeline::CollisionPipeline()
, d_depth(initData(&d_depth, defaultDepthValue, "depth",
("Max depth of bounding trees. (default=" + std::to_string(defaultDepthValue) + ", min=?, max=?)").c_str()))
{
+
}
-#ifdef SOFA_DUMP_VISITOR_INFO
-typedef simulation::Visitor::ctime_t ctime_t;
-#endif
-
void CollisionPipeline::init()
{
- Inherit1::init();
-
- if (broadPhaseDetection == nullptr)
- {
- msg_warning() << "A BroadPhase component is required to compute collision detection and was not found in the current scene";
- }
-
- if (narrowPhaseDetection == nullptr)
- {
- msg_warning() << "A NarrowPhase component is required to compute collision detection and was not found in the current scene";
- }
-
- if (contactManager == nullptr)
- {
- msg_warning() << "A ContactManager component is required to compute collision response and was not found in the current scene";
- }
-
+ msg_info() << "CollisionPipeline is now a wrapper to CompositeCollisionPipeline with a single SubCollisionPipeline.";
+ msg_info() << "If you want more flexibility, use directly the components CompositeCollisionPipeline and SubCollisionPipeline, with their respective Data.";
+
+ auto context = this->getContext();
+ assert(context);
+
+ m_subCollisionPipeline = sofa::core::objectmodel::New();
+ m_subCollisionPipeline->d_depth.setParent(&this->d_depth);
+
+ // set the whole collision models list to the sub collision pipeline
+ sofa::type::vector collisionModels;
+ context->get>(&collisionModels, BaseContext::SearchDown);
+ for(auto collisionModel : collisionModels)
+ {
+ m_subCollisionPipeline->l_collisionModels.add(collisionModel.get());
+ }
+
+ // set the other components to the sub collision pipeline
+ // intersection
+ sofa::core::collision::Intersection* intersectionMethod = nullptr;
+ context->get(intersectionMethod, BaseContext::SearchDown);
+ m_subCollisionPipeline->l_intersectionMethod.set(intersectionMethod);
+
+ // broad phase
+ sofa::core::collision::BroadPhaseDetection* broadPhaseDetection = nullptr;
+ context->get(broadPhaseDetection, BaseContext::SearchDown);
+ m_subCollisionPipeline->l_broadPhaseDetection.set(broadPhaseDetection);
+
+ // narrow phase
+ sofa::core::collision::NarrowPhaseDetection* narrowPhaseDetection = nullptr;
+ context->get(narrowPhaseDetection, BaseContext::SearchDown);
+ m_subCollisionPipeline->l_narrowPhaseDetection.set(narrowPhaseDetection);
+
+ // contact manager
+ sofa::core::collision::ContactManager* contactManager = nullptr;
+ context->get(contactManager, BaseContext::SearchDown);
+ m_subCollisionPipeline->l_contactManager.set(contactManager);
+
+ m_subCollisionPipeline->init();
+ this->l_subCollisionPipelines.add(m_subCollisionPipeline.get());
+ this->addSlave(m_subCollisionPipeline.get());
+
/// Insure that all the value provided by the user are valid and report message if it is not.
checkDataValues() ;
+
+ Inherit1::init();
}
void CollisionPipeline::checkDataValues()
@@ -105,222 +129,4 @@ void CollisionPipeline::checkDataValues()
}
}
-void CollisionPipeline::doCollisionReset()
-{
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "CollisionPipeline::doCollisionReset" ;
-
- // clear all contacts
- if (contactManager != nullptr)
- {
- const type::vector& contacts = contactManager->getContacts();
- for (const auto& contact : contacts)
- {
- if (contact != nullptr)
- {
- contact->removeResponse();
- }
- }
- }
-
- // clear all collision groups
- if (groupManager != nullptr)
- {
- core::objectmodel::BaseContext* scene = getContext();
- groupManager->clearGroups(scene);
- }
-}
-
-void CollisionPipeline::doCollisionDetection(const type::vector& collisionModels)
-{
- SCOPED_TIMER_VARNAME(docollisiontimer, "doCollisionDetection");
-
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "doCollisionDetection, compute Bounding Trees" ;
-
- // First, we compute a bounding volume for the collision model (for example bounding sphere)
- // or we have loaded a collision model that knows its other model
-
- type::vector vectBoundingVolume;
- {
- SCOPED_TIMER_VARNAME(bboxtimer, "ComputeBoundingTree");
-
-#ifdef SOFA_DUMP_VISITOR_INFO
- simulation::Visitor::printNode("ComputeBoundingTree");
-#endif
- const bool continuous = intersectionMethod->useContinuous();
- const auto continuousIntersectionType = intersectionMethod->continuousIntersectionType();
- const SReal dt = getContext()->getDt();
-
- type::vector::const_iterator it;
- const type::vector::const_iterator itEnd = collisionModels.end();
- int nActive = 0;
-
- const int used_depth = (
- (broadPhaseDetection && broadPhaseDetection->needsDeepBoundingTree()) ||
- (narrowPhaseDetection && narrowPhaseDetection->needsDeepBoundingTree())
- ) ? d_depth.getValue() : 0;
-
- for (it = collisionModels.begin(); it != itEnd; ++it)
- {
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "doCollisionDetection, consider model" ;
-
- if (!(*it)->isActive()) continue;
-
- if (continuous)
- {
- const std::string msg = "Compute Continuous BoundingTree: " + (*it)->getName();
- ScopedAdvancedTimer continuousBoundingTreeTimer(msg.c_str());
- (*it)->computeContinuousBoundingTree(dt, continuousIntersectionType, used_depth);
- }
- else
- {
- std::string msg = "Compute BoundingTree: " + (*it)->getName();
- ScopedAdvancedTimer boundingTreeTimer(msg.c_str());
- (*it)->computeBoundingTree(used_depth);
- }
-
- vectBoundingVolume.push_back ((*it)->getFirst());
- ++nActive;
- }
-
-#ifdef SOFA_DUMP_VISITOR_INFO
- simulation::Visitor::printCloseNode("ComputeBoundingTree");
-#endif
-
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "doCollisionDetection, Computed "<getName();
-
-#ifdef SOFA_DUMP_VISITOR_INFO
- simulation::Visitor::printNode("BroadPhase");
-#endif
- {
- SCOPED_TIMER_VARNAME(broadphase, "BroadPhase");
- intersectionMethod->beginBroadPhase();
- broadPhaseDetection->beginBroadPhase();
- broadPhaseDetection->addCollisionModels(vectBoundingVolume); // detection is done there
- broadPhaseDetection->endBroadPhase();
- intersectionMethod->endBroadPhase();
- }
-#ifdef SOFA_DUMP_VISITOR_INFO
- simulation::Visitor::printCloseNode("BroadPhase");
-#endif
-
- // then we start the narrow phase
- if (narrowPhaseDetection == nullptr)
- {
- return; // can't go further
- }
-
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "doCollisionDetection, NarrowPhaseDetection "<getName();
-
-#ifdef SOFA_DUMP_VISITOR_INFO
- simulation::Visitor::printNode("NarrowPhase");
-#endif
- {
- SCOPED_TIMER_VARNAME(narrowphase, "NarrowPhase");
- intersectionMethod->beginNarrowPhase();
- narrowPhaseDetection->beginNarrowPhase();
- const type::vector >& vectCMPair = broadPhaseDetection->getCollisionModelPairs();
-
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "doCollisionDetection, "<< vectCMPair.size()<<" colliding model pairs" ;
-
- narrowPhaseDetection->addCollisionPairs(vectCMPair);
- narrowPhaseDetection->endNarrowPhase();
- intersectionMethod->endNarrowPhase();
- }
-#ifdef SOFA_DUMP_VISITOR_INFO
- simulation::Visitor::printCloseNode("NarrowPhase");
-#endif
-
-}
-
-void CollisionPipeline::doCollisionResponse()
-{
- core::objectmodel::BaseContext* scene = getContext();
- // then we start the creation of contacts
- if (narrowPhaseDetection == nullptr || contactManager == nullptr)
- {
- return; // can't go further
- }
-
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "Create Contacts " << contactManager->getName() ;
-
- {
- SCOPED_TIMER_VARNAME(createContactsTimer, "CreateContacts");
- contactManager->createContacts(narrowPhaseDetection->getDetectionOutputs());
- }
-
- // finally we start the creation of collisionGroup
-
- const type::vector& contacts = contactManager->getContacts();
-
- // First we remove all contacts with non-simulated objects and directly add them
- type::vector notStaticContacts;
-
- {
- SCOPED_TIMER_VARNAME(createStaticObjectsResponseTimer, "CreateStaticObjectsResponse");
- for (const auto& contact : contacts)
- {
- const auto collisionModels = contact->getCollisionModels();
- if (collisionModels.first != nullptr && !collisionModels.first->isSimulated())
- {
- contact->createResponse(collisionModels.second->getContext());
- }
- else if (collisionModels.second != nullptr && !collisionModels.second->isSimulated())
- {
- contact->createResponse(collisionModels.first->getContext());
- }
- else
- {
- notStaticContacts.push_back(contact);
- }
- }
- }
-
- if (groupManager == nullptr)
- {
- SCOPED_TIMER_VARNAME(createResponseTimer, "CreateMovingObjectsResponse");
-
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "Linking all contacts to Scene" ;
-
- for (const auto& contact : notStaticContacts)
- {
- contact->createResponse(scene);
- }
- }
- else
- {
- msg_info_when(d_doPrintInfoMessage.getValue())
- << "Create Groups "<getName();
-
- groupManager->createGroups(scene, notStaticContacts);
- }
-}
-
-std::set< std::string > CollisionPipeline::getResponseList() const
-{
- std::set< std::string > listResponse;
- core::collision::Contact::Factory::iterator it;
- for (it=core::collision::Contact::Factory::getInstance()->begin(); it!=core::collision::Contact::Factory::getInstance()->end(); ++it)
- {
- listResponse.insert(it->first);
- }
- return listResponse;
-}
-
} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h
index 8d7a2233213..d497092d498 100644
--- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h
@@ -22,36 +22,30 @@
#pragma once
#include
-#include
+#include
+#include
namespace sofa::component::collision::detection::algorithm
{
-class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API CollisionPipeline : public sofa::simulation::PipelineImpl
+class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API CollisionPipeline : public CompositeCollisionPipeline
{
public:
- SOFA_CLASS(CollisionPipeline,sofa::simulation::PipelineImpl);
+ SOFA_CLASS(CollisionPipeline, CompositeCollisionPipeline);
Data d_doPrintInfoMessage;
Data d_doDebugDraw;
Data d_depth;
+
protected:
CollisionPipeline();
public:
void init() override;
- /// get the set of response available with the current collision pipeline
- std::set< std::string > getResponseList() const override;
protected:
- // -- Pipeline interface
- /// Remove collision response from last step
- void doCollisionReset() override;
- /// Detect new collisions. Note that this step must not modify the simulation graph
- void doCollisionDetection(const sofa::type::vector& collisionModels) override;
- /// Add collision response in the simulation graph
- void doCollisionResponse() override;
-
virtual void checkDataValues() ;
+
+ SubCollisionPipeline::SPtr m_subCollisionPipeline;
public:
static const int defaultDepthValue;
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.cpp
new file mode 100644
index 00000000000..0f6691f4054
--- /dev/null
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.cpp
@@ -0,0 +1,193 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+using sofa::helper::ScopedAdvancedTimer ;
+
+#include
+
+
+namespace sofa::component::collision::detection::algorithm
+{
+
+using namespace sofa;
+using namespace sofa::core;
+using namespace sofa::core::collision;
+
+void registerCompositeCollisionPipeline(sofa::core::ObjectFactory* factory)
+{
+ factory->registerObjects(core::ObjectRegistrationData("Multiple collision pipelines in one.")
+ .add< CompositeCollisionPipeline >());
+}
+
+CompositeCollisionPipeline::CompositeCollisionPipeline()
+ : d_parallelDetection(initData(&d_parallelDetection, false, "parallelDetection", "Parallelize collision detection."))
+ , l_subCollisionPipelines(initLink("subCollisionPipelines", "List of sub collision pipelines to handle."))
+{
+}
+
+void CompositeCollisionPipeline::init()
+{
+ Inherit1::init();
+
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
+
+ if(l_subCollisionPipelines.size() == 0)
+ {
+ msg_warning() << "No SubCollisionPipeline defined in CompositeCollisionPipeline. Nothing will be done." ;
+
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
+ return;
+ }
+
+ if(d_parallelDetection.getValue())
+ {
+ this->initTaskScheduler();
+ }
+
+ // UX: warn if there is any CollisionModel not handled by any SubCollisionPipeline
+ simulation::Node* root = dynamic_cast(getContext());
+ std::vector sceneCollisionModels;
+ root->getTreeObjects(&sceneCollisionModels);
+
+ std::set pipelineCollisionModels;
+ for(auto* subPipeline : l_subCollisionPipelines)
+ {
+ if(!subPipeline)
+ {
+ msg_error() << "One of the subCollisionPipeline is incorrect (nullptr or invalid) ";
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
+ return;
+ }
+
+ for (auto* cm : subPipeline->getCollisionModels())
+ {
+ pipelineCollisionModels.insert(cm);
+ }
+ }
+
+ for (const auto& cm : sceneCollisionModels)
+ {
+ if (pipelineCollisionModels.find(cm) == pipelineCollisionModels.end())
+ {
+ msg_warning() << "CollisionModel " << cm->getPathName() << " is not handled by any SubCollisionPipeline.";
+ }
+ }
+
+}
+
+void CompositeCollisionPipeline::reset()
+{
+
+}
+
+void CompositeCollisionPipeline::doCollisionReset()
+{
+ msg_info() << "CompositeCollisionPipeline::doCollisionReset" ;
+
+ for(const auto& subPipeline : l_subCollisionPipelines)
+ {
+ subPipeline->computeCollisionReset();
+ }
+}
+
+void CompositeCollisionPipeline::doCollisionDetection(const type::vector& collisionModels)
+{
+ SOFA_UNUSED(collisionModels);
+
+ SCOPED_TIMER_VARNAME(docollisiontimer, "doCollisionDetection");
+
+ if(m_taskScheduler)
+ {
+ auto computeCollisionDetection = [&](const auto& range)
+ {
+ for (auto it = range.start; it != range.end; ++it)
+ {
+ (*it)->computeCollisionDetection();
+ }
+ };
+
+ sofa::simulation::forEachRange(sofa::simulation::ForEachExecutionPolicy::PARALLEL, *m_taskScheduler, l_subCollisionPipelines.begin(), l_subCollisionPipelines.end(), computeCollisionDetection);
+ }
+ else
+ {
+ for (const auto& subPipeline : l_subCollisionPipelines)
+ {
+ subPipeline->computeCollisionDetection();
+ }
+ }
+}
+
+void CompositeCollisionPipeline::doCollisionResponse()
+{
+ for (const auto& subPipeline : l_subCollisionPipelines)
+ {
+ subPipeline->computeCollisionResponse();
+ }
+}
+
+std::set< std::string > CompositeCollisionPipeline::getResponseList() const
+{
+ return BaseSubCollisionPipeline::getResponseList();
+}
+
+void CompositeCollisionPipeline::computeCollisionReset()
+{
+ if(!this->isComponentStateValid())
+ return;
+
+ doCollisionReset();
+}
+
+void CompositeCollisionPipeline::computeCollisionDetection()
+{
+ if(!this->isComponentStateValid())
+ return;
+
+ //useless
+ static std::vector collisionModels{};
+
+ doCollisionDetection(collisionModels);
+}
+
+void CompositeCollisionPipeline::computeCollisionResponse()
+{
+ if(!this->isComponentStateValid())
+ return;
+
+ doCollisionResponse();
+}
+
+} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.h
new file mode 100644
index 00000000000..3e28a8c86b0
--- /dev/null
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+#include
+
+#include
+
+#include
+
+namespace sofa::component::collision::detection::algorithm
+{
+
+class BaseSubCollisionPipeline;
+
+class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API CompositeCollisionPipeline : public sofa::core::collision::Pipeline, public sofa::simulation::TaskSchedulerUser
+{
+public:
+ SOFA_CLASS2(CompositeCollisionPipeline, sofa::core::collision::Pipeline, sofa::simulation::TaskSchedulerUser);
+
+ sofa::Data d_depth;
+protected:
+ CompositeCollisionPipeline();
+public:
+ void init() override;
+
+ /// get the set of response available with the current collision pipeline
+ std::set< std::string > getResponseList() const override;
+protected:
+ // -- Pipeline interface
+ /// Remove collision response from last step
+ void doCollisionReset() override;
+ /// Detect new collisions. Note that this step must not modify the simulation graph
+ void doCollisionDetection(const sofa::type::vector& collisionModels) override;
+ /// Add collision response in the simulation graph
+ void doCollisionResponse() override;
+
+ void reset() override;
+
+ /// Remove collision response from last step
+ virtual void computeCollisionReset() override final;
+ /// Detect new collisions. Note that this step must not modify the simulation graph
+ virtual void computeCollisionDetection() override final;
+ /// Add collision response in the simulation graph
+ virtual void computeCollisionResponse() override final;
+
+public:
+ sofa::Data d_parallelDetection;
+ sofa::MultiLink < CompositeCollisionPipeline, BaseSubCollisionPipeline, sofa::BaseLink::FLAG_DUPLICATE > l_subCollisionPipelines;
+
+
+ friend class CollisionPipeline; // to be able to call do*()
+};
+
+} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.cpp
new file mode 100644
index 00000000000..a8449c5a1cd
--- /dev/null
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.cpp
@@ -0,0 +1,271 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#include
+
+#include
+
+#include
+
+#include
+
+#include
+using sofa::helper::ScopedAdvancedTimer ;
+
+#include
+
+
+namespace sofa::component::collision::detection::algorithm
+{
+
+using namespace sofa;
+using namespace sofa::core;
+using namespace sofa::core::collision;
+
+void registerSubCollisionPipeline(sofa::core::ObjectFactory* factory)
+{
+ factory->registerObjects(core::ObjectRegistrationData("Collision pipeline to be used with CompositeCollisionPipeline.")
+ .add< SubCollisionPipeline >());
+}
+
+SubCollisionPipeline::SubCollisionPipeline()
+ : Inherited()
+ , d_depth(initData(&d_depth, s_defaultDepthValue, "depth", +("Max depth of bounding trees. (default=" + std::to_string(s_defaultDepthValue) + ", min=?, max=?)").c_str()))
+ , l_collisionModels(initLink("collisionModels", "List of collision models to consider in this pipeline"))
+ , l_intersectionMethod(initLink("intersectionMethod", "Intersection method to use in this pipeline"))
+ , l_contactManager(initLink("contactManager", "Contact manager to use in this pipeline"))
+ , l_broadPhaseDetection(initLink("broadPhaseDetection", "Broad phase detection to use in this pipeline"))
+ , l_narrowPhaseDetection(initLink("narrowPhaseDetection", "Narrow phase detection to use in this pipeline"))
+{
+}
+
+void SubCollisionPipeline::doInit()
+{
+ bool validity = true;
+
+ //Check given parameters
+ if (l_collisionModels.size() == 0)
+ {
+ msg_warning() << "At least one CollisionModel is required to compute collision detection.";
+ validity = false;
+ }
+
+ if (!l_intersectionMethod)
+ {
+ msg_warning() << "An Intersection detection component is required to compute collision detection.";
+ validity = false;
+ }
+
+ if (!l_contactManager)
+ {
+ msg_warning() << "A contact manager component is required to compute collision detection.";
+ validity = false;
+ }
+
+ if (!l_broadPhaseDetection)
+ {
+ msg_warning() << "A BroadPhase component is required to compute collision detection.";
+ validity = false;
+ }
+ if (!l_narrowPhaseDetection)
+ {
+ msg_warning() << "A NarrowPhase component is required to compute collision detection.";
+ validity = false;
+ }
+
+ if (!validity)
+ {
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
+ }
+ else
+ {
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
+ }
+
+}
+
+void SubCollisionPipeline::computeCollisionReset()
+{
+ if (!this->isComponentStateValid())
+ return;
+
+ msg_info() << "SubCollisionPipeline::doCollisionReset";
+
+ l_broadPhaseDetection->setIntersectionMethod(l_intersectionMethod.get());
+ l_narrowPhaseDetection->setIntersectionMethod(l_intersectionMethod.get());
+ l_contactManager->setIntersectionMethod(l_intersectionMethod.get());
+
+ // clear all contacts
+ const type::vector& contacts = l_contactManager->getContacts();
+ for (const auto& contact : contacts)
+ {
+ if (contact != nullptr)
+ {
+ contact->removeResponse();
+ }
+ }
+}
+
+void SubCollisionPipeline::computeCollisionDetection()
+{
+ SCOPED_TIMER_VARNAME(docollisiontimer, "doCollisionDetection");
+
+ if (!this->isComponentStateValid())
+ return;
+
+ msg_info() << "doCollisionDetection, compute Bounding Trees" ;
+
+ // First, we compute a bounding volume for the collision model (for example bounding sphere)
+ // or we have loaded a collision model that knows its other model
+
+ type::vector vectBoundingVolume;
+ {
+ SCOPED_TIMER_VARNAME(bboxtimer, "ComputeBoundingTree");
+
+ const bool continuous = l_intersectionMethod->useContinuous();
+ const auto continuousIntersectionType = l_intersectionMethod->continuousIntersectionType();
+ const SReal dt = getContext()->getDt();
+
+ int nActive = 0;
+
+ const int used_depth = (
+ (l_broadPhaseDetection->needsDeepBoundingTree()) ||
+ (l_narrowPhaseDetection->needsDeepBoundingTree())
+ ) ? d_depth.getValue() : 0;
+
+ for (auto it = l_collisionModels.begin(); it != l_collisionModels.end(); ++it)
+ {
+ msg_info() << "doCollisionDetection, consider model" ;
+
+ if (!(*it)->isActive()) continue;
+
+ if (continuous)
+ {
+ const std::string msg = "Compute Continuous BoundingTree: " + (*it)->getName();
+ ScopedAdvancedTimer continuousBoundingTreeTimer(msg.c_str());
+ (*it)->computeContinuousBoundingTree(dt, continuousIntersectionType, used_depth);
+ }
+ else
+ {
+ std::string msg = "Compute BoundingTree: " + (*it)->getName();
+ ScopedAdvancedTimer boundingTreeTimer(msg.c_str());
+ (*it)->computeBoundingTree(used_depth);
+ }
+
+ vectBoundingVolume.push_back ((*it)->getFirst());
+ ++nActive;
+ }
+
+
+ msg_info() << "doCollisionDetection, Computed "<getName();
+
+ {
+ SCOPED_TIMER_VARNAME(broadphase, "BroadPhase");
+ l_intersectionMethod->beginBroadPhase();
+ l_broadPhaseDetection->beginBroadPhase();
+ l_broadPhaseDetection->addCollisionModels(vectBoundingVolume); // detection is done there
+ l_broadPhaseDetection->endBroadPhase();
+ l_intersectionMethod->endBroadPhase();
+ }
+
+ msg_info() << "doCollisionDetection, NarrowPhaseDetection "<< l_narrowPhaseDetection->getName();
+
+ {
+ SCOPED_TIMER_VARNAME(narrowphase, "NarrowPhase");
+ l_intersectionMethod->beginNarrowPhase();
+ l_narrowPhaseDetection->beginNarrowPhase();
+ const type::vector >& vectCMPair = l_broadPhaseDetection->getCollisionModelPairs();
+
+ msg_info() << "doCollisionDetection, "<< vectCMPair.size()<<" colliding model pairs" ;
+
+ l_narrowPhaseDetection->addCollisionPairs(vectCMPair);
+ l_narrowPhaseDetection->endNarrowPhase();
+ l_intersectionMethod->endNarrowPhase();
+ }
+
+}
+
+void SubCollisionPipeline::computeCollisionResponse()
+{
+ if (!this->isComponentStateValid())
+ return;
+
+ core::objectmodel::BaseContext* scene = getContext();
+
+ msg_info() << "Create Contacts " << l_contactManager->getName() ;
+
+ {
+ SCOPED_TIMER_VARNAME(createContactsTimer, "CreateContacts");
+ l_contactManager->createContacts(l_narrowPhaseDetection->getDetectionOutputs());
+ }
+
+ // finally we start the creation of collisionGroup
+ const type::vector& contacts = l_contactManager->getContacts();
+
+ // First we remove all contacts with non-simulated objects and directly add them
+ type::vector notStaticContacts;
+
+ {
+ SCOPED_TIMER_VARNAME(createStaticObjectsResponseTimer, "CreateStaticObjectsResponse");
+ for (const auto& contact : contacts)
+ {
+ const auto collisionModels = contact->getCollisionModels();
+ if (collisionModels.first != nullptr && !collisionModels.first->isSimulated())
+ {
+ contact->createResponse(collisionModels.second->getContext());
+ }
+ else if (collisionModels.second != nullptr && !collisionModels.second->isSimulated())
+ {
+ contact->createResponse(collisionModels.first->getContext());
+ }
+ else
+ {
+ notStaticContacts.push_back(contact);
+ }
+ }
+ }
+
+ SCOPED_TIMER_VARNAME(createResponseTimer, "CreateMovingObjectsResponse");
+
+ msg_info() << "Linking all contacts to Scene" ;
+
+ for (const auto& contact : notStaticContacts)
+ {
+ contact->createResponse(scene);
+ }
+}
+
+
+std::vector SubCollisionPipeline::getCollisionModels()
+{
+ std::vector collisionModels;
+ collisionModels.reserve(l_collisionModels.getSize());
+ for(auto* collisionModel : l_collisionModels)
+ {
+ collisionModels.push_back(collisionModel);
+ }
+ return collisionModels;
+}
+
+} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.h
new file mode 100644
index 00000000000..ff535930df1
--- /dev/null
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace sofa::component::collision::detection::algorithm
+{
+
+class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API SubCollisionPipeline : public BaseSubCollisionPipeline
+{
+public:
+ using Inherited = BaseSubCollisionPipeline;
+ SOFA_CLASS(SubCollisionPipeline, Inherited);
+protected:
+ SubCollisionPipeline();
+public:
+ virtual ~SubCollisionPipeline() override = default;
+ void doInit() override;
+ void doHandleEvent(sofa::core::objectmodel::Event*) override {}
+
+ void computeCollisionReset() override;
+ void computeCollisionDetection() override;
+ void computeCollisionResponse() override;
+
+ std::vector getCollisionModels() override;
+
+ sofa::Data d_depth;
+ sofa::MultiLink < SubCollisionPipeline, sofa::core::CollisionModel, sofa::BaseLink::FLAG_DUPLICATE > l_collisionModels;
+ sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::Intersection, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_intersectionMethod;
+ sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::ContactManager, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_contactManager;
+ sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::BroadPhaseDetection, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_broadPhaseDetection;
+ sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::NarrowPhaseDetection, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_narrowPhaseDetection;
+
+ static inline constexpr unsigned int s_defaultDepthValue = 6;
+};
+
+} // namespace sofa::component::collision::detection::algorithm
diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp
index d6e879397e0..b8ae17c38bf 100644
--- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp
+++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp
@@ -29,6 +29,8 @@ namespace sofa::component::collision::detection::algorithm
extern void registerBruteForceBroadPhase(sofa::core::ObjectFactory* factory);
extern void registerBruteForceDetection(sofa::core::ObjectFactory* factory);
extern void registerBVHNarrowPhase(sofa::core::ObjectFactory* factory);
+extern void registerCompositeCollisionPipeline(sofa::core::ObjectFactory* factory);
+extern void registerSubCollisionPipeline(sofa::core::ObjectFactory* factory);
extern void registerCollisionPipeline(sofa::core::ObjectFactory* factory);
extern void registerDirectSAP(sofa::core::ObjectFactory* factory);
extern void registerDirectSAPNarrowPhase(sofa::core::ObjectFactory* factory);
@@ -64,6 +66,8 @@ void registerObjects(sofa::core::ObjectFactory* factory)
registerBruteForceBroadPhase(factory);
registerBruteForceDetection(factory);
registerBVHNarrowPhase(factory);
+ registerCompositeCollisionPipeline(factory);
+ registerSubCollisionPipeline(factory);
registerCollisionPipeline(factory);
registerDirectSAP(factory);
registerDirectSAPNarrowPhase(factory);
diff --git a/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp b/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp
index ae151f8efd5..9bb60fc3a8d 100644
--- a/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp
+++ b/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp
@@ -72,12 +72,14 @@ class TestCollisionPipeline : public BaseSimulationTest {
void checkCollisionPipelineWithMissingBroadPhase();
void checkCollisionPipelineWithMissingNarrowPhase();
void checkCollisionPipelineWithMissingContactManager();
+ void checkCollisionPipelineWithMissingCollisionModel();
int checkCollisionPipelineWithMonkeyValueForDepth(int value);
void doSetUp() override
{
this->loadPlugins({
Sofa.Component.StateContainer,
+ Sofa.Component.Collision.Geometry,
Sofa.Component.Collision.Detection.Algorithm,
Sofa.Component.Collision.Detection.Intersection,
Sofa.Component.Collision.Response.Contact
@@ -104,6 +106,10 @@ void TestCollisionPipeline::checkCollisionPipelineWithNoAttributes()
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
" \n" ;
root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
@@ -127,6 +133,10 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingIntersection()
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
" \n" ;
root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
@@ -149,6 +159,10 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingBroadPhase()
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
" \n" ;
root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
@@ -170,8 +184,12 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingNarrowPhase()
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
" \n" ;
-
+
root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
ASSERT_NE(root.get(), nullptr) ;
root->init(sofa::core::execparams::defaultInstance()) ;
@@ -191,6 +209,34 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingContactManager()
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n" ;
+
+ root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
+ ASSERT_NE(root.get(), nullptr) ;
+ root->init(sofa::core::execparams::defaultInstance()) ;
+
+ BaseObject* clp = root->getObject("pipeline") ;
+ ASSERT_NE(clp, nullptr) ;
+
+}
+
+void TestCollisionPipeline::checkCollisionPipelineWithMissingCollisionModel()
+{
+ EXPECT_MSG_EMIT(Warning) ;
+ EXPECT_MSG_NOEMIT(Error) ;
+
+ std::stringstream scene ;
+ scene << " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
" \n" ;
root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
@@ -212,6 +258,10 @@ int TestCollisionPipeline::checkCollisionPipelineWithMonkeyValueForDepth(int dva
" \n"
" \n"
" \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
" \n" ;
root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str());
@@ -252,6 +302,12 @@ TEST_F(TestCollisionPipeline, checkCollisionPipelineWithMissingContactManager)
this->checkCollisionPipelineWithMissingContactManager();
}
+TEST_F(TestCollisionPipeline, checkCollisionPipelineWithMissingCollisionModel)
+{
+ this->checkCollisionPipelineWithMissingCollisionModel();
+}
+
+
TEST_F(TestCollisionPipeline, checkCollisionPipelineWithMonkeyValueForDepth_OpenIssue)
{
const std::vector> testvalues = {
diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn
new file mode 100644
index 00000000000..50fdf09fd01
--- /dev/null
+++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn.view b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn.view
new file mode 100644
index 00000000000..0f039dffcad
--- /dev/null
+++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn.view
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn
new file mode 100644
index 00000000000..9fd746092c6
--- /dev/null
+++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn.view b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn.view
new file mode 100644
index 00000000000..0f039dffcad
--- /dev/null
+++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn.view
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/RegressionStateScenes.regression-tests b/examples/RegressionStateScenes.regression-tests
index 6270d2211ad..fc9ec569ad2 100644
--- a/examples/RegressionStateScenes.regression-tests
+++ b/examples/RegressionStateScenes.regression-tests
@@ -37,6 +37,8 @@ Demos/SofaScene.scn 120 1e-5 1 1
### Component scenes ###
Component/Collision/Response/RuleBasedContactManager.scn 100 1e-4 0 1
Component/Collision/Response/FrictionContact.scn 100 1e-4 0 1
+Component/Collision/Detection/CompositeCollisionPipeline.scn 200 1e-4 0 1
+Component/Collision/Detection/CompositeCollisionPipeline_none.scn 200 1e-4 0 1
Component/Constraint/Lagrangian/BilateralLagrangianConstraint_NNCG.scn 100 1e-4 0 1
Component/Constraint/Lagrangian/BilateralLagrangianConstraint_PGS.scn 100 1e-4 0 1
Component/Constraint/Lagrangian/BilateralLagrangianConstraint_UGS.scn 100 1e-4 0 1