Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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