fw4spl
SImageSlice.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/SImageSlice.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 
16 #include <fwDataTools/fieldHelper/Image.hpp>
17 #include <fwDataTools/fieldHelper/MedicalImageHelpers.hpp>
18 
19 #include <fwServices/macros.hpp>
20 
21 #include <fwVtkIO/vtk.hpp>
22 
23 #include <vtkActor.h>
24 #include <vtkCellArray.h>
25 #include <vtkImageActor.h>
26 #include <vtkImageBlend.h>
27 #include <vtkImageData.h>
28 #include <vtkImageMapper3D.h>
29 #include <vtkPolyData.h>
30 #include <vtkPolyDataMapper.h>
31 #include <vtkProperty.h>
32 #include <vtkRenderer.h>
33 #include <vtkTransform.h>
34 
35 fwServicesRegisterMacro( ::fwRenderVTK::IAdaptor, ::visuVTKAdaptor::SImageSlice );
36 
37 namespace visuVTKAdaptor
38 {
39 
40 static const ::fwCom::Slots::SlotKeyType s_UPDATE_SLICE_INDEX_SLOT = "updateSliceIndex";
41 static const ::fwCom::Slots::SlotKeyType s_UPDATE_SLICE_TYPE_SLOT = "updateSliceType";
42 
43 static const ::fwServices::IService::KeyType s_IMAGE_INOUT = "image";
44 
45 //------------------------------------------------------------------------------
46 
47 SImageSlice::SImageSlice() noexcept :
48  m_interpolation(true),
49  m_actorOpacity(1.),
50  m_imageSource(nullptr),
51  m_imageActor(vtkImageActor::New()),
52  m_planeOutlinePolyData(vtkPolyData::New()),
53  m_planeOutlineMapper(vtkPolyDataMapper::New()),
54  m_planeOutlineActor(vtkActor::New())
55 {
56  newSlot(s_UPDATE_SLICE_INDEX_SLOT, &SImageSlice::updateSliceIndex, this);
57  newSlot(s_UPDATE_SLICE_TYPE_SLOT, &SImageSlice::updateSliceType, this);
58 }
59 
60 //------------------------------------------------------------------------------
61 
62 SImageSlice::~SImageSlice() noexcept
63 {
64  m_imageActor->Delete();
65  m_imageActor = nullptr;
66 
67  m_planeOutlineActor->Delete();
68  m_planeOutlineActor = nullptr;
69 
70  m_planeOutlineMapper->Delete();
71  m_planeOutlineMapper = nullptr;
72 
73  m_planeOutlinePolyData->Delete();
74  m_planeOutlinePolyData = nullptr;
75 }
76 
77 //------------------------------------------------------------------------------
78 
80 {
81  this->initialize();
82 
83  this->addToRenderer(m_imageActor);
84  this->addToRenderer(m_planeOutlineActor);
85  this->addToPicker(m_imageActor);
86 
87  this->updating();
88 }
89 
90 //------------------------------------------------------------------------------
91 
93 {
94  this->removeFromPicker(m_imageActor);
96 }
97 
98 //------------------------------------------------------------------------------
99 
101 {
102  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
103  SLM_ASSERT("Missing image", image);
104  SLM_ASSERT("Input image must be three-dimensional. vtkImageActor does not handle 2D images.",
105  image->getNumberOfDimensions() == 3);
106 
108  if (imageIsValid)
109  {
110  this->buildPipeline();
111  this->updateImage(image);
112  this->updateSImageSliceIndex(image);
113  this->updateOutline();
114 
115  this->requestRender();
116  }
117 }
118 
119 //-----------------------------------------------------------------------------
120 
121 void SImageSlice::updateSliceIndex(int axial, int frontal, int sagittal)
122 {
123  m_axialIndex->value() = axial;
124  m_frontalIndex->value() = frontal;
125  m_sagittalIndex->value() = sagittal;
126 
127  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INOUT);
128  SLM_ASSERT("Missing image", image);
129 
130  this->updateSImageSliceIndex(image);
131  this->updateOutline();
132 }
133 
134 //-----------------------------------------------------------------------------
135 
136 void SImageSlice::updateSliceType(int from, int to)
137 {
138  if( to == static_cast<int>(m_orientation) )
139  {
140  setOrientation( static_cast< Orientation >( from ));
141  }
142  else if(from == static_cast<int>(m_orientation))
143  {
144  setOrientation( static_cast< Orientation >( to ));
145  }
146  this->updating();
147 }
148 
149 //------------------------------------------------------------------------------
150 
152 {
153  this->configureParams();
154 
155  const ConfigType config = this->getConfigTree().get_child("config.<xmlattr>");
156 
157  const std::string orientation = config.get<std::string>("sliceIndex", "axial");
158  if(orientation == "axial" )
159  {
160  m_orientation = Z_AXIS;
161  }
162  else if(orientation == "frontal" )
163  {
164  m_orientation = Y_AXIS;
165  }
166  else if(orientation == "sagittal" )
167  {
168  m_orientation = X_AXIS;
169  }
170 
171  this->setVtkImageSourceId( config.get<std::string>("vtkimagesource", ""));
172 
173  const std::string interpolation = config.get<std::string>("interpolation", "off");
174  SLM_ASSERT("'interpolation' value must be 'on' or 'off', actual: " + interpolation,
175  interpolation == "on" || interpolation == "off");
176  this->setInterpolation(interpolation == "yes");
177 
178  this->setActorOpacity(config.get<double>("actorOpacity", 1.));
179 }
180 
181 //------------------------------------------------------------------------------
182 
183 void SImageSlice::updateImage( ::fwData::Image::sptr image )
184 {
185  this->updateImageInfos(image);
186  this->setVtkPipelineModified();
187 }
188 
189 //------------------------------------------------------------------------------
190 
191 void SImageSlice::updateSImageSliceIndex( ::fwData::Image::sptr image )
192 {
193  int axialIndex = m_axialIndex->value();
194  int frontalIndex = m_frontalIndex->value();
195  int sagittalIndex = m_sagittalIndex->value();
196 
197  const int pos[3] = { sagittalIndex, frontalIndex, axialIndex };
198 
199  this->setSlice( pos[ m_orientation], image );
200 }
201 
202 //------------------------------------------------------------------------------
203 
204 void SImageSlice::setSlice( int slice, ::fwData::Image::sptr image )
205 {
206  int extent[6];
207  std::fill( extent, extent+6, 0);
208  extent[1] = static_cast<int>(image->getSize()[0]-1);
209  extent[3] = static_cast<int>(image->getSize()[1]-1);
210  extent[5] = static_cast<int>(image->getSize()[2]-1);
211  extent[2*m_orientation] = slice;
212  extent[2*m_orientation+1] = slice;
213 
214  OSLM_TRACE("DisplayExtent : " << " X min: " << extent[0] << " X max: " << extent[1] <<
215  " Y min: " << extent[2] << " Y max: " << extent[3] <<
216  " Z min: " << extent[4] << " Z max: " << extent[5]
217  );
218 
219  m_imageActor->SetDisplayExtent( extent );
220 
221  this->setVtkPipelineModified();
222 }
223 
224 //------------------------------------------------------------------------------
225 
226 void SImageSlice::buildPipeline( )
227 {
228  if (!m_imageSourceId.empty())
229  {
230  m_imageSource = this->getVtkObject(m_imageSourceId);
231  }
232 
233  vtkImageAlgorithm* algorithm = vtkImageAlgorithm::SafeDownCast(m_imageSource);
234  vtkImageData* imageData = vtkImageData::SafeDownCast(m_imageSource);
235  //vtkImageBlend *imageBlend = vtkImageBlend::SafeDownCast(m_imageSource);
236 
237  SLM_ASSERT("Invalid vtk image source", algorithm||imageData );
238  if (algorithm)
239  {
240  SLM_TRACE("Input is a vtkImageAlgorithm");
241  m_imageActor->GetMapper()->SetInputConnection(algorithm->GetOutputPort());
242  //if (imageBlend)
243  //{
244  //imageBlend->SetBlendModeToCompound();
245  //imageBlend->SetCompoundThreshold(0);
246  //}
247  }
248  else if (imageData)
249  {
250  SLM_TRACE("Input is a vtkImageData");
251  m_imageActor->SetInputData(imageData);
252  }
253 
254  if(!this->getTransformId().empty())
255  {
256  m_imageActor->SetUserTransform(this->getTransform());
257  }
258 
259  m_imageActor->SetInterpolate(m_interpolation);
260  m_imageActor->SetOpacity(m_actorOpacity);
261 
262  this->buildOutline();
263  this->setVtkPipelineModified();
264 }
265 
266 //------------------------------------------------------------------------------
267 
268 void SImageSlice::buildOutline()
269 {
270  vtkPoints* points = vtkPoints::New(VTK_DOUBLE);
271  points->SetNumberOfPoints(4);
272  int i;
273  for (i = 0; i < 4; i++)
274  {
275  points->SetPoint(i, 0.0, 0.0, 0.0);
276  }
277 
278  vtkCellArray* cells = vtkCellArray::New();
279  cells->Allocate(cells->EstimateSize(4, 2));
280  vtkIdType pts[2];
281  pts[0] = 3; pts[1] = 2; // top edge
282  cells->InsertNextCell(2, pts);
283  pts[0] = 0; pts[1] = 1; // bottom edge
284  cells->InsertNextCell(2, pts);
285  pts[0] = 0; pts[1] = 3; // left edge
286  cells->InsertNextCell(2, pts);
287  pts[0] = 1; pts[1] = 2; // right edge
288  cells->InsertNextCell(2, pts);
289 
290  m_planeOutlinePolyData->SetPoints(points);
291  points->Delete();
292  points = nullptr;
293  m_planeOutlinePolyData->SetLines(cells);
294  cells->Delete();
295  cells = nullptr;
296 
297  m_planeOutlineMapper = vtkPolyDataMapper::New();
298  m_planeOutlineMapper->SetInputData( m_planeOutlinePolyData );
299  m_planeOutlineMapper->SetResolveCoincidentTopologyToPolygonOffset();
300  m_planeOutlineActor->SetMapper(m_planeOutlineMapper);
301  m_planeOutlineActor->PickableOff();
302  m_planeOutlineActor->GetProperty()->SetOpacity(0.9);
303  if(!this->getTransformId().empty())
304  {
305  m_planeOutlineActor->SetUserTransform(this->getTransform());
306  }
307  this->setVtkPipelineModified();
308 }
309 
310 //------------------------------------------------------------------------------
311 
312 void SImageSlice::updateOutline()
313 {
314  static const int indexZ[12] = { 0, 2, 4, 1, 2, 4, 1, 3, 4, 0, 3, 4 };
315  static const int indexY[12] = { 0, 2, 4, 1, 2, 4, 1, 2, 5, 0, 2, 5 };
316  static const int indexX[12] = { 0, 2, 4, 0, 2, 5, 0, 3, 5, 0, 3, 4 };
317  static const int* indexSet[3] = { indexX, indexY, indexZ };
318  static double colors[3][3] = { {0., 0., 1.}, {0., 1., 0.}, {1., 0., 0.} };
319 
320  double* extent = m_imageActor->GetBounds();
321  vtkPoints* points = m_planeOutlinePolyData->GetPoints();
322 
323  const int* index = indexSet[ m_orientation ];
324  for ( int i = 0; i < 4; ++i)
325  {
326  double pt[3];
327  pt[0] = extent[ *(index++) ];
328  pt[1] = extent[ *(index++) ];
329  pt[2] = extent[ *(index++) ];
330  points->SetPoint(i, pt);
331  }
332 
333  points->GetData()->Modified();
334  m_planeOutlinePolyData->Modified();
335 
336  m_planeOutlineActor->GetProperty()->SetColor( colors[m_orientation]);
337  this->setVtkPipelineModified();
338 }
339 
340 //------------------------------------------------------------------------------
341 
343 {
344  KeyConnectionsMap connections;
345 
346  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_MODIFIED_SIG, s_UPDATE_SLOT);
347  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_SLICE_INDEX_MODIFIED_SIG, s_UPDATE_SLICE_INDEX_SLOT);
348  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_SLICE_TYPE_MODIFIED_SIG, s_UPDATE_SLICE_TYPE_SLOT);
349  connections.push(s_IMAGE_INOUT, ::fwData::Image::s_BUFFER_MODIFIED_SIG, s_UPDATE_SLOT);
350 
351  return connections;
352 }
353 
354 //------------------------------------------------------------------------------
355 
356 } //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
FWRENDERVTK_API void addToRenderer(vtkProp *prop)
Adds the vtkProp to the renderer.
FWRENDERVTK_API vtkObject * getVtkObject(const SRender::VtkObjectIdType &objectId) const
Returns the vtk object defined by &#39;objectId&#39; in the vtk scene.
FWRENDERVTK_API void addToPicker(vtkProp *prop, std::string pickerId="")
Adds the vtkProp to the picking list.
The namespace visuVTKAdaptor contains the list of adaptors available for the generic scene...
::fwData::Integer::sptr m_axialIndex
Axial slice index.
FWRENDERVTK_API void configureParams()
Parse the xml configuration for renderer, picker and transform.
virtual FWDATATOOLS_API void setOrientation(Orientation orientation)
Set the image orientation.
VISUVTKADAPTOR_API void configuring() override
Configure the service before starting. Apply the configuration to service.
FWRENDERVTK_API void requestRender()
notify a render request iff vtkPipeline is modified
FWRENDERVTK_API void setVtkPipelineModified()
End-user have to call this method when a vtk structure has been modified, thus a render request will ...
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
FWRENDERVTK_API void removeAllPropFromRenderer()
Removes all the vtkProp from the renderer.
::fwData::Integer::sptr m_sagittalIndex
Sagittal slice index.
virtual VISUVTKADAPTOR_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
VISUVTKADAPTOR_API void updating() override
Perform some computations according to object (this service is attached to) attribute values and its ...
FWRENDERVTK_API vtkTransform * getTransform()
Returns the transform used by this adaptor.
VISUVTKADAPTOR_API void stopping() override
Uninitialize the service activity. The stop() method is always invoked before destroying a service...
Definition: SImageSlice.cpp:92
Orientation m_orientation
Image orientation.
FWDATATOOLS_API void updateImageInfos(::fwData::Image::sptr image)
Update the image information (slice index, min/max,...)
VISUVTKADAPTOR_API void starting() override
Initialize the service activity.
Definition: SImageSlice.cpp:79
#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
FWRENDERVTK_API SRender::VtkObjectIdType getTransformId() const
Returns the identifier of the transform used by this adaptor.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_BUFFER_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
FWRENDERVTK_API void removeFromPicker(vtkProp *prop, std::string pickerId="")
Removes the vtkProp to the picking list.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
::fwData::Integer::sptr m_frontalIndex
Frontal slice index.
static FWDATATOOLS_API bool checkImageValidity(::fwData::Image::csptr _pImg)
Check if the image is valid.
#define SLM_TRACE(message)
Definition: spyLog.hpp:228
FWRENDERVTK_API void initialize()
Initialize the adaptor with the associated render service. (must be call in starting).
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_SLICE_TYPE_MODIFIED_SIG
Type of signal when image&#39;s buffer is added.
static FWSERVICES_APIconst::fwCom::Slots::SlotKeyType s_UPDATE_SLOT
Slot to call start method.
Definition: IService.hpp:177
Adaptor to display only one slice of an image.
Definition: SImageSlice.hpp:67
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247