fw4spl
SPickerInteractor.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "visuVTKAdaptor/SPickerInteractor.hpp"
8 
9 #include <fwCom/Signal.hpp>
10 #include <fwCom/Signal.hxx>
11 #include <fwCom/Signals.hpp>
12 
13 #include <fwCore/HiResClock.hpp>
14 
15 #include <fwData/Composite.hpp>
16 #include <fwData/Material.hpp>
17 #include <fwData/Reconstruction.hpp>
18 
19 #include <fwRenderVTK/vtk/Helpers.hpp>
20 
21 #include <fwServices/macros.hpp>
22 
23 #include <boost/tokenizer.hpp>
24 
25 #include <vtkAbstractPropPicker.h>
26 #include <vtkActor.h>
27 #include <vtkCellPicker.h>
28 #include <vtkCommand.h>
29 #include <vtkCubeSource.h>
30 #include <vtkPolyDataMapper.h>
31 #include <vtkRenderWindowInteractor.h>
32 
33 #define START_INTERACTION_EVENT vtkCommand::LeftButtonPressEvent
34 #define STOP_INTERACTION_EVENT vtkCommand::LeftButtonReleaseEvent
35 
36 fwServicesRegisterMacro( ::fwRenderVTK::IAdaptor, ::visuVTKAdaptor::SPickerInteractor);
37 
38 namespace visuVTKAdaptor
39 {
40 
41 const std::map< unsigned long, ::fwDataTools::PickingInfo::Event > SPickerInteractor::s_vtkEventIDConversion
42 {
43  { vtkCommand::LeftButtonReleaseEvent, ::fwDataTools::PickingInfo::Event::MOUSE_LEFT_UP },
44  { vtkCommand::RightButtonReleaseEvent, ::fwDataTools::PickingInfo::Event::MOUSE_RIGHT_UP },
45  { vtkCommand::MiddleButtonReleaseEvent, ::fwDataTools::PickingInfo::Event::MOUSE_MIDDLE_UP },
46  { vtkCommand::MouseWheelForwardEvent, ::fwDataTools::PickingInfo::Event::MOUSE_WHEELFORWARD },
47  { vtkCommand::LeftButtonPressEvent, ::fwDataTools::PickingInfo::Event::MOUSE_LEFT_DOWN },
48  { vtkCommand::RightButtonPressEvent, ::fwDataTools::PickingInfo::Event::MOUSE_RIGHT_DOWN },
49  { vtkCommand::MiddleButtonPressEvent, ::fwDataTools::PickingInfo::Event::MOUSE_MIDDLE_DOWN },
50  { vtkCommand::MouseWheelBackwardEvent, ::fwDataTools::PickingInfo::Event::MOUSE_WHEELBACKWARD },
51  { vtkCommand::MouseMoveEvent, ::fwDataTools::PickingInfo::Event::MOUSE_MOVE },
52  { vtkCommand::KeyPressEvent, ::fwDataTools::PickingInfo::Event::KEY_PRESS }
53 };
54 
56 {
57  { std::string("MOUSE_LEFT_UP"), MOUSE_LEFT_UP },
58  { std::string("MOUSE_RIGHT_UP"), MOUSE_RIGHT_UP },
59  { std::string("MOUSE_MIDDLE_UP"), MOUSE_MIDDLE_UP },
60  { std::string("MOUSE_WHEELBACKWARD"), MOUSE_WHEELBACKWARD },
61  { std::string("MOUSE_LEFT_DOWN"), MOUSE_LEFT_DOWN },
62  { std::string("MOUSE_RIGHT_DOWN"), MOUSE_RIGHT_DOWN },
63  { std::string("MOUSE_MIDDLE_DOWN"), MOUSE_MIDDLE_DOWN },
64  { std::string("MOUSE_WHEELBACKWARD"), MOUSE_WHEELBACKWARD },
65  { std::string("MOUSE_MOVE"), MOUSE_MOVE },
66  { std::string("KEY_PRESS"), KEY_PRESS }
67 };
68 
69 const ::fwCom::Signals::SignalKeyType SPickerInteractor::s_PICKED_SIGNAL = "picked";
70 
71 //------------------------------------------------------------------------------
72 
73 class SPickerInteractorCallback : public vtkCommand
74 {
75 public:
76  //------------------------------------------------------------------------------
77 
78  static SPickerInteractorCallback* New()
79  {
80  return new SPickerInteractorCallback();
81  }
82 
84  m_eventId(nullptr),
85  m_picker(nullptr)
86  {
87  }
88 
90  {
91  }
92 
93  //------------------------------------------------------------------------------
94 
95  virtual void Execute( vtkObject* caller, unsigned long eventId, void*)
96  {
97  SLM_ASSERT("m_adaptor not instanced", m_adaptor);
98  SLM_ASSERT("m_picker not instanced", m_picker);
99 
100  this->process(vtkRenderWindowInteractor::SafeDownCast(caller), eventId);
101  }
102 
103  //------------------------------------------------------------------------------
104 
105  bool pickSomething()
106  {
107  int x, y;
108  double display[3];
109 
110  m_adaptor->getInteractor()->GetEventPosition(x, y);
111  display[0] = x;
112  display[1] = y;
113  display[2] = 0;
114 
115  return (m_picker->Pick( display, m_adaptor->getRenderer() ) != 0);
116  }
117 
118  //------------------------------------------------------------------------------
119 
120  void process(vtkRenderWindowInteractor* caller, unsigned long eventId) // from
121  {
122  SLM_ASSERT("bad vtk caller", caller);
123  if( m_eventId->find( static_cast< SPickerInteractor::EventID>(eventId) ) != m_eventId->end() )
124  {
125 #ifdef __linux
126  if(eventId == SPickerInteractor::MOUSE_MOVE)
129  {
130  m_skipMove++;
131  if( m_skipMove % 10 )
132  {
133  return;
134  }
135  }
136 #endif
137  if(this->pickSomething())
138  {
140  ::fwRenderVTK::vtk::getNearestPickedPosition(m_picker, m_adaptor->getRenderer(), info.m_worldPos);
141  OSLM_TRACE("PICK" << info.m_worldPos[0] << " ," << info.m_worldPos[1] << " ," << info.m_worldPos[2] );
142 
143  info.m_modifierMask =
144  caller->GetControlKey() ? ::fwDataTools::PickingInfo::CTRL : ::fwDataTools::PickingInfo::NONE;
145  info.m_modifierMask |=
146  caller->GetShiftKey() ? ::fwDataTools::PickingInfo::SHIFT : ::fwDataTools::PickingInfo::NONE;
147 
148  vtkCellPicker* picker = vtkCellPicker::SafeDownCast( m_picker );
149  if (picker)
150  {
151  info.m_cellId = static_cast<int>(picker->GetCellId());
152  info.m_closestPointId = static_cast<int>(picker->GetPointId());
153  }
154 
155  const auto iter = SPickerInteractor::s_vtkEventIDConversion.find(eventId);
156  SLM_ASSERT("Unknown eventId", iter != SPickerInteractor::s_vtkEventIDConversion.end());
157  info.m_eventId = iter->second;
158 
159  info.m_keyPressed = caller->GetKeyCode();
160  OSLM_TRACE("EVENT" << static_cast<int>(info.m_eventId) );
161  OSLM_TRACE("KEY" << info.m_keyPressed << " - MASK " << static_cast<int>(info.m_modifierMask) );
162 
163  info.m_timestamp = ::fwCore::HiResClock::getTimeInMilliSec();
164 
165  auto sig = m_adaptor->signal<SPickerInteractor::PickedSignalType>(
166  SPickerInteractor::s_PICKED_SIGNAL);
167  sig->asyncEmit(info);
168 
169  // The "abortOnPick" flag has been set
170  if(this->GetPassiveObserver() != 1)
171  {
172  this->AbortFlagOn();
173  }
174  }
175  }
176  }
177 
178  //------------------------------------------------------------------------------
179 
180  void setAdaptor( SPickerInteractor::sptr adaptor)
181  {
182  m_adaptor = adaptor;
183  }
184 
185  //------------------------------------------------------------------------------
186 
187  void setPicker( vtkAbstractPropPicker* picker)
188  {
189  m_picker = picker;
190  }
191 
192  //------------------------------------------------------------------------------
193 
194  void setEventId(SPickerInteractor::SetEventIdType* eventId)
195  {
196  m_eventId = eventId;
197  }
198 
199 protected:
200  SPickerInteractor::SetEventIdType* m_eventId;
201  SPickerInteractor::sptr m_adaptor;
202  vtkAbstractPropPicker* m_picker;
203 #ifdef __linux
204  unsigned int m_skipMove = 0u;
205 #endif // __linux
206 
207 };
208 
209 //------------------------------------------------------------------------------
210 
211 SPickerInteractor::SPickerInteractor() noexcept :
212  m_interactionCommand(nullptr)
213 {
214  newSignal<PickedSignalType>(s_PICKED_SIGNAL);
215 }
216 
217 //------------------------------------------------------------------------------
218 
219 SPickerInteractor::~SPickerInteractor() noexcept
220 {
221 }
222 
223 //------------------------------------------------------------------------------
224 
226 {
227  this->configureParams();
228 
229  const ConfigType config = this->getConfigTree().get_child("config.<xmlattr>");
230 
231  if (config.count("event"))
232  {
233  const std::string eventTxt = config.get<std::string>("event");
234 
235  ::boost::char_separator<char> sep(", ;");
236  ::boost::tokenizer< ::boost::char_separator<char> > tok(eventTxt, sep);
237  for( const auto& it : tok)
238  {
239  const auto iter = m_eventIdConversion.find(it);
240  SLM_ASSERT("Unknown eventId '"+ it+"'.", iter != m_eventIdConversion.end());
241  m_eventId.insert(iter->second);
242  }
243  }
244  else
245  {
246  for(auto elt : m_eventIdConversion)
247  {
248  m_eventId.insert(elt.second);
249  }
250  }
251 
252  m_abortOnPick = config.get<bool>("abortOnPick", false);
253 }
254 
255 //------------------------------------------------------------------------------
256 
258 {
259  this->initialize();
260 
261  SPickerInteractorCallback* observer = SPickerInteractorCallback::New();
262  observer->SetPassiveObserver(static_cast<int>(!m_abortOnPick));
263  observer->setAdaptor( SPickerInteractor::dynamicCast(this->getSptr()) );
264  observer->setPicker(this->getPicker());
265  observer->setEventId(&m_eventId);
266 
267  m_interactionCommand = observer;
268 
269  vtkRenderWindowInteractor* interactor = this->getInteractor();
270  const float priority = 0.999f;
271  interactor->AddObserver(vtkCommand::LeftButtonPressEvent, m_interactionCommand, priority);
272  interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, m_interactionCommand, priority);
273  interactor->AddObserver(vtkCommand::MiddleButtonPressEvent, m_interactionCommand, priority);
274  interactor->AddObserver(vtkCommand::MiddleButtonReleaseEvent, m_interactionCommand, priority);
275  interactor->AddObserver(vtkCommand::RightButtonPressEvent, m_interactionCommand, priority);
276  interactor->AddObserver(vtkCommand::RightButtonReleaseEvent, m_interactionCommand, priority);
277  interactor->AddObserver(vtkCommand::MouseMoveEvent, m_interactionCommand, priority);
278  interactor->AddObserver(vtkCommand::MouseWheelForwardEvent, m_interactionCommand, priority);
279  interactor->AddObserver(vtkCommand::MouseWheelBackwardEvent, m_interactionCommand, priority);
280  interactor->AddObserver(vtkCommand::KeyPressEvent, m_interactionCommand, priority);
281 
282 }
283 
284 //------------------------------------------------------------------------------
285 
287 {
288 }
289 
290 //------------------------------------------------------------------------------
291 
293 {
294  vtkRenderWindowInteractor* interactor = this->getInteractor();
295  interactor->RemoveObservers(vtkCommand::LeftButtonPressEvent, m_interactionCommand);
296  interactor->RemoveObservers(vtkCommand::LeftButtonReleaseEvent, m_interactionCommand);
297  interactor->RemoveObservers(vtkCommand::MiddleButtonPressEvent, m_interactionCommand);
298  interactor->RemoveObservers(vtkCommand::MiddleButtonReleaseEvent, m_interactionCommand);
299  interactor->RemoveObservers(vtkCommand::RightButtonPressEvent, m_interactionCommand);
300  interactor->RemoveObservers(vtkCommand::RightButtonReleaseEvent, m_interactionCommand);
301  interactor->RemoveObservers(vtkCommand::MouseMoveEvent, m_interactionCommand);
302  interactor->RemoveObservers(vtkCommand::MouseWheelForwardEvent, m_interactionCommand);
303  interactor->RemoveObservers(vtkCommand::MouseWheelBackwardEvent, m_interactionCommand);
304  interactor->RemoveObservers(vtkCommand::KeyPressEvent, m_interactionCommand);
305 
306  m_interactionCommand->Delete();
307  m_interactionCommand = nullptr;
308 }
309 
310 //------------------------------------------------------------------------------
311 
312 } //namespace visuVTKAdaptor
double m_worldPos[3]
Position clicked in world coordinates.
Definition: PickingInfo.hpp:44
This service emits a signal when the user click on a actor in the scene.
The namespace visuVTKAdaptor contains the list of adaptors available for the generic scene...
int m_closestPointId
Id of the closest point.
Definition: PickingInfo.hpp:48
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
std::int8_t m_modifierMask
Modifier mask.
Definition: PickingInfo.hpp:52
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
static MapEventIdType m_eventIdConversion
map containing the association between &#39;event text&#39; and &#39;event ID&#39;.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
VISUVTKADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
VISUVTKADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
Structure to store picking information.
Definition: PickingInfo.hpp:20
char m_keyPressed
Key event.
Definition: PickingInfo.hpp:54
std::map< std::string, EventID > MapEventIdType
typedef for the map (seen below).
Event m_eventId
Mouse event.
Definition: PickingInfo.hpp:50
int m_cellId
Id of the cell.
Definition: PickingInfo.hpp:46