Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkSimulationInteractor.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
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>
29 #include "mitkSimulation.h"
31 
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;
58 
59 namespace mitk
60 {
61  class SimulationInteractor::Impl
62  {
63  public:
64  Impl();
65  ~Impl();
66 
67  void Initialize(Node::SPtr rootNode);
68  void Uninitialize();
69  void AttachMouseNode();
70  void DetachMouseNode();
71  bool IsInteractionPerformerNotNull() const;
72  void UpdatePickRay(InteractionPositionEvent* event);
73  void FindCollision();
74  void AttachCompatibleInteraction();
75  void DetachInteraction(bool setNull);
76  void StartInteraction(const std::string& type);
77  void ExecuteInteraction();
78  void StopInteraction();
79 
80  private:
81  Impl(const Impl&);
82  Impl& operator=(const Impl&);
83 
84  BodyPicked FindCollisionUsingPipeline();
85  BodyPicked FindCollisionUsingBruteForce();
86  void ConfigureInteractionPerformer();
87 
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;
98  };
99 }
100 
101 mitk::SimulationInteractor::Impl::Impl()
102  : m_Interaction(NULL),
103  m_IsMouseNodeAttached(false),
104  m_UseCollisionPipeline(true)
105 {
106 }
107 
108 mitk::SimulationInteractor::Impl::~Impl()
109 {
110  this->Uninitialize();
111 }
112 
113 void mitk::SimulationInteractor::Impl::Initialize(const Node::SPtr rootNode)
114 {
115  this->Uninitialize();
116 
117  m_RootNode = rootNode;
118 
119  m_PickRayContainer = sofa::core::objectmodel::New<MechanicalObject<Vec3Types> >();
120  m_PickRayContainer->setName("MousePosition");
121  m_PickRayContainer->resize(1);
122 
123  m_PickRayModel = sofa::core::objectmodel::New<RayModel>();
124  m_PickRayModel->setName("MouseCollisionModel");
125  m_PickRayModel->setNbRay(1);
126 
127  m_MouseNode = rootNode->createChild("Mouse");
128  m_MouseNode->addObject(m_PickRayContainer);
129  m_MouseNode->addObject(m_PickRayModel);
130 
131  m_MouseNode->init(ExecParams::defaultInstance());
132  m_PickRayContainer->init();
133  m_PickRayModel->init();
134 
135  typedef ComponentMouseInteraction::ComponentMouseInteractionFactory Factory;
136  const Factory* factory = Factory::getInstance();
137 
138  for (Factory::const_iterator it = factory->begin(); it != factory->end(); ++it)
139  m_InteractionComponents.push_back(it->second->createInstance(NULL));
140 
141  m_MouseNode->detachFromGraph();
142 
143  Pipeline* collisionPipeline;
144  rootNode->getContext()->get(collisionPipeline, BaseContext::SearchRoot);
145 
146  m_UseCollisionPipeline = collisionPipeline != NULL;
147 }
148 
149 void mitk::SimulationInteractor::Impl::Uninitialize()
150 {
151  this->DetachMouseNode();
152 
153  if (!m_InteractionComponents.empty())
154  {
155  for (std::vector<ComponentMouseInteraction*>::iterator it = m_InteractionComponents.begin(); it != m_InteractionComponents.end(); ++it)
156  delete *it;
157 
158  m_InteractionComponents.clear();
159  m_Interaction = NULL;
160  }
161 
162  if (m_MouseNode)
163  {
164  m_MouseNode->execute<DeleteVisitor>(ExecParams::defaultInstance());
165 
166  m_PickRayModel.reset();
167  m_PickRayContainer.reset();
168  m_MouseNode.reset();
169  m_RootNode.reset();
170  }
171 }
172 
173 void mitk::SimulationInteractor::Impl::AttachMouseNode()
174 {
175  if (!m_IsMouseNodeAttached)
176  {
177  m_RootNode->addChild(m_MouseNode);
178  m_IsMouseNodeAttached = true;
179  }
180 }
181 
182 void mitk::SimulationInteractor::Impl::DetachMouseNode()
183 {
184  if (m_IsMouseNodeAttached)
185  {
186  this->DetachInteraction(false);
187  m_MouseNode->detachFromGraph();
188  m_IsMouseNodeAttached = false;
189  }
190 }
191 
192 bool mitk::SimulationInteractor::Impl::IsInteractionPerformerNotNull() const
193 {
194  return m_InteractionPerformer.get() != NULL;
195 }
196 
197 void mitk::SimulationInteractor::Impl::UpdatePickRay(InteractionPositionEvent* event)
198 {
199  if (!m_IsMouseNodeAttached)
200  return;
201 
202  vtkCamera* camera = event->GetSender()->GetVtkRenderer()->GetActiveCamera();
203 
204  Vec3d cameraOrigin(camera->GetPosition());
205  Vec3d pickedPosition(event->GetPositionInWorld().GetDataPointer());
206  Vec3d pickRayDirection(pickedPosition - cameraOrigin);
207  Vec3d focalPoint(camera->GetFocalPoint());
208 
209  Vec3d cameraDirection(focalPoint - cameraOrigin);
210  cameraDirection.normalize();
211 
212  std::pair<double, double> clippingRange;
213  camera->GetClippingRange(clippingRange.first, clippingRange.second);
214 
215  double dotProduct = dot(cameraDirection, pickRayDirection);
216  double norm = pickRayDirection.norm();
217 
218  clippingRange.first = clippingRange.first / dotProduct * norm;
219  clippingRange.second = clippingRange.second / dotProduct * norm;
220 
221  pickRayDirection.normalize();
222 
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);
227 
228  MechanicalPropagatePositionVisitor(MechanicalParams::defaultInstance(), 0, VecCoordId::position(), true)
229  .execute(m_PickRayModel->getContext());
230 
231  MechanicalPropagatePositionVisitor(MechanicalParams::defaultInstance(), 0, VecCoordId::freePosition(), true)
232  .execute(m_PickRayModel->getContext());
233 }
234 
235 void mitk::SimulationInteractor::Impl::FindCollision()
236 {
237  CollisionVisitor(ExecParams::defaultInstance()).execute(m_RootNode->getContext());
238 
239  if (m_UseCollisionPipeline)
240  {
241  m_LastBodyPicked = this->FindCollisionUsingPipeline();
242 
243  if (m_LastBodyPicked.body != NULL)
244  return;
245  }
246 
247  m_LastBodyPicked = this->FindCollisionUsingBruteForce();
248 }
249 
250 BodyPicked mitk::SimulationInteractor::Impl::FindCollisionUsingPipeline()
251 {
252  BodyPicked bodyPicked;
253 
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();
258 
259  const std::set<BaseRayContact*>& contacts = m_PickRayModel->getContacts();
260 
261  for (std::set<BaseRayContact*>::const_iterator contact = contacts.begin(); contact != contacts.end(); ++contact)
262  {
263  const vector<DetectionOutput*>& detectionOutputs = (*contact)->getDetectionOutputs();
264 
265  for (vector<DetectionOutput*>::const_iterator detectionOutput = detectionOutputs.begin(); detectionOutput != detectionOutputs.end(); ++detectionOutput)
266  {
267  CollisionElementIterator collisionElement;
268  int pointIndex;
269 
270  if ((*detectionOutput)->elem.first.getCollisionModel() == m_PickRayModel)
271  {
272  collisionElement = (*detectionOutput)->elem.second;
273  pointIndex = 1;
274  }
275  else if ((*detectionOutput)->elem.second.getCollisionModel() == m_PickRayModel)
276  {
277  collisionElement = (*detectionOutput)->elem.first;
278  pointIndex = 0;
279  }
280  else
281  {
282  continue;
283  }
284 
285  if (!collisionElement.getCollisionModel()->isSimulated())
286  continue;
287 
288  const double t = ((*detectionOutput)->point[pointIndex] - origin) * direction;
289 
290  if (t < 0.0 || t > length)
291  continue;
292 
293  if (bodyPicked.body == NULL || t < bodyPicked.rayLength)
294  {
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;
300  }
301  }
302  }
303 
304  return bodyPicked;
305 }
306 
307 BodyPicked mitk::SimulationInteractor::Impl::FindCollisionUsingBruteForce()
308 {
309  BodyPicked bodyPicked;
310 
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();
315 
316  MechanicalPickParticlesVisitor pickVisitor(ExecParams::defaultInstance(), origin, direction, length);
317  pickVisitor.execute(m_RootNode->getContext());
318 
319  if (!pickVisitor.particles.empty())
320  {
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);
326  bodyPicked.dist = 0;
327  bodyPicked.rayLength = (bodyPicked.point - origin) * direction;
328  }
329 
330  return bodyPicked;
331 }
332 
333 void mitk::SimulationInteractor::Impl::AttachCompatibleInteraction()
334 {
335  BaseContext* context;
336 
337  if (m_LastBodyPicked.body == NULL)
338  {
339  context = m_LastBodyPicked.mstate != NULL
340  ? m_LastBodyPicked.mstate->getContext()
341  : NULL;
342  }
343  else
344  {
345  context = m_LastBodyPicked.body->getContext();
346  }
347 
348  if (context != NULL)
349  {
350  if (m_Interaction == NULL || !m_Interaction->isCompatible(context))
351  {
352  bool foundCompatibleInteractor = false;
353 
354  for (std::vector<ComponentMouseInteraction*>::const_iterator it = m_InteractionComponents.begin(); it != m_InteractionComponents.end(); ++it)
355  {
356  if (*it != m_Interaction && (*it)->isCompatible(context))
357  {
358  this->DetachInteraction(false);
359  m_Interaction = *it;
360  m_Interaction->attach(m_MouseNode.get());
361 
362  foundCompatibleInteractor = true;
363  break;
364  }
365  }
366 
367  if (!foundCompatibleInteractor)
368  this->DetachInteraction(true);
369  }
370  }
371  else
372  {
373  this->DetachInteraction(true);
374  }
375 
376  if (m_Interaction != NULL)
377  {
378  m_Interaction->mouseInteractor->setMouseRayModel(m_PickRayModel.get());
379  m_Interaction->mouseInteractor->setBodyPicked(m_LastBodyPicked);
380  }
381 }
382 
383 void mitk::SimulationInteractor::Impl::DetachInteraction(bool setNull)
384 {
385  if (m_Interaction != NULL)
386  {
387  m_Interaction->detach();
388 
389  if (setNull)
390  m_Interaction = NULL;
391  }
392 }
393 
394 void mitk::SimulationInteractor::Impl::StartInteraction(const std::string& type)
395 {
396  if (m_Interaction == NULL)
397  return;
398 
399  InteractionPerformer::InteractionPerformerFactory* factory = InteractionPerformer::InteractionPerformerFactory::getInstance();
400  m_InteractionPerformer.reset(factory->createObject(type, m_Interaction->mouseInteractor.get()));
401 
402  if (m_InteractionPerformer.get() != NULL)
403  {
404  this->ConfigureInteractionPerformer();
405  m_Interaction->mouseInteractor->addInteractionPerformer(m_InteractionPerformer.get());
406  m_InteractionPerformer->start();
407  }
408 }
409 
410 void mitk::SimulationInteractor::Impl::ConfigureInteractionPerformer()
411 {
412  AttachBodyPerformer<Vec3Types>* attachBodyPerformer = dynamic_cast<AttachBodyPerformer<Vec3Types>*>(m_InteractionPerformer.get());
413 
414  if (attachBodyPerformer != NULL)
415  {
416  attachBodyPerformer->setStiffness(1000);
417  attachBodyPerformer->setArrowSize(0);
418  attachBodyPerformer->setShowFactorSize(1);
419  return;
420  }
421 
422  FixParticlePerformerConfiguration* fixParticlePerformer = dynamic_cast<FixParticlePerformerConfiguration*>(m_InteractionPerformer.get());
423 
424  if (fixParticlePerformer != NULL)
425  fixParticlePerformer->setStiffness(10000);
426 }
427 
428 void mitk::SimulationInteractor::Impl::ExecuteInteraction()
429 {
430  if (m_InteractionPerformer.get() == NULL)
431  return;
432 
433  m_InteractionPerformer->execute();
434 }
435 
436 void mitk::SimulationInteractor::Impl::StopInteraction()
437 {
438  if (m_InteractionPerformer.get() == NULL)
439  return;
440 
441  AttachBodyPerformer<Vec3Types>* attachBodyPerformer = dynamic_cast<AttachBodyPerformer<Vec3Types>*>(m_InteractionPerformer.get());
442 
443  if (attachBodyPerformer != NULL)
444  attachBodyPerformer->clear();
445 
446  m_Interaction->mouseInteractor->removeInteractionPerformer(m_InteractionPerformer.get());
447  m_InteractionPerformer.release();
448 }
449 
450 mitk::SimulationInteractor::SimulationInteractor()
451  : m_Impl(new Impl)
452 {
453 }
454 
455 mitk::SimulationInteractor::~SimulationInteractor()
456 {
457 }
458 
460 {
461  CONNECT_FUNCTION("startPrimaryInteraction", StartPrimaryInteraction);
462  CONNECT_FUNCTION("startSecondaryInteraction", StartSecondaryInteraction);
463  CONNECT_FUNCTION("stopInteraction", StopInteraction);
464  CONNECT_FUNCTION("executeInteraction", ExecuteInteraction);
465  CONNECT_CONDITION("isInteractionPerformerNotNull", IsInteractionPerformerNotNull);
466 }
467 
469 {
470  this->ResetToStartState();
471 
472  mitk::DataNode* dataNode = this->GetDataNode();
473 
474  if (dataNode != nullptr)
475  {
476  Simulation::Pointer simulation = dynamic_cast<Simulation*>(dataNode->GetData());
477 
478  if (simulation.IsNotNull())
479  {
480  m_Impl->Initialize(simulation->GetRootNode());
481  return;
482  }
483  }
484 
485  m_Impl->Uninitialize();
486 }
487 
488 void mitk::SimulationInteractor::StartInteraction(const std::string& type, InteractionPositionEvent* event)
489 {
490  m_Impl->AttachMouseNode();
491  m_Impl->UpdatePickRay(event);
492  m_Impl->FindCollision();
493  m_Impl->AttachCompatibleInteraction();
494  m_Impl->StartInteraction(type);
495 }
496 
497 void mitk::SimulationInteractor::StartPrimaryInteraction(StateMachineAction*, InteractionEvent* event)
498 {
499  this->StartInteraction("AttachBody", dynamic_cast<InteractionPositionEvent*>(event));
500 }
501 
502 void mitk::SimulationInteractor::StartSecondaryInteraction(StateMachineAction*, InteractionEvent* event)
503 {
504  this->StartInteraction("FixParticle", dynamic_cast<InteractionPositionEvent*>(event));
505 }
506 
507 void mitk::SimulationInteractor::StopInteraction(StateMachineAction*, InteractionEvent*)
508 {
509  m_Impl->StopInteraction();
510  m_Impl->DetachMouseNode();
511 }
512 
513 void mitk::SimulationInteractor::ExecuteInteraction(StateMachineAction*, InteractionEvent* event)
514 {
515  m_Impl->UpdatePickRay(dynamic_cast<InteractionPositionEvent*>(event));
516  m_Impl->ExecuteInteraction();
517 }
518 
519 bool mitk::SimulationInteractor::IsInteractionPerformerNotNull(const InteractionEvent*)
520 {
521  return m_Impl->IsInteractionPerformerNotNull();
522 }
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.
Definition: mitkDataNode.h:66