NorMIT-nav  16.5
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxPickerRep.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 
34 #include "cxPickerRep.h"
35 
36 #include "boost/bind.hpp"
37 #include <vtkActor.h>
38 #include <vtkCamera.h>
39 #include <vtkRenderer.h>
40 #include <vtkProperty.h>
41 #include <vtkImageData.h>
42 #include <vtkLineSource.h>
43 //#include <vtkDoubleArray.h>
44 #include <vtkProbeFilter.h>
45 #include <vtkSphereSource.h>
46 #include <vtkRenderWindow.h>
47 #include <vtkCallbackCommand.h>
48 #include <vtkPolyDataMapper.h>
49 //#include <vtkDataSetAttributes.h>
50 #include <vtkEventQtSlotConnect.h>
51 //#include <vtkCellPicker.h>
52 #include "cxMesh.h"
53 #include "cxPatientModelService.h"
54 #include "cxLogger.h"
55 #include "cxImage.h"
56 #include "cxView.h"
57 #include "cxTool.h"
59 #include "cxGeometricRep.h"
60 #include <vtkRenderWindowInteractor.h>
61 #include "cxLogger.h"
62 #include "vtkVolumePicker.h"
63 
64 #include "cxConfig.h"
65 #ifdef CX_BUILD_MEHDI_VTKMULTIVOLUME
66  #include "vtkMultiVolumePicker.h"
67  typedef vtkSmartPointer<class vtkMultiVolumePicker> vtkMultiVolumePickerPtr;
68 // typedef vtkSmartPointer<class vtkVolumePicker> vtkMultiVolumePickerPtr;
69 #else
70  typedef vtkSmartPointer<class vtkVolumePicker> vtkMultiVolumePickerPtr;
71 #endif
72 
73 namespace cx
74 {
75 PickerRepPtr PickerRep::New(PatientModelServicePtr dataManager, const QString& uid)
76 {
77  return wrap_new(new PickerRep(dataManager), uid);
78 }
80  RepImpl(),
81  mDataManager(dataManager),
82  mPickedPoint(), mSphereRadius(2) //, mConnections(vtkEventQtSlotConnectPtr::New())
83 {
84  mIsDragging = false;
86  mViewportListener->setCallback(boost::bind(&PickerRep::scaleSphere, this));
87 
88  this->mCallbackCommand = vtkCallbackCommandPtr::New();
89  this->mCallbackCommand->SetClientData(this);
90  this->mCallbackCommand->SetCallback(PickerRep::ProcessEvents);
91 
92  mEnabled = true;
93  mConnected = false;
94  mSnapToSurface = false;
95 }
96 
98 {
99  if (!mGraphicalPoint)
100  return;
101 
102  double size = mViewportListener->getVpnZoom();
103  double sphereSize = mSphereRadius / 100 / size;
104  mGraphicalPoint->setRadius(sphereSize);
105 }
106 
108 {
109 }
110 QString PickerRep::getType() const
111 {
112  return "PickerRep";
113 }
114 
115 void PickerRep::setSphereRadius(double radius)
116 {
117  mSphereRadius = radius;
118  if (mGraphicalPoint)
119  mGraphicalPoint->setRadius(mSphereRadius);
120 }
121 
123 {
124  if (tool == mTool)
125  return;
126 
127  if (mTool)
128  {
129  disconnect(mTool.get(), SIGNAL(toolTransformAndTimestamp(Transform3D, double)), this,
130  SLOT(setModified()));
131  }
132 
133  mTool = tool;
134 
135  if (mTool)
136  {
137  connect(mTool.get(), SIGNAL(toolTransformAndTimestamp(Transform3D, double)), this,
138  SLOT(setModified()));
139  this->setModified();
140  }
141 }
142 
144 {
145  if (!mGlyph)
146  mGlyph = glyph;
147 
148  if (!mGlyphRep)
149  {
150  mGlyphRep = GeometricRep::New("PickerGlyphRep");
151  if (this->getView())
152  {
153  this->getView()->addRep(mGlyphRep);
154  }
155  }
156 
157  mGlyphRep->setMesh(mGlyph);
158 }
159 
160 typedef vtkSmartPointer<class vtkDataSet> vtkDataSetPtr;
161 
169 void PickerRep::pickLandmark(const Vector3D& clickPosition, vtkRendererPtr renderer)
170 {
171  if (!this->mEnabled)
172  return;
173  vtkMultiVolumePickerPtr picker = vtkMultiVolumePickerPtr::New();
174  int hit = picker->Pick(clickPosition[0], clickPosition[1], 0, renderer);
175  if (!hit)
176  {
177  mIsDragging = false;
178  return;
179  }
180 
181  // search for picked data in manager, emit uid if found.
182  vtkDataSetPtr data = picker->GetDataSet();
183  if (data)
184  {
185  std::map<QString, DataPtr> allData = mDataManager->getData();
186  for (std::map<QString, DataPtr>::iterator iter = allData.begin(); iter != allData.end(); ++iter)
187  {
188  MeshPtr mesh = boost::dynamic_pointer_cast<Mesh>(iter->second);
189  if (mesh && mesh->getVtkPolyData() == data)
190  emit dataPicked(iter->first);
191 
192  ImagePtr image = boost::dynamic_pointer_cast<Image>(iter->second);
193  if (image && image->getBaseVtkImageData() == data)
194  emit dataPicked(iter->first);
195  }
196  }
197 
198  Vector3D pick_w(picker->GetPickPosition());
199 
200  if ( data &&
201  ((mGraphicalPoint && (data == mGraphicalPoint->getPolyData() ))
202  ||(mGlyph && (data == mGlyph->getVtkPolyData() ))
203  ||(mTool && (data == mTool->getGraphicsPolyData() )))
204  )
205  {
206  // We have clicked the picker/tool itself.
207  // Store click pos and wait for dragging.
208  mClickedPoint = pick_w;
209  mIsDragging = true;
210  mCallbackCommand->SetAbortFlag(1); // abort this event: interactor does not receive it.
211  return;
212  }
213  else
214  {
215  mIsDragging = false;
216  }
217 
218  if (hit && mSnapToSurface)
219  {
220  mPickedPoint = pick_w;
221 
222  if (mGraphicalPoint)
223  mGraphicalPoint->setValue(mPickedPoint);
225 
227  }
228 }
229 
230 void PickerRep::pickLandmarkSlot(vtkObject* renderWindowInteractor)
231 {
232  vtkRenderWindowInteractorPtr iren = vtkRenderWindowInteractor::SafeDownCast(renderWindowInteractor);
233 
234  if (iren == NULL)
235  return;
236 
237  int pickedPoint[2]; //<x,y>
238  iren->GetEventPosition(pickedPoint); //mouse positions are measured in pixels
239 
240  vtkRendererPtr renderer = this->getRenderer();
241  if (renderer == NULL)
242  return;
243 
244  Vector3D clickPoint(pickedPoint[0], pickedPoint[1], 0);
245 
246  this->pickLandmark(clickPoint, renderer);
247 }
248 
250 {
251  this->toolHasChanged();
252 }
253 
255 {
256  if (!mTool)
257  return;
258  Transform3D prMt = mTool->get_prMt();
259  Transform3D rMpr = mDataManager->get_rMpr();
260  Transform3D rMt = rMpr * prMt;
261  Vector3D p_r = rMt.coord(Vector3D(0, 0, mTool->getTooltipOffset()));
262 
263  mPickedPoint = p_r;
264  if (mGraphicalPoint)
265  mGraphicalPoint->setValue(mPickedPoint);
267 }
268 
270 {
271  mEnabled = on;
272  if (mSnapToSurface == on)
273  return;
274 
275  mSnapToSurface = on;
276 
277  if (mSnapToSurface)
278  {
279  if (mGraphicalPoint)
280  mGraphicalPoint->getActor()->SetVisibility(true);
281  }
282  else
283  {
284  if (mGraphicalPoint)
285  mGraphicalPoint->getActor()->SetVisibility(false);
286  }
287 }
288 
289 void PickerRep::ProcessEvents(vtkObject* vtkNotUsed(object), unsigned long event, void* clientdata,
290  void* vtkNotUsed(calldata))
291 {
292  PickerRep* self = reinterpret_cast<PickerRep *>(clientdata);
293 
294  //okay, let's do the right thing
295  switch (event)
296  {
297  case vtkCommand::LeftButtonPressEvent:
298  self->OnLeftButtonDown();
299  break;
300  case vtkCommand::LeftButtonReleaseEvent:
301  self->OnLeftButtonUp();
302  break;
303  case vtkCommand::MouseMoveEvent:
304  self->OnMouseMove();
305  break;
306  }
307 }
308 
313 {
314  double worldPt[4];
315  vtkRendererPtr ren = this->getRenderer();
316  ren->SetDisplayPoint(p_d.data());
317  ren->DisplayToWorld();
318  ren->GetWorldPoint(worldPt);
319  return Vector3D(worldPt)/worldPt[3];
320 }
321 
326 {
327  Vector3D p_d;
328  vtkRendererPtr ren = this->getRenderer();
329  ren->SetWorldPoint(p_w[0], p_w[1], p_w[2], 1.0);
330  ren->WorldToDisplay();
331  ren->GetDisplayPoint(p_d.data());
332  return p_d;
333 }
334 
338 {
339  vtkRenderWindowInteractorPtr interactor = this->getView()->getRenderWindow()->GetInteractor();
340 
341 // // find previous pos in world and display:
342  Vector3D p_prev_w = mClickedPoint;
343 // std::cout << " p_prev_w = \t" << p_prev_w << std::endl;
344  Vector3D p_prev_d = this->ComputeWorldToDisplay(p_prev_w);
345 // std::cout << " p_prev_d = \t" << p_prev_d << std::endl;
346 
347  // find current pos in world and display, set z-pos in d equal to previous z-pos:
348  Vector3D p_current_d(interactor->GetEventPosition()[0], interactor->GetEventPosition()[1], p_prev_d[2]);
349 // std::cout << " p_current_d = \t" << p_current_d << std::endl;
350  Vector3D p_current_w = this->ComputeDisplayToWorld(p_current_d);
351 // std::cout << " p_current_w = \t" << p_current_w << std::endl;
352 
353  // both positions are now in the camera focal plane: the diff lies in the view plane.
354 // std::cout << " diff_d = \t" << p_current_d - p_prev_d << std::endl;
355 // std::cout << " diff_w = \t" << p_current_w - p_prev_w << std::endl;
356  return p_current_w - p_prev_w;
357 }
358 
360 {
361  this->pickLandmarkSlot(this->getView()->getRenderWindow()->GetInteractor());
362 }
363 
365 {
366  if (mIsDragging)
367  {
368  mPickedPoint += this->getDisplacement();
370 
371  if (mGraphicalPoint)
372  mGraphicalPoint->setValue(mPickedPoint);
375 
376  mCallbackCommand->SetAbortFlag(1);
377  }
378 }
379 
381 {
382  if (mGlyph)
383  {
384  mGlyph->get_rMd_History()->setRegistration(createTransformTranslate(pos));
385  }
386 }
387 
388 
390 {
391  if (mIsDragging)
392  {
393  mIsDragging = false;
394  mCallbackCommand->SetAbortFlag(1); // abort this event: interactor does not receive it.
395  }
396 }
397 
399 {
400  if (!this->getView())
401  return;
402  if (mConnected)
403  return;
404 
405  vtkRenderWindowInteractorPtr i = this->getView()->getRenderWindow()->GetInteractor();
406  i->AddObserver(vtkCommand::MouseMoveEvent, this->mCallbackCommand, 1.0);
407  i->AddObserver(vtkCommand::LeftButtonPressEvent, this->mCallbackCommand, 1.0);
408  i->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->mCallbackCommand, 1.0);
409 
410  mConnected = true;
411 }
412 
414 {
415  if (!this->getView())
416  return;
417  if (!mConnected)
418  return;
419 
420  // don't listen for events any more
421  this->getView()->getRenderWindow()->GetInteractor()->RemoveObserver(this->mCallbackCommand);
422 
423  mConnected = false;
424 }
425 
427 {
428  if (view == NULL)
429  {
430  reportDebug("Cannot add rep actor to a NULL view.");
431  return;
432  }
433 
434  this->connectInteractor();
435 
436  mGraphicalPoint.reset(new GraphicalPoint3D(this->getRenderer()));
437  mGraphicalPoint->setColor(QColor(Qt::blue));
438  mGraphicalPoint->setRadius(mSphereRadius);
439  mGraphicalPoint->getActor()->SetVisibility(mSnapToSurface);
440 
441  // show even if disabled
442  if (mGlyphRep)
443  {
444  this->getView()->addRep(mGlyphRep);
445  }
446 
447  mViewportListener->startListen(this->getRenderer());
448  this->scaleSphere();
449 }
450 
452 {
453  if (view == NULL)
454  return;
455 
456  this->disconnectInteractor();
457  mViewportListener->stopListen();
458  mGraphicalPoint.reset();
459 
460  if (mGlyphRep)
461  view->removeRep(mGlyphRep);
462 }
463 
465 {
466  return mPickedPoint;
467 }
468 
469 } //namespace cx
Vector3D ComputeDisplayToWorld(Vector3D p_d)
ViewPtr getView() const
Definition: cxRepImpl.cpp:104
vtkRendererPtr getRenderer()
Definition: cxRepImpl.cpp:109
void OnLeftButtonDown()
virtual QString getType() const
returns a string identifying this class type
A mesh data set.
Definition: cxMesh.h:61
void scaleSphere()
Definition: cxPickerRep.cpp:97
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< class vtkRenderWindowInteractor > vtkRenderWindowInteractorPtr
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
vtkSmartPointer< class vtkVolumePicker > vtkMultiVolumePickerPtr
Definition: cxPickerRep.cpp:70
bool mConnected
Interactor connected.
Definition: cxPickerRep.h:118
static boost::shared_ptr< REP > wrap_new(REP *object, QString uid)
Definition: cxRepImpl.h:83
void setTool(ToolPtr tool)
set the tool to listen to
Vector3D ComputeWorldToDisplay(Vector3D p_w)
double mSphereRadius
Definition: cxPickerRep.h:121
void pickLandmark(const Vector3D &clickPosition, vtkRendererPtr renderer)
When you don't use the renderwindowinteractor.
virtual void onModifiedStartRender()
void connectInteractor()
Helper for rendering a point in 3D.
boost::shared_ptr< class View > ViewPtr
void OnMouseMove()
void OnLeftButtonUp()
Listens to changes in viewport and camera matrix.
void setGlyphCenter(Vector3D pos)
boost::shared_ptr< class PickerRep > PickerRepPtr
Picking of points in an image.
Definition: cxPickerRep.h:70
vtkSmartPointer< class vtkRenderer > vtkRendererPtr
void setGlyph(MeshPtr glyph)
MeshPtr mGlyph
Definition: cxPickerRep.h:122
A volumetric data set.
Definition: cxImage.h:66
void disconnectInteractor()
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
Transform3D createTransformTranslate(const Vector3D &translation)
static GeometricRepPtr New(const QString &uid="")
Default implementation of Rep.
Definition: cxRepImpl.h:63
bool mSnapToSurface
if set, clicking on a Data surface will pick that point
Definition: cxPickerRep.h:127
Vector3D mClickedPoint
Definition: cxPickerRep.h:124
virtual void addRepActorsToViewRenderer(ViewPtr view)
connects to the renderwindowinteractor
vtkSmartPointer< class vtkDataSet > vtkDataSetPtr
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
void pointPicked(Vector3D p_r)
GraphicalPoint3DPtr mGraphicalPoint
Definition: cxPickerRep.h:129
void setSphereRadius(double radius)
PickerRep(PatientModelServicePtr dataManager)
use New instead
Definition: cxPickerRep.cpp:79
static void ProcessEvents(vtkObject *object, unsigned long event, void *clientdata, void *calldata)
ViewportListenerPtr mViewportListener
Definition: cxPickerRep.h:130
PatientModelServicePtr mDataManager
Definition: cxPickerRep.h:132
void pickLandmarkSlot(vtkObject *renderWindowInteractor)
When you use the renderwindowinteractor.
Vector3D getPosition() const
static PickerRepPtr New(PatientModelServicePtr dataManager, const QString &uid="")
for creating new instances
Definition: cxPickerRep.cpp:75
GeometricRepPtr mGlyphRep
Definition: cxPickerRep.h:123
Vector3D getDisplacement()
ToolPtr mTool
the connected tool
Definition: cxPickerRep.h:119
boost::shared_ptr< class Mesh > MeshPtr
void setEnabled(bool on)
void dataPicked(QString uid)
the rep sends out a signal when the user picks a point on it
virtual ~PickerRep()
empty
Vector3D mPickedPoint
the last point that was successfully sampled from intersection with an image
Definition: cxPickerRep.h:120
vtkCallbackCommandPtr mCallbackCommand
Definition: cxPickerRep.h:131
virtual void removeRepActorsFromViewRenderer(ViewPtr view)
disconnects from the renderwindowinteractor
void setModified()
Definition: cxRepImpl.cpp:132
void reportDebug(QString msg)
Definition: cxLogger.cpp:89
boost::shared_ptr< class Tool > ToolPtr
void toolHasChanged()