fw4spl
SImageMultiDistances.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
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/SImageMultiDistances.hpp"
8 
9 #include "visuVTKAdaptor/SDistance.hpp"
10 #include "visuVTKAdaptor/SPointList.hpp"
11 
12 #include <fwCom/Signal.hpp>
13 #include <fwCom/Signal.hxx>
14 #include <fwCom/Slot.hpp>
15 #include <fwCom/Slot.hxx>
16 #include <fwCom/Slots.hpp>
17 #include <fwCom/Slots.hxx>
18 
19 #include <fwData/Boolean.hpp>
20 #include <fwData/Color.hpp>
21 #include <fwData/Image.hpp>
22 #include <fwData/Material.hpp>
23 #include <fwData/String.hpp>
24 #include <fwData/Vector.hpp>
25 
26 #include <fwDataTools/fieldHelper/Image.hpp>
27 
28 #include <fwServices/macros.hpp>
29 #include <fwServices/op/Add.hpp>
30 
31 #include <fwTools/fwID.hpp>
32 
33 #include <boost/assign/std/vector.hpp>
34 
35 #include <vtkActor.h>
36 #include <vtkAssemblyNode.h>
37 #include <vtkAssemblyPath.h>
38 #include <vtkCamera.h>
39 #include <vtkCellPicker.h>
40 #include <vtkCommand.h>
41 #include <vtkCubeSource.h>
42 #include <vtkInteractorStyle.h>
43 #include <vtkPolyDataMapper.h>
44 #include <vtkRenderer.h>
45 #include <vtkRenderWindow.h>
46 #include <vtkRenderWindowInteractor.h>
47 
48 #include <algorithm>
49 #include <sstream>
50 
51 fwServicesRegisterMacro( ::fwRenderVTK::IAdaptor, ::visuVTKAdaptor::SImageMultiDistances);
52 
53 namespace visuVTKAdaptor
54 {
55 
56 const ::fwServices::IService::KeyType s_IMAGE_INOUT = "image";
57 
58 //------------------------------------------------------------------------------
59 
60 class vtkDistanceDeleteCallBack : public vtkCommand
61 {
62 
63 public:
64 
65  //------------------------------------------------------------------------------
66 
67  static vtkDistanceDeleteCallBack* New( SImageMultiDistances* service )
68  {
69  return new vtkDistanceDeleteCallBack(service);
70  }
71 
73  m_service(service),
74  m_picker( vtkSmartPointer< vtkCellPicker>::New() ),
75  m_propCollection( vtkSmartPointer< vtkPropCollection>::New() )
76  {
77  m_lastPos[0] = -1;
78  m_lastPos[1] = -1;
79  m_picker->PickFromListOn();
80  m_picker->SetTolerance(0.001);
81 
82  m_display[2] = 0.0;
83  }
84 
85  //------------------------------------------------------------------------------
86 
87  void fillPickList()
88  {
89  m_picker->InitializePickList();
90  m_propCollection->RemoveAllItems();
91  m_service->getAllSubProps(m_propCollection);
92  m_propCollection->InitTraversal();
93 
94  vtkProp* prop;
95 
96  while ( (prop = m_propCollection->GetNextProp()) )
97  {
98  m_picker->AddPickList(prop);
99  }
100  }
101 
102  //------------------------------------------------------------------------------
103 
104  virtual void Execute( vtkObject* /*caller*/, unsigned long eventId, void*)
105  {
106  int pos[2];
107  m_service->getInteractor()->GetLastEventPosition(pos);
108 
109  if ( eventId == vtkCommand::RightButtonPressEvent )
110  {
111  std::copy(pos, pos+1, m_lastPos);
112  }
113  else if ( ( eventId == vtkCommand::RightButtonReleaseEvent ) ||
114  (( eventId == vtkCommand::StartInteractionEvent) && std::equal(pos, pos+1, m_lastPos) ))
115  {
116  m_display[0] = pos[0];
117  m_display[1] = pos[1];
118 
119  this->fillPickList();
120  if (m_picker->Pick( m_display, m_service->getRenderer() ) )
121  {
122  vtkPropCollection* propc = m_picker->GetActors();
123  vtkProp* prop;
124 
125  propc->InitTraversal();
126  while ( (prop = propc->GetNextProp()) )
127  {
128  ::fwRenderVTK::IAdaptor::sptr plAdaptor = m_service->getAssociatedAdaptor(prop, 1);
129  if (plAdaptor)
130  {
131  ::fwData::PointList::csptr plist =
132  plAdaptor->getInput< ::fwData::PointList >(SPointList::s_POINTLIST_INPUT);
133 
134  ::fwData::Image::sptr image = m_service->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
135  auto sig = image->signal< ::fwData::Image::DistanceRemovedSignalType >(
137  sig->asyncEmit(plist);
138 
139  break;
140  }
141  }
142  }
143  }
144  }
145 
146 protected:
147 
148  SImageMultiDistances* m_service;
149  vtkSmartPointer< vtkPicker> m_picker;
150  vtkSmartPointer< vtkPropCollection> m_propCollection;
151  double m_display[3];
152  int m_lastPos[2];
153 
154 };
155 
156 static const ::fwCom::Slots::SlotKeyType s_CREATE_DISTANCE_SLOT = "createDistance";
157 static const ::fwCom::Slots::SlotKeyType s_REMOVE_DISTANCE_SLOT = "removeDistance";
158 
159 //------------------------------------------------------------------------------
160 
161 SImageMultiDistances::SImageMultiDistances() noexcept :
162  m_rightButtonCommand(nullptr),
163  m_needSubservicesDeletion(false),
164  m_filter(false)
165 {
166  newSlot(s_CREATE_DISTANCE_SLOT, &SImageMultiDistances::createDistance, this);
167  newSlot(s_REMOVE_DISTANCE_SLOT, &SImageMultiDistances::removeDistance, this);
168 }
169 
170 //------------------------------------------------------------------------------
171 
172 SImageMultiDistances::~SImageMultiDistances() noexcept
173 {
174 }
175 
176 //------------------------------------------------------------------------------
177 
179 {
180  this->configureParams();
181 
182  const ConfigType config = this->getConfigTree().get_child("config.<xmlattr>");
183 
184  const std::string filter = config.get<std::string>("filter", "false");
185  SLM_ASSERT("'filter' value must be 'true' or 'false'", filter == "true" || filter == "false");
186  m_filter = (filter == "true");
187 }
188 
189 //------------------------------------------------------------------------------
190 
192 {
193  this->initialize();
194 
195  m_rightButtonCommand = vtkDistanceDeleteCallBack::New(this);
196  this->getInteractor()->AddObserver( "RightButtonPressEvent", m_rightButtonCommand, 1 );
197  this->getInteractor()->AddObserver( "RightButtonReleaseEvent", m_rightButtonCommand, 1 );
198  this->getInteractor()->AddObserver( "StartInteractionEvent", m_rightButtonCommand, 0);
199 
200  this->updating();
201 }
202 
203 //------------------------------------------------------------------------------
204 
205 ::fwData::Color::sptr generateColor()
206 {
207  using namespace fwData;
208 
209  static std::vector< Color::sptr > colors;
210  static std::vector< Color::sptr >::iterator current;
211  if ( colors.empty() )
212  {
213  Color::sptr magenta = Color::New();
214  magenta->setRGBA( 1, 0, 1);
215  colors.push_back( magenta );
216 
217  Color::sptr cyan = Color::New();
218  cyan->setRGBA(0, 1, 1);
219  colors.push_back( cyan );
220 
221  Color::sptr orange = Color::New();
222  orange->setRGBA( 1, 0.647f, 0);
223  colors.push_back( orange );
224 
225  Color::sptr violet = Color::New();
226  violet->setRGBA( .5f, 0.26f, 1);
227  colors.push_back( violet );
228 
229  Color::sptr vertpomme = Color::New();
230  vertpomme->setRGBA( .65f, 1, 0);
231  colors.push_back( vertpomme );
232 
233  Color::sptr jaune = Color::New();
234  jaune->setRGBA( 1, 1, 0);
235  colors.push_back( jaune );
236 
237  current = colors.begin();
238  }
239 
240  if ( ++current == colors.end() )
241  {
242  current = colors.begin();
243  }
244 
245  Color::sptr newColor;
246  newColor = ::fwData::Object::copy( *current );
247  return newColor;
248 }
249 
250 //------------------------------------------------------------------------------
251 
252 void SImageMultiDistances::installSubServices( ::fwData::PointList::sptr pl )
253 {
254  if ( pl->getPoints().size() > 1 )
255  {
256  // create the srv configuration for objects auto-connection
257  auto serviceDistance = this->registerService< ::fwRenderVTK::IAdaptor>("::visuVTKAdaptor::SDistance");
258 
259  // register image
260  serviceDistance->registerInput(pl, SDistance::s_POINTLIST_INPUT, true);
261 
262  // install Color Field if none
263  pl->setDefaultField( ::fwDataTools::fieldHelper::Image::m_colorId, generateColor() );
264 
265  // no mandatory to set picker id
266  serviceDistance->setPickerId( this->getPickerId() );
267  serviceDistance->setRendererId( this->getRendererId() );
268  serviceDistance->setRenderService( this->getRenderService() );
269  serviceDistance->start();
270 
271  // create the srv configuration for objects auto-connection
272  IService::Config srvPLConfig;
273  auto servicePointList = this->registerService< ::fwRenderVTK::IAdaptor>("::visuVTKAdaptor::SPointList");
274  // register image
275  servicePointList->registerInput(pl, SPointList::s_POINTLIST_INPUT, true);
276 
277  servicePointList->setPickerId( this->getPickerId() );
278  servicePointList->setRendererId( this->getRendererId() );
279  servicePointList->setRenderService( this->getRenderService() );
280  servicePointList->start();
281  }
282 }
283 
284 //------------------------------------------------------------------------------
285 
286 ::fwData::Point::sptr SImageMultiDistances::screenToWorld(int X, int Y)
287 {
288  double* world;
289  double display[3];
290  double worldTmp[4];
291  display[0] = X;
292  display[1] = Y;
293  display[2] = 0;
294 
295  if ( this->getPicker() && this->getPicker()->Pick( display, this->getRenderer() ) )
296  {
297  world = this->getPicker()->GetPickPosition();
298  }
299  else
300  {
301  // set temporaly the clipping around the focal point : see (1)
302  vtkCamera* camera = this->getRenderer()->GetActiveCamera();
303  double* clippingCamBackup = camera->GetClippingRange();
304  // set the clipping around the focal point
305  camera->SetClippingRange( camera->GetDistance() - 0.1, camera->GetDistance() + 0.1 );
306 
307  world = worldTmp;
308  // (1) this function use the near clipping range to estimate the world point (by defaut 0.1 from camera view).
309  // The clipping can be modified
310  // by insertion of new object. By setting previously the clipping to the focal point we ensure to not place new
311  // point a camera position
312  // RETURN HOMOGEN COORD !!!
313  this->getInteractor()->GetInteractorStyle()->ComputeDisplayToWorld( this->getRenderer(), X, Y, 0, world);
314 
315  // restore initial clipping
316  camera->SetClippingRange( clippingCamBackup );
317  }
318 
319  ::fwData::Point::sptr pt = ::fwData::Point::New();
320  std::copy( world, world +3, pt->getCoord().begin() );
321  this->setVtkPipelineModified();
322  return pt;
323 }
324 
325 //------------------------------------------------------------------------------
326 
328 {
329  // get PointList in image Field then install distance service if required
330  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
331  SLM_ASSERT("Missing image", image);
332 
333  ::fwData::Vector::sptr distanceField;
334  distanceField = image->getField< ::fwData::Vector >( ::fwDataTools::fieldHelper::Image::m_imageDistancesId);
335 
336  bool isShown;
337  isShown = image->getField("ShowDistances", ::fwData::Boolean::New(true))->value();
338 
339  this->unregisterServices();
340 
341  if( isShown && distanceField )
342  {
343  for(::fwData::Object::sptr object : *distanceField)
344  {
345  ::fwData::PointList::sptr distance = ::fwData::PointList::dynamicCast(object);
346  ::fwData::String::sptr relatedService = distance->getField< ::fwData::String >(
348 
349  if ( m_filter && relatedService )
350  {
351  std::string servId = relatedService->value();
352  if ( this->getRenderService()->getID() != servId )
353  {
354  continue; // filtering ON + distance instanced from another RenderService
355  }
356  }
357  // test pass OK : install service
358  SLM_ASSERT( "Empty Point List for Distance !!!!", !distance->getPoints().empty() );
359  this->installSubServices(distance);
360  }
361  }
362  this->setVtkPipelineModified();
363 }
364 
365 //------------------------------------------------------------------------------
366 
367 void SImageMultiDistances::removeDistance(::fwData::PointList::csptr plToRemove )
368 {
369  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
370  SLM_ASSERT("Missing image", image);
371 
372  this->unregisterServices();
373 
374  ::fwData::Vector::sptr distanceField;
375  distanceField = image->getField< ::fwData::Vector >( ::fwDataTools::fieldHelper::Image::m_imageDistancesId);
376 
377  ::fwData::Vector::IteratorType iter = std::find(distanceField->begin(), distanceField->end(), plToRemove);
378  if(iter != distanceField->end())
379  {
380  distanceField->getContainer().erase(iter);
381  }
382 
383  this->updating();
384 }
385 
386 //------------------------------------------------------------------------------
387 
388 void SImageMultiDistances::createDistance()
389 {
390  std::string sceneId = getRenderService()->getID();
391  this->createNewDistance(sceneId);
392 }
393 
394 //------------------------------------------------------------------------------
395 
396 void SImageMultiDistances::createNewDistance( std::string sceneId )
397 {
398  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
399  SLM_ASSERT("Missing image", image);
400 
401  ::fwData::PointList::sptr newPL = ::fwData::PointList::New();
402 
403  newPL->setField( ::fwDataTools::fieldHelper::Image::m_relatedServiceId, ::fwData::String::New( sceneId ) );
404 
405  ::fwData::Vector::sptr distanceField;
406  distanceField = image->setDefaultField< ::fwData::Vector >(::fwDataTools::fieldHelper::Image::m_imageDistancesId,
407  ::fwData::Vector::New());
408  distanceField->getContainer().push_back(newPL);
409 
410  OSLM_INFO("DistanceField size: " << distanceField->size() );
411 
412  int sizeX = this->getRenderer()->GetRenderWindow()->GetSize()[0];
413  int sizeY = this->getRenderer()->GetRenderWindow()->GetSize()[1];
414 
415  SLM_ASSERT("invalid RenderWindow size", sizeX > 0 && sizeY > 0 );
416  ::fwData::Point::sptr pt1 = this->screenToWorld(sizeX/3, sizeY/2);
417  ::fwData::Point::sptr pt2 = this->screenToWorld(2*sizeX/3, sizeY/2);
418 
419  newPL->getPoints().push_back( pt1 );
420  newPL->getPoints().push_back( pt2 );
421 
422  this->installSubServices(newPL);
423  this->setVtkPipelineModified();
424 }
425 
426 //------------------------------------------------------------------------------
427 
428 void SImageMultiDistances::setNeedSubservicesDeletion( bool _needSubservicesDeletion)
429 {
430  m_needSubservicesDeletion = _needSubservicesDeletion; // to manage point deletion
431 }
432 
433 //------------------------------------------------------------------------------
434 
436 {
437  if ( m_rightButtonCommand ) // can be not instantiated (use of SImageMultiDistances::show() )
438  {
439  this->getInteractor()->RemoveObserver(m_rightButtonCommand);
440  m_rightButtonCommand->Delete();
441  m_rightButtonCommand = 0;
442  }
443 
444  this->unregisterServices();
445 }
446 
447 //------------------------------------------------------------------------------
448 
449 void SImageMultiDistances::show(bool showDistances)
450 {
451  if(showDistances)
452  {
453  this->starting();
454  }
455  else
456  {
457  this->stopping();
458  }
459 }
460 
461 //------------------------------------------------------------------------------
462 
464 {
465  KeyConnectionsMap connections;
466  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_DISTANCE_ADDED_SIG, s_UPDATE_SLOT);
467  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_DISTANCE_REMOVED_SIG, s_REMOVE_DISTANCE_SLOT);
468  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_DISTANCE_DISPLAYED_SIG, s_UPDATE_SLOT);
469 
470  return connections;
471 }
472 
473 //------------------------------------------------------------------------------
474 
475 } //namespace visuVTKAdaptor
FWRENDERVTK_API vtkRenderWindowInteractor * getInteractor()
Returns the render interactor.
This class is a helper to define the connections of a service and its data.
Definition: IService.hpp:454
virtual VISUVTKADAPTOR_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
FWRENDERVTK_API vtkRenderer * getRenderer()
Returns the renderer.
The namespace visuVTKAdaptor contains the list of adaptors available for the generic scene...
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
FWRENDERVTK_API IAdaptor::sptr getAssociatedAdaptor(vtkProp *prop, int depth)
Returns the adaptor associated to the vtkProp.
static FWDATATOOLS_API const std::string m_relatedServiceId
to store uid (simple) of service which create the object
#define OSLM_INFO(message)
Definition: spyLog.hpp:252
FWDATA_API::fwData::Object::sptr getField(const FieldNameType &name,::fwData::Object::sptr defaultValue=::fwData::Object::sptr()) const
Returns a pointer of corresponding field (null if non exist).
T & value() noexcept
Get the value (mutable version).
This class defines a vector of objects.
VISUVTKADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_DISTANCE_ADDED_SIG
Type of signal when image&#39;s buffer is added.
Adaptor to display distance on an image.
#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_API::fwData::Object::sptr copy(const ::fwData::Object::csptr &source)
return a copy of the source. if source is a null pointer, return a null pointer.
FWRENDERVTK_API void getAllSubProps(vtkPropCollection *propc, int depth=-1)
Gets all the vtkProp associated to this adaptor.
This class defines a list of points.
VISUVTKADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
ContainerType & getContainer()
get/set the vector of fwData::Object
Contains the representation of the data objects used in the framework.
std::shared_ptr< DATATYPE > getInOut(const KeyType &key) const
Return the inout object at the given key. Asserts if the data is not of the right type...
Definition: IService.hxx:47
This class defines an image.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_DISTANCE_REMOVED_SIG
Type of signal when image&#39;s buffer is added.
This class contains an std::string value.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_DISTANCE_DISPLAYED_SIG
Type of signal when image&#39;s buffer is added.