CustusX  2023.01.05-dev+develop.0da12
An IGT application
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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 
13 #include "cxPickerRep.h"
14 
15 #include "boost/bind.hpp"
16 #include <vtkActor.h>
17 #include <vtkCamera.h>
18 #include <vtkRenderer.h>
19 #include <vtkProperty.h>
20 #include <vtkImageData.h>
21 #include <vtkLineSource.h>
22 //#include <vtkDoubleArray.h>
23 #include <vtkProbeFilter.h>
24 #include <vtkSphereSource.h>
25 #include <vtkRenderWindow.h>
26 #include <vtkCallbackCommand.h>
27 #include <vtkPolyDataMapper.h>
28 //#include <vtkDataSetAttributes.h>
29 #include <vtkEventQtSlotConnect.h>
30 //#include <vtkCellPicker.h>
31 #include "cxMesh.h"
32 #include "cxPatientModelService.h"
33 #include "cxLogger.h"
34 #include "cxImage.h"
35 #include "cxView.h"
36 #include "cxTool.h"
38 #include "cxGeometricRep.h"
39 #include <vtkRenderWindowInteractor.h>
40 #include "cxLogger.h"
41 #include "vtkVolumePicker.h"
42 
43 #include "cxConfig.h"
44 #ifdef CX_BUILD_MEHDI_VTKMULTIVOLUME
45  #include "vtkMultiVolumePicker.h"
46  typedef vtkSmartPointer<class vtkMultiVolumePicker> vtkMultiVolumePickerPtr;
47 // typedef vtkSmartPointer<class vtkVolumePicker> vtkMultiVolumePickerPtr;
48 #else
49  typedef vtkSmartPointer<class vtkVolumePicker> vtkMultiVolumePickerPtr;
50 #endif
51 
52 namespace cx
53 {
54 PickerRepPtr PickerRep::New(PatientModelServicePtr dataManager, const QString& uid)
55 {
56  return wrap_new(new PickerRep(dataManager), uid);
57 }
59  RepImpl(),
60  mDataManager(dataManager),
61  mPickedPoint(), mSphereRadius(2) //, mConnections(vtkEventQtSlotConnectPtr::New())
62 {
63  mIsDragging = false;
65  mViewportListener->setCallback(boost::bind(&PickerRep::scaleSphere, this));
66 
67  this->mCallbackCommand = vtkCallbackCommandPtr::New();
68  this->mCallbackCommand->SetClientData(this);
69  this->mCallbackCommand->SetCallback(PickerRep::ProcessEvents);
70 
71  mEnabled = true;
72  mConnected = false;
73  mSnapToSurface = false;
74 }
75 
77 {
78  if (!mGraphicalPoint)
79  return;
80 
81  double size = mViewportListener->getVpnZoom(mPickedPoint);
82  double sphereSize = mSphereRadius / 100 / size;
83  mGraphicalPoint->setRadius(sphereSize);
84 }
85 
87 {
88 }
89 QString PickerRep::getType() const
90 {
91  return "PickerRep";
92 }
93 
94 void PickerRep::setSphereRadius(double radius)
95 {
96  mSphereRadius = radius;
97  if (mGraphicalPoint)
98  mGraphicalPoint->setRadius(mSphereRadius);
99 }
100 
102 {
103  if (tool == mTool)
104  return;
105 
106  if (mTool)
107  {
108  disconnect(mTool.get(), SIGNAL(toolTransformAndTimestamp(Transform3D, double)), this,
109  SLOT(setModified()));
110  }
111 
112  mTool = tool;
113 
114  if (mTool)
115  {
116  connect(mTool.get(), SIGNAL(toolTransformAndTimestamp(Transform3D, double)), this,
117  SLOT(setModified()));
118  this->setModified();
119  }
120 }
121 
123 {
124  if (!mGlyph)
125  mGlyph = glyph;
126 
127  if (!mGlyphRep)
128  {
129  mGlyphRep = GeometricRep::New("PickerGlyphRep");
130  if (this->getView())
131  {
132  this->getView()->addRep(mGlyphRep);
133  }
134  }
135 
136  mGlyphRep->setMesh(mGlyph);
137 }
138 
139 typedef vtkSmartPointer<class vtkDataSet> vtkDataSetPtr;
140 
148 void PickerRep::pickLandmark(const Vector3D& clickPosition, vtkRendererPtr renderer)
149 {
150  if (!this->mEnabled)
151  return;
152  vtkMultiVolumePickerPtr picker = vtkMultiVolumePickerPtr::New();
153  int hit = picker->Pick(clickPosition[0], clickPosition[1], 0, renderer);
154  if (!hit)
155  {
156  mIsDragging = false;
157  return;
158  }
159 
160  // search for picked data in manager, emit uid if found.
161  vtkDataSetPtr data = picker->GetDataSet();
162  if (data)
163  {
164  std::map<QString, DataPtr> allData = mDataManager->getDatas();
165  for (std::map<QString, DataPtr>::iterator iter = allData.begin(); iter != allData.end(); ++iter)
166  {
167  MeshPtr mesh = boost::dynamic_pointer_cast<Mesh>(iter->second);
168  if (mesh && mesh->getVtkPolyData() == data)
169  emit dataPicked(iter->first);
170 
171  ImagePtr image = boost::dynamic_pointer_cast<Image>(iter->second);
172  if (image && image->getBaseVtkImageData() == data)
173  emit dataPicked(iter->first);
174  }
175  }
176 
177  Vector3D pick_w(picker->GetPickPosition());
178 
179  if ( data &&
180  ((mGraphicalPoint && (data == mGraphicalPoint->getPolyData() ))
181  ||(mGlyph && (data == mGlyph->getVtkPolyData() ))
182  ||(mTool && (data == mTool->getGraphicsPolyData() )))
183  )
184  {
185  // We have clicked the picker/tool itself.
186  // Store click pos and wait for dragging.
187  mClickedPoint = pick_w;
188  mIsDragging = true;
189  mCallbackCommand->SetAbortFlag(1); // abort this event: interactor does not receive it.
190  return;
191  }
192  else
193  {
194  mIsDragging = false;
195  }
196 
197  if (hit && mSnapToSurface)
198  {
199  mPickedPoint = pick_w;
200 
201  if (mGraphicalPoint)
202  mGraphicalPoint->setValue(mPickedPoint);
204 
206  }
207 }
208 
209 void PickerRep::pickLandmarkSlot(vtkObject* renderWindowInteractor)
210 {
211  vtkRenderWindowInteractorPtr iren = vtkRenderWindowInteractor::SafeDownCast(renderWindowInteractor);
212 
213  if (iren == NULL)
214  return;
215 
216  int pickedPoint[2]; //<x,y>
217  iren->GetEventPosition(pickedPoint); //mouse positions are measured in pixels
218 
219  vtkRendererPtr renderer = this->getRenderer();
220  if (renderer == NULL)
221  return;
222 
223  Vector3D clickPoint(pickedPoint[0], pickedPoint[1], 0);
224 
225  this->pickLandmark(clickPoint, renderer);
226 }
227 
229 {
230  this->toolHasChanged();
231 }
232 
234 {
235  if (!mTool)
236  return;
237  Transform3D prMt = mTool->get_prMt();
238  Transform3D rMpr = mDataManager->get_rMpr();
239  Transform3D rMt = rMpr * prMt;
240  Vector3D p_r = rMt.coord(Vector3D(0, 0, mTool->getTooltipOffset()));
241 
242  mPickedPoint = p_r;
243  if (mGraphicalPoint)
244  mGraphicalPoint->setValue(mPickedPoint);
246 }
247 
249 {
250  mEnabled = on;
251  if (mSnapToSurface == on)
252  return;
253 
254  mSnapToSurface = on;
255 
256  if (mSnapToSurface)
257  {
258  if (mGraphicalPoint)
259  mGraphicalPoint->getActor()->SetVisibility(true);
260  }
261  else
262  {
263  if (mGraphicalPoint)
264  mGraphicalPoint->getActor()->SetVisibility(false);
265  }
266 }
267 
268 void PickerRep::ProcessEvents(vtkObject* vtkNotUsed(object), unsigned long event, void* clientdata,
269  void* vtkNotUsed(calldata))
270 {
271  PickerRep* self = reinterpret_cast<PickerRep *>(clientdata);
272 
273  //okay, let's do the right thing
274  switch (event)
275  {
276  case vtkCommand::LeftButtonPressEvent:
277  self->OnLeftButtonDown();
278  break;
279  case vtkCommand::LeftButtonReleaseEvent:
280  self->OnLeftButtonUp();
281  break;
282  case vtkCommand::MouseMoveEvent:
283  self->OnMouseMove();
284  break;
285  }
286 }
287 
292 {
293  double worldPt[4];
294  vtkRendererPtr ren = this->getRenderer();
295  ren->SetDisplayPoint(p_d.data());
296  ren->DisplayToWorld();
297  ren->GetWorldPoint(worldPt);
298  return Vector3D(worldPt)/worldPt[3];
299 }
300 
305 {
306  Vector3D p_d;
307  vtkRendererPtr ren = this->getRenderer();
308  ren->SetWorldPoint(p_w[0], p_w[1], p_w[2], 1.0);
309  ren->WorldToDisplay();
310  ren->GetDisplayPoint(p_d.data());
311  return p_d;
312 }
313 
317 {
318  vtkRenderWindowInteractorPtr interactor = this->getView()->getRenderWindow()->GetInteractor();
319 
320 // // find previous pos in world and display:
321  Vector3D p_prev_w = mClickedPoint;
322 // std::cout << " p_prev_w = \t" << p_prev_w << std::endl;
323  Vector3D p_prev_d = this->ComputeWorldToDisplay(p_prev_w);
324 // std::cout << " p_prev_d = \t" << p_prev_d << std::endl;
325 
326  // find current pos in world and display, set z-pos in d equal to previous z-pos:
327  Vector3D p_current_d(interactor->GetEventPosition()[0], interactor->GetEventPosition()[1], p_prev_d[2]);
328 // std::cout << " p_current_d = \t" << p_current_d << std::endl;
329  Vector3D p_current_w = this->ComputeDisplayToWorld(p_current_d);
330 // std::cout << " p_current_w = \t" << p_current_w << std::endl;
331 
332  // both positions are now in the camera focal plane: the diff lies in the view plane.
333 // std::cout << " diff_d = \t" << p_current_d - p_prev_d << std::endl;
334 // std::cout << " diff_w = \t" << p_current_w - p_prev_w << std::endl;
335  return p_current_w - p_prev_w;
336 }
337 
339 {
340  this->pickLandmarkSlot(this->getView()->getRenderWindow()->GetInteractor());
341 }
342 
344 {
345  if (mIsDragging)
346  {
347  mPickedPoint += this->getDisplacement();
349 
350  if (mGraphicalPoint)
351  mGraphicalPoint->setValue(mPickedPoint);
354 
355  mCallbackCommand->SetAbortFlag(1);
356  }
357 }
358 
360 {
361  if (mGlyph)
362  {
363  mGlyph->get_rMd_History()->setRegistration(createTransformTranslate(pos));
364  }
365 }
366 
367 
369 {
370  if (mIsDragging)
371  {
372  mIsDragging = false;
373  mCallbackCommand->SetAbortFlag(1); // abort this event: interactor does not receive it.
374  }
375 }
376 
378 {
379  if (!this->getView())
380  return;
381  if (mConnected)
382  return;
383 
384  vtkRenderWindowInteractorPtr i = this->getView()->getRenderWindow()->GetInteractor();
385  i->AddObserver(vtkCommand::MouseMoveEvent, this->mCallbackCommand, 1.0);
386  i->AddObserver(vtkCommand::LeftButtonPressEvent, this->mCallbackCommand, 1.0);
387  i->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->mCallbackCommand, 1.0);
388 
389  mConnected = true;
390 }
391 
393 {
394  if (!this->getView())
395  return;
396  if (!mConnected)
397  return;
398 
399  // don't listen for events any more
400  this->getView()->getRenderWindow()->GetInteractor()->RemoveObserver(this->mCallbackCommand);
401 
402  mConnected = false;
403 }
404 
406 {
407  if (view == NULL)
408  {
409  reportDebug("Cannot add rep actor to a NULL view.");
410  return;
411  }
412 
413  this->connectInteractor();
414 
415  mGraphicalPoint.reset(new GraphicalPoint3D(this->getRenderer()));
416  mGraphicalPoint->setColor(QColor(Qt::blue));
417  mGraphicalPoint->setRadius(mSphereRadius);
418  mGraphicalPoint->getActor()->SetVisibility(mSnapToSurface);
419 
420  // show even if disabled
421  if (mGlyphRep)
422  {
423  this->getView()->addRep(mGlyphRep);
424  }
425 
426  mViewportListener->startListen(this->getRenderer());
427  this->scaleSphere();
428 }
429 
431 {
432  if (view == NULL)
433  return;
434 
435  this->disconnectInteractor();
436  mViewportListener->stopListen();
437  mGraphicalPoint.reset();
438 
439  if (mGlyphRep)
440  view->removeRep(mGlyphRep);
441 }
442 
444 {
445  return mPickedPoint;
446 }
447 
448 } //namespace cx
Vector3D ComputeDisplayToWorld(Vector3D p_d)
ViewPtr getView() const
Definition: cxRepImpl.cpp:83
vtkRendererPtr getRenderer()
Definition: cxRepImpl.cpp:88
void OnLeftButtonDown()
virtual QString getType() const
returns a string identifying this class type
Definition: cxPickerRep.cpp:89
A mesh data set.
Definition: cxMesh.h:45
void scaleSphere()
Definition: cxPickerRep.cpp:76
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< class vtkRenderWindowInteractor > vtkRenderWindowInteractorPtr
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
vtkSmartPointer< class vtkVolumePicker > vtkMultiVolumePickerPtr
Definition: cxPickerRep.cpp:49
bool mConnected
Interactor connected.
Definition: cxPickerRep.h:97
static boost::shared_ptr< REP > wrap_new(REP *object, QString uid)
Definition: cxRepImpl.h:62
void setTool(ToolPtr tool)
set the tool to listen to
Vector3D ComputeWorldToDisplay(Vector3D p_w)
double mSphereRadius
Definition: cxPickerRep.h:100
void pickLandmark(const Vector3D &clickPosition, vtkRendererPtr renderer)
When you don&#39;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:49
vtkSmartPointer< class vtkRenderer > vtkRendererPtr
void setGlyph(MeshPtr glyph)
MeshPtr mGlyph
Definition: cxPickerRep.h:101
A volumetric data set.
Definition: cxImage.h:45
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:42
bool mSnapToSurface
if set, clicking on a Data surface will pick that point
Definition: cxPickerRep.h:106
Vector3D mClickedPoint
Definition: cxPickerRep.h:103
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:42
void pointPicked(Vector3D p_r)
GraphicalPoint3DPtr mGraphicalPoint
Definition: cxPickerRep.h:108
void setSphereRadius(double radius)
Definition: cxPickerRep.cpp:94
PickerRep(PatientModelServicePtr dataManager)
use New instead
Definition: cxPickerRep.cpp:58
static void ProcessEvents(vtkObject *object, unsigned long event, void *clientdata, void *calldata)
ViewportListenerPtr mViewportListener
Definition: cxPickerRep.h:109
PatientModelServicePtr mDataManager
Definition: cxPickerRep.h:111
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:54
GeometricRepPtr mGlyphRep
Definition: cxPickerRep.h:102
Vector3D getDisplacement()
ToolPtr mTool
the connected tool
Definition: cxPickerRep.h:98
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
Definition: cxPickerRep.cpp:86
Vector3D mPickedPoint
the last point that was successfully sampled from intersection with an image
Definition: cxPickerRep.h:99
vtkCallbackCommandPtr mCallbackCommand
Definition: cxPickerRep.h:110
virtual void removeRepActorsFromViewRenderer(ViewPtr view)
disconnects from the renderwindowinteractor
void setModified()
Definition: cxRepImpl.cpp:112
void reportDebug(QString msg)
Definition: cxLogger.cpp:68
Namespace for all CustusX production code.
boost::shared_ptr< class Tool > ToolPtr
void toolHasChanged()