fw4spl
SProbeCursor.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/SProbeCursor.hpp"
8 
9 #include <fwCom/Slot.hpp>
10 #include <fwCom/Slot.hxx>
11 #include <fwCom/Slots.hpp>
12 #include <fwCom/Slots.hxx>
13 
14 #include <fwData/Image.hpp>
15 #include <fwData/Integer.hpp>
16 #include <fwData/TransferFunction.hpp>
17 
18 #include <fwDataTools/fieldHelper/Image.hpp>
19 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp>
20 #include <fwDataTools/helper/Image.hpp>
21 
22 #include <fwRenderVTK/vtk/Helpers.hpp>
23 
24 #include <fwServices/macros.hpp>
25 
26 #include <boost/format.hpp>
27 
28 #include <vtkAbstractPropPicker.h>
29 #include <vtkActor.h>
30 #include <vtkCellArray.h>
31 #include <vtkCellData.h>
32 #include <vtkCommand.h>
33 #include <vtkInteractorStyleImage.h>
34 #include <vtkPolyData.h>
35 #include <vtkPolyDataMapper.h>
36 #include <vtkProperty.h>
37 #include <vtkRenderWindowInteractor.h>
38 #include <vtkTextActor.h>
39 #include <vtkTextMapper.h>
40 #include <vtkTextProperty.h>
41 #include <vtkTransform.h>
42 
43 fwServicesRegisterMacro( ::fwRenderVTK::IAdaptor, ::visuVTKAdaptor::SProbeCursor);
44 
45 #define START_PROBE_EVENT vtkCommand::LeftButtonPressEvent
46 #define STOP_PROBE_EVENT vtkCommand::LeftButtonReleaseEvent
47 
48 namespace visuVTKAdaptor
49 {
50 
51 class ProbingCallback : public vtkCommand
52 {
53 public:
54  //------------------------------------------------------------------------------
55 
56  static ProbingCallback* New()
57  {
58  return new ProbingCallback();
59  }
60 
61  ProbingCallback() :
62  m_picker(nullptr),
63  m_priority(-1),
64  m_mouseMoveObserved(false)
65  {
66  this->PassiveObserverOff();
67  }
68 
70  {
71  }
72 
73  //------------------------------------------------------------------------------
74 
75  virtual void Execute( vtkObject* /*caller*/, unsigned long eventId, void*)
76  {
77  assert(m_priority >= 0);
78  SLM_ASSERT("m_adaptor not instanced", m_adaptor);
79  SLM_ASSERT("m_picker not instanced", m_picker);
80  if ( m_mouseMoveObserved || !m_adaptor->getInteractor()->GetShiftKey() )
81  {
82  if ( eventId == vtkCommand::MouseMoveEvent )
83  {
84  SLM_ASSERT("m_mouseMoveObserved not instanced", m_mouseMoveObserved);
85  process();
86  }
87  else if ( eventId == START_PROBE_EVENT)
88  {
89  assert(m_mouseMoveObserved == false );
90  if ( pickSomething() )
91  {
92  m_mouseMoveObserved = true;
93  SetAbortFlag(1);
94  m_adaptor->setVisibility(true);
95  m_adaptor->startSProbeCursor();
96  process();
97  m_adaptor->getInteractor()->AddObserver(vtkCommand::MouseMoveEvent, this, m_priority);
98  }
99  }
100  else if ( eventId == STOP_PROBE_EVENT && m_mouseMoveObserved)
101  {
102  SLM_ASSERT("m_mouseMoveObserved not instanced", m_mouseMoveObserved);
103  m_adaptor->setVisibility(false);
104  m_adaptor->getInteractor()->RemoveObservers(vtkCommand::MouseMoveEvent, this);
105  m_mouseMoveObserved = false;
106  }
107  }
108  }
109 
110  //------------------------------------------------------------------------------
111 
112  bool pickSomething()
113  {
114  int x, y;
115  double display[3];
116 
117  m_adaptor->getInteractor()->GetEventPosition(x, y);
118  display[0] = x;
119  display[1] = y;
120  display[2] = 0;
121 
122  return m_picker->Pick( display, m_adaptor->getRenderer() );
123  }
124 
125  //------------------------------------------------------------------------------
126 
127  void process() // from
128  {
129  double world[3] = {-1, 0, 0};
130  if ( pickSomething() )
131  {
132  ::fwRenderVTK::vtk::getNearestPickedPosition(m_picker, m_adaptor->getRenderer(), world);
133  OSLM_TRACE("PICK" << world[0] << " ," << world[1] << " ," << world[2] );
134  m_adaptor->updateView( world);
135  }
136  m_adaptor->updateView(world);
137  }
138 
139  //------------------------------------------------------------------------------
140 
141  void setAdaptor( SProbeCursor::sptr adaptor)
142  {
143  m_adaptor = adaptor;
144  }
145 
146  //------------------------------------------------------------------------------
147 
148  void setPicker( vtkAbstractPropPicker* adaptor)
149  {
150  m_picker = adaptor;
151  }
152 
153  //------------------------------------------------------------------------------
154 
155  void setPriority( float priority )
156  {
157  m_priority = priority;
158  }
159 
160 protected:
161  SProbeCursor::sptr m_adaptor;
162  vtkAbstractPropPicker* m_picker;
163  float m_priority;
164 
165  bool m_mouseMoveObserved;
166 
167 };
168 
169 const ::fwCom::Slots::SlotKeyType SProbeCursor::s_UPDATE_SLICE_INDEX_SLOT = "updateSliceIndex";
170 
171 static const ::fwServices::IService::KeyType s_IMAGE_INOUT = "image";
172 
173 //------------------------------------------------------------------------------
174 
175 SProbeCursor::SProbeCursor() noexcept :
176  m_priority(.6f),
177  m_vtkObserver(nullptr),
178  m_textActor(vtkActor2D::New()),
179  m_textMapper(vtkTextMapper::New()),
180  m_cursorPolyData( vtkPolyData::New() ),
181  m_cursorMapper(vtkPolyDataMapper::New() ),
182  m_cursorActor(vtkActor::New() )
183 {
184  newSlot(s_UPDATE_SLICE_INDEX_SLOT, &SProbeCursor::updateSliceIndex, this);
185 }
186 
187 //------------------------------------------------------------------------------
188 
189 SProbeCursor::~SProbeCursor() noexcept
190 {
191  m_textMapper->Delete();
192  m_textActor->Delete();
193 
194  m_cursorActor->Delete();
195  m_cursorActor = nullptr;
196  m_cursorMapper->Delete();
197  m_cursorMapper = nullptr;
198  m_cursorPolyData->Delete();
199 }
200 
201 //------------------------------------------------------------------------------
202 void SProbeCursor::setVisibility( bool visibility )
203 {
204  m_textActor->SetVisibility(visibility);
205  m_cursorActor->SetVisibility(visibility);
206  this->setVtkPipelineModified();
207  this->requestRender();
208 }
209 
210 //------------------------------------------------------------------------------
211 
213 {
214  this->configureParams();
215 }
216 
217 //------------------------------------------------------------------------------
218 
219 void SProbeCursor::buildTextActor()
220 {
221  vtkTextProperty* textprop = m_textMapper->GetTextProperty();
222  textprop->SetColor(1, 1, 1);
223  textprop->SetFontFamilyToArial();
224  textprop->SetFontSize(20);
225  textprop->BoldOn();
226  textprop->ItalicOff();
227  textprop->ShadowOn();
228  textprop->SetJustificationToLeft();
229  textprop->SetVerticalJustificationToTop();
230 
231  m_textActor->SetMapper( m_textMapper );
232 
233  vtkCoordinate* coord = m_textActor->GetPositionCoordinate();
234  coord->SetCoordinateSystemToNormalizedViewport();
235  coord->SetValue(.01, .98);
236  this->setVtkPipelineModified();
237 }
238 
239 //------------------------------------------------------------------------------
240 
242 {
243  this->initialize();
244 
245  this->buildTextActor();
246  this->addToRenderer(m_textActor );
247 
248  this->buildPolyData();
249  m_cursorMapper->SetInputData( m_cursorPolyData );
250  m_cursorActor->SetMapper(m_cursorMapper);
251  m_cursorActor->GetProperty()->SetColor(1, 0, 0);
252  m_cursorActor->GetProperty()->SetOpacity(0.9);
253  if(!this->getTransformId().empty())
254  {
255  m_cursorActor->SetUserTransform(this->getTransform());
256  }
257  this->addToRenderer(m_cursorActor);
258 
259  ProbingCallback* observer = ProbingCallback::New();
260  observer->setAdaptor( SProbeCursor::dynamicCast(this->getSptr()) );
261  observer->setPicker(this->getPicker());
262  observer->setPriority( m_priority );
263 
264  m_vtkObserver = observer;
265 
266  this->getInteractor()->AddObserver(START_PROBE_EVENT, m_vtkObserver, m_priority);
267  this->getInteractor()->AddObserver(STOP_PROBE_EVENT, m_vtkObserver, m_priority);
268 
269  this->updating();
270 }
271 
272 //------------------------------------------------------------------------------
273 
275 {
276  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
277  SLM_ASSERT("Missing image", image);
278 
279  this->updateImageInfos(image);
280  this->setVisibility(false);
281  this->requestRender();
282 }
283 
284 //------------------------------------------------------------------------------
285 
287 {
288  this->getInteractor()->RemoveObservers(START_PROBE_EVENT, m_vtkObserver);
289  this->getInteractor()->RemoveObservers(STOP_PROBE_EVENT, m_vtkObserver);
290  m_vtkObserver->Delete();
291  m_vtkObserver = nullptr;
292  this->removeAllPropFromRenderer();
293  this->requestRender();
294 }
295 
296 //-----------------------------------------------------------------------------
297 
298 void SProbeCursor::updateSliceIndex(int axial, int frontal, int sagittal)
299 {
300  m_axialIndex->value() = axial;
301  m_frontalIndex->value() = frontal;
302  m_sagittalIndex->value() = sagittal;
303 }
304 
305 //------------------------------------------------------------------------------
306 
307 void SProbeCursor::startSProbeCursor( )
308 {
309 }
310 
311 //------------------------------------------------------------------------------
312 
313 void SProbeCursor::updateView( double world[3] )
314 {
315  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
316  SLM_ASSERT("Missing image", image);
317 
318  int index[3];
319  this->worldToImageSliceIndex( world, index );
320  OSLM_TRACE("index=" << index[0] << "," << index[1] << "," << index[2] << "," );
321 
322  std::string txt;
323 
324  if ( world[0] < image->getOrigin()[0] || world[1] < image->getOrigin()[1] || world[2] < image->getOrigin()[2] ||
325  index[0] < 0 || index[1] < 0 || index[2] < 0 ||
326  index[0] >= static_cast<int>(image->getSize()[0]) ||
327  index[1] >= static_cast<int>(image->getSize()[1]) ||
328  index[2] >= static_cast<int>(image->getSize()[2])
329  )
330  {
331  txt = "(---,---,---)";
332  m_textMapper->SetInput(txt.c_str());
333  }
334  else
335  {
336  ::fwDataTools::helper::Image imageHelper(image);
337  const size_t x = static_cast<size_t>(index[0]);
338  const size_t y = static_cast<size_t>(index[1]);
339  const size_t z = static_cast<size_t>(index[2]);
340  const std::string greyLevel = imageHelper.getPixelAsString(x, y, z);
341  txt = (::boost::format("(% 4li,% 4li, % 4li) : %s ") % index[0] % index[1] % index[2] % greyLevel ).str();
342 
343  m_textMapper->SetInput(txt.c_str());
344 
345  // update polyData
346  double worldCross[4][3];
347  this->computeCrossExtremity(image, index, worldCross);
348 
349  vtkPoints* points = m_cursorPolyData->GetPoints();
350  for ( int i = 0; i < 4; ++i)
351  {
352  OSLM_TRACE("p=" << worldCross[i][0] << "," << worldCross[i][2] << "," << worldCross[i][2] << "," );
353  points->SetPoint(i, worldCross[i]);
354  }
355  m_cursorPolyData->Modified();
356  }
357  this->setVtkPipelineModified();
358  this->requestRender();
359 }
360 
361 //------------------------------------------------------------------------------
362 
363 void SProbeCursor::computeCrossExtremity(::fwData::Image::csptr image, const int probeSlice[3],
364  double worldCross[4][3] )
365 {
366  int sliceIndex[3]; // the current sliceIndex
367 
368  sliceIndex[2] = m_axialIndex->value();
369  sliceIndex[1] = m_frontalIndex->value();
370  sliceIndex[0] = m_sagittalIndex->value();
371 
372  double probeWorld[3]; // probe index in world positioning system
373  for (unsigned int dim = 0; dim < 3; ++dim )
374  {
375  if ( probeSlice[dim] == sliceIndex[dim] ) // FIXME if (sliceIndex==probeWorld)
376  {
377  this->setOrientation(static_cast<int>(dim));
378  }
379  probeWorld[dim] = probeSlice[dim]*image->getSpacing()[dim] + image->getOrigin().at(dim);
380  }
381 
382  for (unsigned int p = 0; p < 2; ++p )
383  {
384  for (unsigned int dim = 0; dim < 3; ++dim )
385  {
386  worldCross[p][dim] = probeWorld[dim];
387  worldCross[p+2][dim] = probeWorld[dim];
388  if ( (dim + p + 1)%3 == m_orientation )
389  {
390  worldCross[p][dim] = image->getOrigin().at(dim);
391  const ::fwData::Image::SizeType::value_type size = image->getSize().at(dim)-1;
392  const ::fwData::Image::SpacingType::value_type spacing = image->getSpacing().at(dim);
393  worldCross[p+2][dim] = size * spacing + image->getOrigin().at(dim);
394  }
395  }
396  }
397 }
398 
399 //------------------------------------------------------------------------------
400 
401 void SProbeCursor::buildPolyData()
402 {
403  // point are stored Left,right,up,down
404  int nbPoints = 4;
405  vtkPoints* points = vtkPoints::New(VTK_DOUBLE);
406  points->SetNumberOfPoints(nbPoints);
407  int i;
408  for (i = 0; i < nbPoints; i++)
409  {
410  points->SetPoint(i, 0.0, 0.0, 0.0);
411  }
412 
413  vtkCellArray* cells = vtkCellArray::New();
414  cells->Allocate(cells->EstimateSize(nbPoints, 2));
415 
416  vtkIdType pts[2];
417  pts[0] = 0; pts[1] = 2;
418  cells->InsertNextCell(2, pts);
419  pts[0] = 1; pts[1] = 3;
420  cells->InsertNextCell(2, pts);
421 
422  m_cursorPolyData->SetPoints(points);
423  points->Delete();
424  m_cursorPolyData->SetLines(cells);
425  cells->Delete();
426  this->setVtkPipelineModified();
427 }
428 
429 //------------------------------------------------------------------------------
430 
432 {
433  KeyConnectionsMap connections;
434  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_MODIFIED_SIG, s_UPDATE_SLOT);
435  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_SLICE_INDEX_MODIFIED_SIG, s_UPDATE_SLICE_INDEX_SLOT);
436  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_BUFFER_MODIFIED_SIG, s_UPDATE_SLOT);
437 
438  return connections;
439 }
440 
441 //------------------------------------------------------------------------------
442 
443 } //namespace visuVTKAdaptor
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_SLICE_INDEX_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
This class is a helper to define the connections of a service and its data.
Definition: IService.hpp:454
The namespace visuVTKAdaptor contains the list of adaptors available for the generic scene...
Cursor management: displays a red cross representing the image picked point.
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
virtual VISUVTKADAPTOR_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
Defines an helper to modify an fwData::Image by adding few medical fields and create in parallel the ...
FWDATATOOLS_API const std::string getPixelAsString(SizeType::value_type x, SizeType::value_type y, SizeType::value_type z)
Helpers for 3D images.
VISUVTKADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
#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
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_BUFFER_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
VISUVTKADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...