fw4spl
vtkSimpleMesh/src/vtkSimpleMesh/SRenderer.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 "vtkSimpleMesh/SRenderer.hpp"
8 
9 #include <fwCom/Signal.hxx>
10 #include <fwCom/Signals.hpp>
11 #include <fwCom/Slots.hpp>
12 #include <fwCom/Slots.hxx>
13 
14 #include <fwCore/HiResTimer.hpp>
15 
16 #include <fwData/Mesh.hpp>
17 #include <fwData/mt/ObjectReadLock.hpp>
18 
19 #include <fwServices/macros.hpp>
20 #include <fwServices/registry/ActiveWorkers.hpp>
21 
22 #include <fwVtkIO/helper/Mesh.hpp>
23 #include <fwVtkIO/vtk.hpp>
24 
25 #include <vtkCamera.h>
26 #include <vtkCommand.h>
27 #ifndef ANDROID
28 #include <vtkInteractorStyleTrackballCamera.h>
29 #else
30 #include <vtkInteractorStyleMultiTouchCamera.h>
31 #endif
32 #include <vtkMatrix4x4.h>
33 #include <vtkPolyData.h>
34 #include <vtkPolyDataMapper.h>
35 #include <vtkPolyDataNormals.h>
36 #include <vtkProperty.h>
37 #include <vtkRenderWindow.h>
38 #include <vtkRenderer.h>
39 #include <vtkTransform.h>
40 
41 fwServicesRegisterMacro( ::fwRender::IRender, ::vtkSimpleMesh::SRenderer, ::fwData::Mesh );
42 
43 namespace vtkSimpleMesh
44 {
45 
46 //-----------------------------------------------------------------------------
47 
48 const ::fwCom::Slots::SlotKeyType SRenderer::s_UPDATE_CAM_POSITION_SLOT = "updateCamPosition";
49 const ::fwCom::Slots::SlotKeyType SRenderer::s_UPDATE_PIPELINE_SLOT = "updatePipeline";
50 const ::fwCom::Slots::SlotKeyType SRenderer::s_INIT_PIPELINE_SLOT = "initPipeline";
51 const ::fwCom::Signals::SignalKeyType SRenderer::s_CAM_UPDATED_SIG = "camUpdated";
52 
53 static const std::string s_MESH_KEY = "mesh";
54 
55 //-----------------------------------------------------------------------------
56 
57 // vtkCommand used to catch the user interactions and notify the new camera position
58 class vtkLocalCommand : public vtkCommand
59 {
60 public:
61 
63  {
64  m_service = _service;
65  this->m_isMousePressed = false;
66  }
67  //------------------------------------------------------------------------------
68 
69  void Execute(vtkObject* _caller, unsigned long _event, void* _obj)
70  {
71  if (_event == vtkCommand::StartInteractionEvent )
72  {
73  this->m_isMousePressed = true;
74  }
75  else if (_event == vtkCommand::EndInteractionEvent )
76  {
77  this->m_isMousePressed = false;
78  }
79  else if ( (_event == vtkCommand::ModifiedEvent && this->m_isMousePressed)
80  || _event == vtkCommand::MouseWheelBackwardEvent || _event == vtkCommand::MouseWheelForwardEvent)
81  {
82  m_service->notifyCamPositionUpdated();
83  ::fwThread::Worker::sptr worker = m_service->getWorker();
84  worker->processTasks();
85  }
86  }
87 private:
88  ::vtkSimpleMesh::SRenderer* m_service;
89  bool m_isMousePressed;
90 };
91 
92 //-----------------------------------------------------------------------------
93 
95  m_render( 0 ),
96  m_bPipelineIsInit(false)
97 {
98  newSlot(s_UPDATE_CAM_POSITION_SLOT, &SRenderer::updateCamPosition, this);
99  newSlot(s_UPDATE_PIPELINE_SLOT, &SRenderer::updatePipeline, this);
100  newSlot(s_INIT_PIPELINE_SLOT, &SRenderer::initPipeline, this);
101 
102  m_sigCamUpdated = newSignal<CamUpdatedSignalType>(s_CAM_UPDATED_SIG);
103 }
104 
105 //-----------------------------------------------------------------------------
106 
108 {
109 }
110 
111 //-----------------------------------------------------------------------------
112 
114 {
115  this->create();
116 
117  m_interactorManager = ::fwRenderVTK::IVtkRenderWindowInteractorManager::createManager();
118 
119  m_interactorManager->installInteractor( this->getContainer() );
120 
121  m_bPipelineIsInit = false;
122 
123  // Renderer
124  m_render = vtkRenderer::New();
125  m_interactorManager->getInteractor()->GetRenderWindow()->AddRenderer(m_render);
126 
127  bool meshIsLoaded;
128  {
129  ::fwData::Mesh::csptr mesh = this->getInput< ::fwData::Mesh >(s_MESH_KEY);
130  SLM_ASSERT("'" + s_MESH_KEY + "' key not found", mesh);
131  ::fwData::mt::ObjectReadLock lock(mesh);
132  meshIsLoaded = mesh->getNumberOfPoints() > 0;
133  }
134 
135  if ( meshIsLoaded )
136  {
137  this->initVTKPipeline();
138  m_bPipelineIsInit = true;
139  }
140 }
141 
142 //-----------------------------------------------------------------------------
143 
145 {
146  this->initialize();
147 }
148 
149 //-----------------------------------------------------------------------------
150 
152 {
153  if( m_render == 0 )
154  {
155  return;
156  }
157 
158  m_interactorManager->getInteractor()->RemoveObserver(m_loc);
159 
160  m_interactorManager->uninstallInteractor();
161  m_interactorManager.reset();
162 
163  SLM_ASSERT("m_render not instanced", m_render);
164  m_render->Delete();
165  m_render = 0;
166 
167  this->destroy();
168 }
169 
170 //-----------------------------------------------------------------------------
171 
173 {
174  m_interactorManager->getInteractor()->Render();
175 }
176 
177 //-----------------------------------------------------------------------------
178 
179 void SRenderer::initVTKPipeline()
180 {
181  ::fwData::Mesh::csptr mesh = this->getInput< ::fwData::Mesh >(s_MESH_KEY);
182  SLM_ASSERT("'" + s_MESH_KEY + "' key not found", mesh);
183  m_vtkPolyData = vtkSmartPointer<vtkPolyData>::New();
184 
185  {
186  ::fwData::mt::ObjectReadLock lock(mesh);
187  ::fwVtkIO::helper::Mesh::toVTKMesh( mesh, m_vtkPolyData );
188  }
189 
190  m_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
191  m_mapper->SetInputData(m_vtkPolyData);
192 
193  auto actor = vtkSmartPointer<vtkActor>::New();
194  actor->SetMapper(m_mapper);
195 
196  // Add the actors
197  m_render->AddActor( actor);
198 #ifndef ANDROID
199  m_interactorManager->getInteractor()->SetInteractorStyle(vtkInteractorStyleTrackballCamera::New());
200 #else
201  m_interactorManager->getInteractor()->SetInteractorStyle(vtkInteractorStyleMultiTouchCamera::New());
202 #endif
203  m_loc = new vtkLocalCommand(this);
204 
205  m_interactorManager->getInteractor()->AddObserver(vtkCommand::AnyEvent, m_loc);
206 
207  // Repaint and resize window
208  m_render->ResetCamera();
209 }
210 
211 //-----------------------------------------------------------------------------
212 
213 void SRenderer::updateVTKPipeline(bool resetCamera)
214 {
215  ::fwData::Mesh::csptr mesh = this->getInput< ::fwData::Mesh >(s_MESH_KEY);
216  SLM_ASSERT("'" + s_MESH_KEY + "' key not found", mesh);
217 
218  {
219  ::fwData::mt::ObjectReadLock lock(mesh);
224  }
225 
226  if (resetCamera)
227  {
228  m_render->ResetCamera();
229  }
230 
231 }
232 
233 //-----------------------------------------------------------------------------
234 
236 {
237  vtkCamera* camera = m_render->GetActiveCamera();
238 
239  SharedArray position = SharedArray(new double[3]);
240  SharedArray focal = SharedArray(new double[3]);
241  SharedArray viewUp = SharedArray(new double[3]);
242 
243  std::copy(camera->GetPosition(), camera->GetPosition()+3, position.get());
244  std::copy(camera->GetFocalPoint(), camera->GetFocalPoint()+3, focal.get());
245  std::copy(camera->GetViewUp(), camera->GetViewUp()+3, viewUp.get());
246 
247  {
248  ::fwCom::Connection::Blocker block(m_sigCamUpdated->getConnection(this->slot(s_UPDATE_CAM_POSITION_SLOT)));
249  m_sigCamUpdated->asyncEmit(position, focal, viewUp);
250  }
251 }
252 
253 //-----------------------------------------------------------------------------
254 
255 void SRenderer::updateCamPosition(SharedArray positionValue, SharedArray focalValue, SharedArray viewUpValue)
256 {
257  vtkCamera* camera = m_render->GetActiveCamera();
258 
259  camera->SetPosition(positionValue.get());
260  camera->SetFocalPoint(focalValue.get());
261  camera->SetViewUp(viewUpValue.get());
262  camera->SetClippingRange(0.1, 1000000);
263 
264  m_interactorManager->getInteractor()->Render();
265 }
266 
267 //-----------------------------------------------------------------------------
268 
269 void SRenderer::initPipeline()
270 {
271  if(!m_bPipelineIsInit)
272  {
273  this->initVTKPipeline();
274  m_bPipelineIsInit = true;
275  }
276  else
277  {
278  m_vtkPolyData = vtkSmartPointer<vtkPolyData>::New();
279  ::fwData::Mesh::csptr mesh = this->getInput< ::fwData::Mesh >(s_MESH_KEY);
280  SLM_ASSERT("'" + s_MESH_KEY + "' key not found", mesh);
281  {
282  ::fwData::mt::ObjectReadLock lock(mesh);
283  ::fwVtkIO::helper::Mesh::toVTKMesh( mesh, m_vtkPolyData );
284  }
285  m_mapper->SetInputData(m_vtkPolyData);
286  }
287  m_interactorManager->getInteractor()->Render();
288 }
289 
290 //-----------------------------------------------------------------------------
291 
292 void SRenderer::updatePipeline()
293 {
294  m_hiResTimer.reset();
295  m_hiResTimer.start();
296  this->updateVTKPipeline(false);
297  m_hiResTimer.stop();
298  OSLM_INFO("Vertex updating time (milli sec) = " << m_hiResTimer.getElapsedTimeInMilliSec());
299 
300  m_hiResTimer.reset();
301  m_hiResTimer.start();
302  m_interactorManager->getInteractor()->Render();
303  m_hiResTimer.stop();
304  OSLM_INFO("Render time (milli sec) = " << m_hiResTimer.getElapsedTimeInMilliSec());
305 }
306 
307 //-----------------------------------------------------------------------------
308 
310 {
311  KeyConnectionsMap connections;
312  connections.push( s_MESH_KEY, ::fwData::Object::s_MODIFIED_SIG, s_INIT_PIPELINE_SLOT );
313  connections.push( s_MESH_KEY, ::fwData::Mesh::s_VERTEX_MODIFIED_SIG, s_UPDATE_PIPELINE_SLOT );
314  return connections;
315 }
316 
317 //-----------------------------------------------------------------------------
318 }
static FWVTKIO_API void updatePolyDataPointColor(vtkSmartPointer< vtkPolyData > polyDataDst, const ::fwData::Mesh::csptr &meshSrc)
Update a vtkPolyData with point color of fwData::Mesh.
Service rendering a fwData::Mesh using VTK.
This class is a helper to define the connections of a service and its data.
Definition: IService.hpp:454
void notifyCamPositionUpdated()
This method is used to notify that the VTK camera position is updated.
virtual VTKSIMPLEMESH_API void updating() override
Updating method.
Class allowing to block a Connection.
Definition: Connection.hpp:20
static FWVTKIO_API void toVTKMesh(const ::fwData::Mesh::csptr &_mesh, vtkSmartPointer< vtkPolyData > _polyData)
Convert a ::fwData::Mesh::csptr to a vtkPolyData.
virtual VTKSIMPLEMESH_API ~SRenderer() noexcept
Destructor.
A helper to lock object on read mode.
static FWVTKIO_API void updatePolyDataPoints(vtkSmartPointer< vtkPolyData > polyDataDst, const ::fwData::Mesh::csptr &meshSrc)
Update a vtkPolyData with ::fwData::Mesh::sptr points.
#define OSLM_INFO(message)
Definition: spyLog.hpp:252
virtual VTKSIMPLEMESH_API void configuring() override
This method is used to configure the service. Initialize the qt container.
Defines the service interface managing the rendering service for object.
Definition: IRender.hpp:36
virtual VTKSIMPLEMESH_API void stopping() override
Stopping method.
#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 FWVTKIO_API void updatePolyDataCellNormals(vtkSmartPointer< vtkPolyData > polyDataDst, const ::fwData::Mesh::csptr &meshSrc)
Update a vtkPolyData with cell normals of fwData::Mesh.
The namespace vtkSimpleMesh contains a service which renders one mesh (fwData::Mesh).
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_VERTEX_MODIFIED_SIG
Key in m_signals map of signal m_sigVertexModified.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
virtual VTKSIMPLEMESH_API void starting() override
Starting method.
static FWVTKIO_API void updatePolyDataPointNormals(vtkSmartPointer< vtkPolyData > polyDataDst, const ::fwData::Mesh::csptr &meshSrc)
Update a vtkPolyData with point normals of fwData::Mesh.
VTKSIMPLEMESH_API SRenderer() noexcept
Constructor.
Data holding a geometric structure composed of points, lines, triangles, quads or polygons...
virtual VTKSIMPLEMESH_API KeyConnectionsMap getAutoConnections() const override
Returns proposals to connect service slots to associated object signals, this method is used for obj/...
FWSERVICES_API std::shared_ptr< ::fwThread::Worker > getWorker() const
Returns associate worker.
Definition: IService.cpp:419