18 #include <sofa/component/collision/AttachBodyPerformer.h>
19 #include <sofa/component/collision/ComponentMouseInteraction.h>
20 #include <sofa/component/collision/FixParticlePerformer.h>
21 #include <sofa/component/collision/RayContact.h>
22 #include <sofa/component/collision/RayModel.h>
23 #include <sofa/component/container/MechanicalObject.h>
24 #include <sofa/simulation/common/CollisionVisitor.h>
25 #include <sofa/simulation/common/DeleteVisitor.h>
26 #include <sofa/simulation/common/MechanicalVisitor.h>
27 #include <sofa/simulation/common/Node.h>
28 #include <vtkCamera.h>
32 using sofa::component::collision::AttachBodyPerformer;
33 using sofa::component::collision::BaseRayContact;
34 using sofa::component::collision::BodyPicked;
35 using sofa::component::collision::ComponentMouseInteraction;
36 using sofa::component::collision::FixParticlePerformerConfiguration;
37 using sofa::component::collision::InteractionPerformer;
38 using sofa::component::collision::Ray;
39 using sofa::component::collision::RayModel;
40 using sofa::component::container::MechanicalObject;
41 using sofa::core::behavior::BaseMechanicalState;
42 using sofa::core::collision::DetectionOutput;
43 using sofa::core::collision::Pipeline;
44 using sofa::core::objectmodel::BaseContext;
45 using sofa::core::CollisionElementIterator;
46 using sofa::core::ExecParams;
47 using sofa::core::MechanicalParams;
48 using sofa::core::VecCoordId;
49 using sofa::defaulttype::dot;
50 using sofa::defaulttype::Vec3d;
51 using sofa::defaulttype::Vec3Types;
52 using sofa::helper::vector;
53 using sofa::simulation::CollisionVisitor;
54 using sofa::simulation::DeleteVisitor;
55 using sofa::simulation::MechanicalPickParticlesVisitor;
56 using sofa::simulation::MechanicalPropagatePositionVisitor;
57 using sofa::simulation::Node;
61 class SimulationInteractor::Impl
67 void Initialize(Node::SPtr rootNode);
69 void AttachMouseNode();
70 void DetachMouseNode();
71 bool IsInteractionPerformerNotNull()
const;
72 void UpdatePickRay(InteractionPositionEvent* event);
74 void AttachCompatibleInteraction();
75 void DetachInteraction(
bool setNull);
76 void StartInteraction(
const std::string& type);
77 void ExecuteInteraction();
78 void StopInteraction();
82 Impl& operator=(
const Impl&);
84 BodyPicked FindCollisionUsingPipeline();
85 BodyPicked FindCollisionUsingBruteForce();
86 void ConfigureInteractionPerformer();
88 Node::SPtr m_RootNode;
89 Node::SPtr m_MouseNode;
90 MechanicalObject<Vec3Types>::SPtr m_PickRayContainer;
91 RayModel::SPtr m_PickRayModel;
92 std::vector<ComponentMouseInteraction*> m_InteractionComponents;
93 ComponentMouseInteraction* m_Interaction;
94 std::unique_ptr<InteractionPerformer> m_InteractionPerformer;
95 bool m_IsMouseNodeAttached;
96 bool m_UseCollisionPipeline;
97 BodyPicked m_LastBodyPicked;
101 mitk::SimulationInteractor::Impl::Impl()
102 : m_Interaction(NULL),
103 m_IsMouseNodeAttached(false),
104 m_UseCollisionPipeline(true)
108 mitk::SimulationInteractor::Impl::~Impl()
110 this->Uninitialize();
113 void mitk::SimulationInteractor::Impl::Initialize(
const Node::SPtr rootNode)
115 this->Uninitialize();
117 m_RootNode = rootNode;
119 m_PickRayContainer = sofa::core::objectmodel::New<MechanicalObject<Vec3Types> >();
120 m_PickRayContainer->setName(
"MousePosition");
121 m_PickRayContainer->resize(1);
123 m_PickRayModel = sofa::core::objectmodel::New<RayModel>();
124 m_PickRayModel->setName(
"MouseCollisionModel");
125 m_PickRayModel->setNbRay(1);
127 m_MouseNode = rootNode->createChild(
"Mouse");
128 m_MouseNode->addObject(m_PickRayContainer);
129 m_MouseNode->addObject(m_PickRayModel);
131 m_MouseNode->init(ExecParams::defaultInstance());
132 m_PickRayContainer->init();
133 m_PickRayModel->init();
135 typedef ComponentMouseInteraction::ComponentMouseInteractionFactory Factory;
136 const Factory* factory = Factory::getInstance();
138 for (Factory::const_iterator it = factory->begin(); it != factory->end(); ++it)
139 m_InteractionComponents.push_back(it->second->createInstance(NULL));
141 m_MouseNode->detachFromGraph();
143 Pipeline* collisionPipeline;
144 rootNode->getContext()->get(collisionPipeline, BaseContext::SearchRoot);
146 m_UseCollisionPipeline = collisionPipeline != NULL;
149 void mitk::SimulationInteractor::Impl::Uninitialize()
151 this->DetachMouseNode();
153 if (!m_InteractionComponents.empty())
155 for (std::vector<ComponentMouseInteraction*>::iterator it = m_InteractionComponents.begin(); it != m_InteractionComponents.end(); ++it)
158 m_InteractionComponents.clear();
159 m_Interaction = NULL;
164 m_MouseNode->execute<DeleteVisitor>(ExecParams::defaultInstance());
166 m_PickRayModel.reset();
167 m_PickRayContainer.reset();
173 void mitk::SimulationInteractor::Impl::AttachMouseNode()
175 if (!m_IsMouseNodeAttached)
177 m_RootNode->addChild(m_MouseNode);
178 m_IsMouseNodeAttached =
true;
182 void mitk::SimulationInteractor::Impl::DetachMouseNode()
184 if (m_IsMouseNodeAttached)
186 this->DetachInteraction(
false);
187 m_MouseNode->detachFromGraph();
188 m_IsMouseNodeAttached =
false;
192 bool mitk::SimulationInteractor::Impl::IsInteractionPerformerNotNull()
const
194 return m_InteractionPerformer.get() != NULL;
197 void mitk::SimulationInteractor::Impl::UpdatePickRay(InteractionPositionEvent* event)
199 if (!m_IsMouseNodeAttached)
202 vtkCamera* camera =
event->GetSender()->GetVtkRenderer()->GetActiveCamera();
204 Vec3d cameraOrigin(camera->GetPosition());
205 Vec3d pickedPosition(event->GetPositionInWorld().GetDataPointer());
206 Vec3d pickRayDirection(pickedPosition - cameraOrigin);
207 Vec3d focalPoint(camera->GetFocalPoint());
209 Vec3d cameraDirection(focalPoint - cameraOrigin);
210 cameraDirection.normalize();
212 std::pair<double, double> clippingRange;
213 camera->GetClippingRange(clippingRange.first, clippingRange.second);
215 double dotProduct = dot(cameraDirection, pickRayDirection);
216 double norm = pickRayDirection.norm();
218 clippingRange.first = clippingRange.first / dotProduct * norm;
219 clippingRange.second = clippingRange.second / dotProduct * norm;
221 pickRayDirection.normalize();
223 Ray pickRay = m_PickRayModel->getRay(0);
224 pickRay.setOrigin(cameraOrigin + pickRayDirection * clippingRange.first);
225 pickRay.setDirection(pickRayDirection);
226 pickRay.setL(clippingRange.second - clippingRange.first);
228 MechanicalPropagatePositionVisitor(MechanicalParams::defaultInstance(), 0, VecCoordId::position(),
true)
229 .execute(m_PickRayModel->getContext());
231 MechanicalPropagatePositionVisitor(MechanicalParams::defaultInstance(), 0, VecCoordId::freePosition(),
true)
232 .execute(m_PickRayModel->getContext());
235 void mitk::SimulationInteractor::Impl::FindCollision()
237 CollisionVisitor(ExecParams::defaultInstance()).execute(m_RootNode->getContext());
239 if (m_UseCollisionPipeline)
241 m_LastBodyPicked = this->FindCollisionUsingPipeline();
243 if (m_LastBodyPicked.body != NULL)
247 m_LastBodyPicked = this->FindCollisionUsingBruteForce();
250 BodyPicked mitk::SimulationInteractor::Impl::FindCollisionUsingPipeline()
252 BodyPicked bodyPicked;
254 Ray ray = m_PickRayModel->getRay(0);
255 const Vec3d& origin = ray.origin();
256 const Vec3d& direction = ray.direction();
257 const double length = ray.l();
259 const std::set<BaseRayContact*>& contacts = m_PickRayModel->getContacts();
261 for (std::set<BaseRayContact*>::const_iterator contact = contacts.begin(); contact != contacts.end(); ++contact)
263 const vector<DetectionOutput*>& detectionOutputs = (*contact)->getDetectionOutputs();
265 for (vector<DetectionOutput*>::const_iterator detectionOutput = detectionOutputs.begin(); detectionOutput != detectionOutputs.end(); ++detectionOutput)
267 CollisionElementIterator collisionElement;
270 if ((*detectionOutput)->elem.first.getCollisionModel() == m_PickRayModel)
272 collisionElement = (*detectionOutput)->elem.second;
275 else if ((*detectionOutput)->elem.second.getCollisionModel() == m_PickRayModel)
277 collisionElement = (*detectionOutput)->elem.first;
285 if (!collisionElement.getCollisionModel()->isSimulated())
288 const double t = ((*detectionOutput)->point[pointIndex] - origin) * direction;
290 if (t < 0.0 || t > length)
293 if (bodyPicked.body == NULL || t < bodyPicked.rayLength)
295 bodyPicked.body = collisionElement.getCollisionModel();
296 bodyPicked.indexCollisionElement = collisionElement.getIndex();
297 bodyPicked.point = (*detectionOutput)->point[pointIndex];
298 bodyPicked.dist = ((*detectionOutput)->point[1] - (*detectionOutput)->point[0]).norm();
299 bodyPicked.rayLength = t;
307 BodyPicked mitk::SimulationInteractor::Impl::FindCollisionUsingBruteForce()
309 BodyPicked bodyPicked;
311 Ray ray = m_PickRayModel->getRay(0);
312 const Vec3d& origin = ray.origin();
313 const Vec3d& direction = ray.direction();
314 const double length = ray.l();
316 MechanicalPickParticlesVisitor pickVisitor(ExecParams::defaultInstance(), origin, direction, length);
317 pickVisitor.execute(m_RootNode->getContext());
319 if (!pickVisitor.particles.empty())
321 bodyPicked.mstate = pickVisitor.particles.begin()->second.first;
322 bodyPicked.indexCollisionElement = pickVisitor.particles.begin()->second.second;
323 bodyPicked.point[0] = bodyPicked.mstate->getPX(bodyPicked.indexCollisionElement);
324 bodyPicked.point[1] = bodyPicked.mstate->getPY(bodyPicked.indexCollisionElement);
325 bodyPicked.point[2] = bodyPicked.mstate->getPZ(bodyPicked.indexCollisionElement);
327 bodyPicked.rayLength = (bodyPicked.point - origin) * direction;
333 void mitk::SimulationInteractor::Impl::AttachCompatibleInteraction()
335 BaseContext* context;
337 if (m_LastBodyPicked.body == NULL)
339 context = m_LastBodyPicked.mstate != NULL
340 ? m_LastBodyPicked.mstate->getContext()
345 context = m_LastBodyPicked.body->getContext();
350 if (m_Interaction == NULL || !m_Interaction->isCompatible(context))
352 bool foundCompatibleInteractor =
false;
354 for (std::vector<ComponentMouseInteraction*>::const_iterator it = m_InteractionComponents.begin(); it != m_InteractionComponents.end(); ++it)
356 if (*it != m_Interaction && (*it)->isCompatible(context))
358 this->DetachInteraction(
false);
360 m_Interaction->attach(m_MouseNode.get());
362 foundCompatibleInteractor =
true;
367 if (!foundCompatibleInteractor)
368 this->DetachInteraction(
true);
373 this->DetachInteraction(
true);
376 if (m_Interaction != NULL)
378 m_Interaction->mouseInteractor->setMouseRayModel(m_PickRayModel.get());
379 m_Interaction->mouseInteractor->setBodyPicked(m_LastBodyPicked);
383 void mitk::SimulationInteractor::Impl::DetachInteraction(
bool setNull)
385 if (m_Interaction != NULL)
387 m_Interaction->detach();
390 m_Interaction = NULL;
394 void mitk::SimulationInteractor::Impl::StartInteraction(
const std::string& type)
396 if (m_Interaction == NULL)
399 InteractionPerformer::InteractionPerformerFactory* factory = InteractionPerformer::InteractionPerformerFactory::getInstance();
400 m_InteractionPerformer.reset(factory->createObject(type, m_Interaction->mouseInteractor.get()));
402 if (m_InteractionPerformer.get() != NULL)
404 this->ConfigureInteractionPerformer();
405 m_Interaction->mouseInteractor->addInteractionPerformer(m_InteractionPerformer.get());
406 m_InteractionPerformer->start();
410 void mitk::SimulationInteractor::Impl::ConfigureInteractionPerformer()
412 AttachBodyPerformer<Vec3Types>* attachBodyPerformer =
dynamic_cast<AttachBodyPerformer<Vec3Types>*
>(m_InteractionPerformer.get());
414 if (attachBodyPerformer != NULL)
416 attachBodyPerformer->setStiffness(1000);
417 attachBodyPerformer->setArrowSize(0);
418 attachBodyPerformer->setShowFactorSize(1);
422 FixParticlePerformerConfiguration* fixParticlePerformer =
dynamic_cast<FixParticlePerformerConfiguration*
>(m_InteractionPerformer.get());
424 if (fixParticlePerformer != NULL)
425 fixParticlePerformer->setStiffness(10000);
428 void mitk::SimulationInteractor::Impl::ExecuteInteraction()
430 if (m_InteractionPerformer.get() == NULL)
433 m_InteractionPerformer->execute();
436 void mitk::SimulationInteractor::Impl::StopInteraction()
438 if (m_InteractionPerformer.get() == NULL)
441 AttachBodyPerformer<Vec3Types>* attachBodyPerformer =
dynamic_cast<AttachBodyPerformer<Vec3Types>*
>(m_InteractionPerformer.get());
443 if (attachBodyPerformer != NULL)
444 attachBodyPerformer->clear();
446 m_Interaction->mouseInteractor->removeInteractionPerformer(m_InteractionPerformer.get());
447 m_InteractionPerformer.release();
450 mitk::SimulationInteractor::SimulationInteractor()
455 mitk::SimulationInteractor::~SimulationInteractor()
465 CONNECT_CONDITION(
"isInteractionPerformerNotNull", IsInteractionPerformerNotNull);
470 this->ResetToStartState();
474 if (dataNode !=
nullptr)
478 if (simulation.IsNotNull())
480 m_Impl->Initialize(simulation->GetRootNode());
490 m_Impl->AttachMouseNode();
491 m_Impl->UpdatePickRay(event);
493 m_Impl->AttachCompatibleInteraction();
494 m_Impl->StartInteraction(type);
497 void mitk::SimulationInteractor::StartPrimaryInteraction(StateMachineAction*, InteractionEvent* event)
499 this->StartInteraction(
"AttachBody", dynamic_cast<InteractionPositionEvent*>(event));
502 void mitk::SimulationInteractor::StartSecondaryInteraction(StateMachineAction*, InteractionEvent* event)
504 this->StartInteraction(
"FixParticle", dynamic_cast<InteractionPositionEvent*>(event));
507 void mitk::SimulationInteractor::StopInteraction(StateMachineAction*, InteractionEvent*)
509 m_Impl->StopInteraction();
510 m_Impl->DetachMouseNode();
513 void mitk::SimulationInteractor::ExecuteInteraction(StateMachineAction*, InteractionEvent* event)
515 m_Impl->UpdatePickRay(dynamic_cast<InteractionPositionEvent*>(event));
516 m_Impl->ExecuteInteraction();
519 bool mitk::SimulationInteractor::IsInteractionPerformerNotNull(
const InteractionEvent*)
521 return m_Impl->IsInteractionPerformerNotNull();
Super class for all position events.
DataCollection - Class to facilitate loading/accessing structured data.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
#define CONNECT_CONDITION(a, f)
#define CONNECT_FUNCTION(a, f)
void ConnectActionsAndFunctions() override
Overwrite this function to connect actions from StateMachine description with functions.
void DataNodeChanged() override
Is called when a DataNode is initially set or changed To be implemented by sub-classes for initializa...
Class for nodes of the DataTree.