fw4spl
SMeshesBoxWidget.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 #ifndef ANDROID
8 
9 #include "visuVTKAdaptor/SMeshesBoxWidget.hpp"
10 
11 #include <fwCom/Slot.hpp>
12 #include <fwCom/Slot.hxx>
13 #include <fwCom/Slots.hpp>
14 #include <fwCom/Slots.hxx>
15 
16 #include <fwData/Mesh.hpp>
17 
18 #include <fwServices/macros.hpp>
19 
20 #include <fwVtkIO/helper/Mesh.hpp>
21 #include <fwVtkIO/vtk.hpp>
22 
23 #include <vtkActor.h>
24 #include <vtkAssembly.h>
25 #include <vtkBoxRepresentation.h>
26 #include <vtkBoxWidget2.h>
27 #include <vtkCommand.h>
28 #include <vtkPolyData.h>
29 #include <vtkPolyDataMapper.h>
30 #include <vtkProp3DCollection.h>
31 #include <vtkTransform.h>
32 
33 #include <limits>
34 
35 class MeshesBoxClallback : public ::vtkCommand
36 {
37 public:
38 
39  //------------------------------------------------------------------------------
40 
42  {
44  cb->m_adaptor = adaptor;
45  return cb;
46  }
47 
49  m_adaptor(NULL)
50  {
51  }
53  {
54  }
55 
56  //------------------------------------------------------------------------------
57 
58  virtual void Execute( ::vtkObject* pCaller, unsigned long, void* )
59  {
60  m_adaptor->updateFromVtk();
61  }
62 
64 };
65 
66 //-----------------------------------------------------------------------------
67 
68 fwServicesRegisterMacro( ::fwRenderVTK::IAdaptor, ::visuVTKAdaptor::SMeshesBoxWidget);
69 
70 static const ::fwServices::IService::KeyType s_COMPOSITE_INPUT = "composite";
71 
72 namespace visuVTKAdaptor
73 {
74 
75 static const ::fwCom::Slots::SlotKeyType s_UPDATE_MATRICES_SLOT = "updateMatrices";
76 static const ::fwCom::Slots::SlotKeyType s_ADD_OBJECTS_SLOT = "addObject";
77 static const ::fwCom::Slots::SlotKeyType s_CHANGE_OBJECTS_SLOT = "changeObject";
78 static const ::fwCom::Slots::SlotKeyType s_REMOVE_OBJECTS_SLOT = "removeObjects";
79 
80 //-----------------------------------------------------------------------------
81 
82 SMeshesBoxWidget::SMeshesBoxWidget() noexcept :
83  m_assembly(nullptr),
84  m_boxWidgetCommand(MeshesBoxClallback::New(this)),
85  m_vtkBoxWidget(nullptr)
86 {
87  newSlot(s_UPDATE_MATRICES_SLOT, &SMeshesBoxWidget::updateMatrices, this);
88  newSlot(s_ADD_OBJECTS_SLOT, &SMeshesBoxWidget::addObjects, this);
89  newSlot(s_CHANGE_OBJECTS_SLOT, &SMeshesBoxWidget::changeObjects, this);
90  newSlot(s_REMOVE_OBJECTS_SLOT, &SMeshesBoxWidget::removeObjects, this);
91 }
92 
93 //-----------------------------------------------------------------------------
94 
95 SMeshesBoxWidget::~SMeshesBoxWidget() noexcept
96 {
97 }
98 
99 //-----------------------------------------------------------------------------
100 
101 void SMeshesBoxWidget::configuring()
102 {
103  this->configureParams();
104 }
105 
106 //-----------------------------------------------------------------------------
107 
108 void SMeshesBoxWidget::starting()
109 {
110  this->initialize();
111 
112  ::fwData::Composite::csptr composite = this->getInput< ::fwData::Composite >(s_COMPOSITE_INPUT);
113  SLM_ASSERT("Missing composite", composite);
114 
115  m_assembly = vtkAssembly::New();
116 
117  vtkBoxRepresentation* boxRep = vtkBoxRepresentation::New();
118  boxRep->SetPlaceFactor(1.0);
119 
120  m_vtkBoxWidget = vtkBoxWidget2::New();
121  m_vtkBoxWidget->SetInteractor( this->getInteractor() );
122  m_vtkBoxWidget->SetRepresentation( boxRep );
123 
124  m_vtkBoxWidget->AddObserver( ::vtkCommand::InteractionEvent, m_boxWidgetCommand );
125 
126  this->updateMeshMapFromComposite(composite->getContainer());
127  this->updating();
128 }
129 
130 //-----------------------------------------------------------------------------
131 
132 void SMeshesBoxWidget::updating()
133 {
134  m_assembly->GetParts()->RemoveAllItems();
135  if (!m_meshMap.empty())
136  {
137  for(MeshMapType::value_type elt : m_meshMap)
138  {
139  m_assembly->AddPart( elt.second );
140  }
141  vtkBoxRepresentation* boxRep = vtkBoxRepresentation::SafeDownCast( m_vtkBoxWidget->GetRepresentation() );
142  boxRep->PlaceWidget(m_assembly->GetBounds());
143  m_vtkBoxWidget->On();
144  }
145  else
146  {
147  m_vtkBoxWidget->Off();
148  }
149  this->setVtkPipelineModified();
150  this->requestRender();
151 }
152 
153 //-----------------------------------------------------------------------------
154 
155 void SMeshesBoxWidget::stopping()
156 {
157  ::fwData::Composite::csptr composite = this->getInput< ::fwData::Composite >(s_COMPOSITE_INPUT);
158  SLM_ASSERT("Missing composite", composite);
159 
160  for(::fwData::Composite::value_type elt : *composite)
161  {
162  ::fwData::Mesh::sptr mesh = ::fwData::Mesh::dynamicCast(elt.second);
163  ::fwData::TransformationMatrix3D::sptr fieldTransform;
164  fieldTransform = mesh->getField< ::fwData::TransformationMatrix3D > ("TransformMatrix");
165  m_connections[elt.first].disconnect();
166  m_connections.erase(elt.first);
167  }
168  m_meshMap.clear();
169 
170  m_assembly->Delete();
171  m_assembly = nullptr;
172 
173  m_vtkBoxWidget->Off();
174  m_vtkBoxWidget->RemoveObserver( m_boxWidgetCommand );
175  m_vtkBoxWidget->Delete();
176  m_vtkBoxWidget = nullptr;
177  this->requestRender();
178 }
179 
180 //-----------------------------------------------------------------------------
181 
182 void SMeshesBoxWidget::updateFromVtk()
183 {
184  m_vtkBoxWidget->RemoveObserver( m_boxWidgetCommand );
185 
186  ::fwData::Composite::csptr composite = this->getInput< ::fwData::Composite >(s_COMPOSITE_INPUT);
187  SLM_ASSERT("Missing composite", composite);
188 
189  vtkBoxRepresentation* boxRep = vtkBoxRepresentation::SafeDownCast( m_vtkBoxWidget->GetRepresentation() );
190  vtkTransform* boxTransform = vtkTransform::New();
191  boxRep->GetTransform(boxTransform);
192 
193  for(const ::fwData::Composite::value_type& elt : composite->getContainer())
194  {
195  ::fwData::Mesh::sptr mesh = ::fwData::Mesh::dynamicCast(elt.second);
196  ::fwData::TransformationMatrix3D::sptr fieldTransform;
197  SLM_ASSERT("Mesh must have a TransformMatrix field", mesh->getField("TransformMatrix"));
198  fieldTransform = mesh->getField< ::fwData::TransformationMatrix3D > ("TransformMatrix");
199 
200  vtkTransform* transform = vtkTransform::New();
201  vtkLinearTransform* meshTransform = m_meshMap[elt.first]->GetUserTransform();
202  transform->Concatenate(boxTransform);
203  transform->Concatenate(meshTransform);
204 
205  vtkMatrix4x4* mat = transform->GetMatrix();
206  for(int lt = 0; lt < 4; lt++)
207  {
208  for(int ct = 0; ct < 4; ct++)
209  {
210  fieldTransform->setCoefficient(static_cast<size_t>(lt), static_cast<size_t>(ct),
211  mat->GetElement(lt, ct));
212  }
213  }
214 
215  auto sig = fieldTransform->signal< ::fwData::Object::ModifiedSignalType >(
217  sig->asyncEmit();
218 
219  transform->Delete();
220  }
221  m_vtkBoxWidget->AddObserver( ::vtkCommand::InteractionEvent, m_boxWidgetCommand );
222  boxTransform->Delete();
223 }
224 
225 //-----------------------------------------------------------------------------
226 
227 void SMeshesBoxWidget::updateMeshMapFromComposite(::fwData::Composite::ContainerType objects)
228 {
229  for(const ::fwData::Composite::value_type& elt : objects)
230  {
231  ::fwData::Mesh::sptr mesh = ::fwData::Mesh::dynamicCast(elt.second);
232  SLM_ASSERT("Composite must only contain meshes", mesh);
233 
234  vtkSmartPointer<vtkPolyData> vtkMesh = vtkSmartPointer<vtkPolyData>::New();
235  ::fwVtkIO::helper::Mesh::toVTKMesh( mesh, vtkMesh);
236 
237  ::fwData::TransformationMatrix3D::sptr fieldTransform;
238  fieldTransform = mesh->setDefaultField("TransformMatrix", ::fwData::TransformationMatrix3D::New());
239 
240  vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
241  transform->Identity();
242 
243  vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New();
244 
245  for(int lt = 0; lt < 4; lt++)
246  {
247  for(int ct = 0; ct < 4; ct++)
248  {
249  matrix->SetElement(lt, ct,
250  fieldTransform->getCoefficient(static_cast<size_t>(lt), static_cast<size_t>(ct)));
251  }
252  }
253 
254  transform->SetMatrix(matrix);
255  vtkSmartPointer<vtkPolyDataMapper> meshMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
256  meshMapper->SetInputData(vtkMesh);
257 
258  vtkActor* meshActor = vtkActor::New();
259  meshActor->SetMapper(meshMapper);
260  meshActor->SetUserTransform(transform);
261 
262  if (m_meshMap.find(elt.first) == m_meshMap.end())
263  {
264  ::fwCom::Connection connection = fieldTransform->signal(::fwData::Object::s_MODIFIED_SIG)->
265  connect(this->slot(s_UPDATE_MATRICES_SLOT));
266  m_connections[elt.first] = connection;
267  }
268 
269  m_meshMap[elt.first] = meshActor;
270  }
271 }
272 
273 //-----------------------------------------------------------------------------
274 
275 void SMeshesBoxWidget::updateMeshTransform()
276 {
277  ::fwData::Composite::csptr composite = this->getInput< ::fwData::Composite >(s_COMPOSITE_INPUT);
278  SLM_ASSERT("Missing composite", composite);
279 
280  for(const ::fwData::Composite::value_type& elt : composite->getContainer())
281  {
282  ::fwData::Mesh::sptr mesh = ::fwData::Mesh::dynamicCast(elt.second);
283 
284  ::fwData::TransformationMatrix3D::sptr fieldTransform;
285  SLM_ASSERT("Triangular mesh must have a TransformMatrix field", mesh->getField("TransformMatrix"));
286  fieldTransform = mesh->getField< ::fwData::TransformationMatrix3D > ("TransformMatrix");
287 
288  vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
289  transform->Identity();
290 
291  vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New();
292 
293  for(int lt = 0; lt < 4; lt++)
294  {
295  for(int ct = 0; ct < 4; ct++)
296  {
297  matrix->SetElement(lt, ct,
298  fieldTransform->getCoefficient(static_cast<size_t>(lt), static_cast<size_t>(ct)));
299  }
300  }
301 
302  transform->SetMatrix(matrix);
303  vtkActor* meshActor = m_meshMap[elt.first];
304  meshActor->SetUserTransform(transform);
305  }
306 }
307 
308 //-----------------------------------------------------------------------------
309 
310 void SMeshesBoxWidget::updateMatrices()
311 {
312  this->updateMeshTransform();
313  this->updating();
314 }
315 
316 //------------------------------------------------------------------------------
317 
318 void SMeshesBoxWidget::addObjects(::fwData::Composite::ContainerType objects)
319 {
320  this->updateMeshMapFromComposite(objects);
321  this->updateMeshTransform();
322  this->updating();
323 }
324 
325 //------------------------------------------------------------------------------
326 
327 void SMeshesBoxWidget::changeObjects(::fwData::Composite::ContainerType newObjects,
328  ::fwData::Composite::ContainerType /*oldObjects*/)
329 {
330  this->updateMeshMapFromComposite(newObjects);
331  this->updateMeshTransform();
332  this->updating();
333 }
334 
335 //------------------------------------------------------------------------------
336 
337 void SMeshesBoxWidget::removeObjects(::fwData::Composite::ContainerType objects)
338 {
339  for(const ::fwData::Composite::value_type& elt : objects)
340  {
341  ::fwData::Mesh::sptr mesh = ::fwData::Mesh::dynamicCast(elt.second);
342  m_meshMap[elt.first]->Delete();
343  m_meshMap.erase(elt.first);
344 
345  ::fwData::TransformationMatrix3D::sptr fieldTransform;
346  fieldTransform = mesh->getField< ::fwData::TransformationMatrix3D > ("TransformMatrix");
347  m_connections[elt.first].disconnect();
348  m_connections.erase(elt.first);
349  }
350 
351  this->updateMeshTransform();
352  this->updating();
353 }
354 
355 //------------------------------------------------------------------------------
356 
357 ::fwServices::IService::KeyConnectionsMap SMeshesBoxWidget::getAutoConnections() const
358 {
359  KeyConnectionsMap connections;
360  connections.push(s_COMPOSITE_INPUT, ::fwData::Composite::s_ADDED_OBJECTS_SIG, s_ADD_OBJECTS_SLOT);
361  connections.push(s_COMPOSITE_INPUT, ::fwData::Composite::s_CHANGED_OBJECTS_SIG, s_CHANGE_OBJECTS_SLOT);
362  connections.push(s_COMPOSITE_INPUT, ::fwData::Composite::s_REMOVED_OBJECTS_SIG, s_REMOVE_OBJECTS_SLOT);
363 
364  return connections;
365 }
366 
367 //-----------------------------------------------------------------------------
368 
369 } //namespace visuVTKAdaptor
370 
371 #endif // ANDROID
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...
static FWVTKIO_API void toVTKMesh(const ::fwData::Mesh::csptr &_mesh, vtkSmartPointer< vtkPolyData > _polyData)
Convert a ::fwData::Mesh::csptr to a vtkPolyData.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_CHANGED_OBJECTS_SIG
Type of signal when objects are added.
Class managing Signal-Slot connections.
Definition: Connection.hpp:17
Create a Box widget around the meshes contained in the composite.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_REMOVED_OBJECTS_SIG
Type of signal when objects are added.
#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
This class represents a 3D transformation matrix (4x4).
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_ADDED_OBJECTS_SIG
Type of signal when objects are added.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
void updateFromVtk()
Updates meshes transformation matrix from vtk box widget transform.