CustusX  15.8
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  this->pickLandmark(clickPoint, renderer);
246 }
247 
249 {
250  this->toolHasChanged();
251 }
252 
254 {
255  if (!mTool)
256  return;
257  Transform3D prMt = mTool->get_prMt();
258  Transform3D rMpr = mDataManager->get_rMpr();
259  Transform3D rMt = rMpr * prMt;
260  Vector3D p_r = rMt.coord(Vector3D(0, 0, mTool->getTooltipOffset()));
261 
262  mPickedPoint = p_r;
263  if (mGraphicalPoint)
264  mGraphicalPoint->setValue(mPickedPoint);
266 }
267 
269 {
270  mEnabled = on;
271  if (mSnapToSurface == on)
272  return;
273 
274  mSnapToSurface = on;
275 
276  if (mSnapToSurface)
277  {
278  if (mGraphicalPoint)
279  mGraphicalPoint->getActor()->SetVisibility(true);
280  }
281  else
282  {
283  if (mGraphicalPoint)
284  mGraphicalPoint->getActor()->SetVisibility(false);
285  }
286 }
287 
288 void PickerRep::ProcessEvents(vtkObject* vtkNotUsed(object), unsigned long event, void* clientdata,
289  void* vtkNotUsed(calldata))
290 {
291  PickerRep* self = reinterpret_cast<PickerRep *>(clientdata);
292 
293  //okay, let's do the right thing
294  switch (event)
295  {
296  case vtkCommand::LeftButtonPressEvent:
297  self->OnLeftButtonDown();
298  break;
299  case vtkCommand::LeftButtonReleaseEvent:
300  self->OnLeftButtonUp();
301  break;
302  case vtkCommand::MouseMoveEvent:
303  self->OnMouseMove();
304  break;
305  }
306 }
307 
312 {
313  double worldPt[4];
314  vtkRendererPtr ren = this->getRenderer();
315  ren->SetDisplayPoint(p_d.data());
316  ren->DisplayToWorld();
317  ren->GetWorldPoint(worldPt);
318  return Vector3D(worldPt)/worldPt[3];
319 }
320 
325 {
326  Vector3D p_d;
327  vtkRendererPtr ren = this->getRenderer();
328  ren->SetWorldPoint(p_w[0], p_w[1], p_w[2], 1.0);
329  ren->WorldToDisplay();
330  ren->GetDisplayPoint(p_d.data());
331  return p_d;
332 }
333 
337 {
338  vtkRenderWindowInteractorPtr interactor = this->getView()->getRenderWindow()->GetInteractor();
339 
340 // // find previous pos in world and display:
341  Vector3D p_prev_w = mClickedPoint;
342 // std::cout << " p_prev_w = \t" << p_prev_w << std::endl;
343  Vector3D p_prev_d = this->ComputeWorldToDisplay(p_prev_w);
344 // std::cout << " p_prev_d = \t" << p_prev_d << std::endl;
345 
346  // find current pos in world and display, set z-pos in d equal to previous z-pos:
347  Vector3D p_current_d(interactor->GetEventPosition()[0], interactor->GetEventPosition()[1], p_prev_d[2]);
348 // std::cout << " p_current_d = \t" << p_current_d << std::endl;
349  Vector3D p_current_w = this->ComputeDisplayToWorld(p_current_d);
350 // std::cout << " p_current_w = \t" << p_current_w << std::endl;
351 
352  // both positions are now in the camera focal plane: the diff lies in the view plane.
353 // std::cout << " diff_d = \t" << p_current_d - p_prev_d << std::endl;
354 // std::cout << " diff_w = \t" << p_current_w - p_prev_w << std::endl;
355  return p_current_w - p_prev_w;
356 }
357 
359 {
360  this->pickLandmarkSlot(this->getView()->getRenderWindow()->GetInteractor());
361 }
362 
364 {
365  if (mIsDragging)
366  {
367  mPickedPoint += this->getDisplacement();
369 
370  if (mGraphicalPoint)
371  mGraphicalPoint->setValue(mPickedPoint);
374 
375  mCallbackCommand->SetAbortFlag(1);
376  }
377 }
378 
380 {
381  if (mGlyph)
382  {
383  mGlyph->get_rMd_History()->setRegistration(createTransformTranslate(pos));
384  }
385 }
386 
387 
389 {
390  if (mIsDragging)
391  {
392  mIsDragging = false;
393  mCallbackCommand->SetAbortFlag(1); // abort this event: interactor does not receive it.
394  }
395 }
396 
398 {
399  if (!this->getView())
400  return;
401  if (mConnected)
402  return;
403 
404  vtkRenderWindowInteractorPtr i = this->getView()->getRenderWindow()->GetInteractor();
405  i->AddObserver(vtkCommand::MouseMoveEvent, this->mCallbackCommand, 1.0);
406  i->AddObserver(vtkCommand::LeftButtonPressEvent, this->mCallbackCommand, 1.0);
407  i->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->mCallbackCommand, 1.0);
408 
409  mConnected = true;
410 }
411 
413 {
414  if (!this->getView())
415  return;
416  if (!mConnected)
417  return;
418 
419  // don't listen for events any more
420  this->getView()->getRenderWindow()->GetInteractor()->RemoveObserver(this->mCallbackCommand);
421 
422  mConnected = false;
423 }
424 
426 {
427  if (view == NULL)
428  {
429  reportDebug("Cannot add rep actor to a NULL view.");
430  return;
431  }
432 
433  this->connectInteractor();
434 
435  mGraphicalPoint.reset(new GraphicalPoint3D(this->getRenderer()));
436  mGraphicalPoint->setColor(QColor(Qt::blue));
437  mGraphicalPoint->setRadius(mSphereRadius);
438  mGraphicalPoint->getActor()->SetVisibility(mSnapToSurface);
439 
440  // show even if disabled
441  if (mGlyphRep)
442  {
443  this->getView()->addRep(mGlyphRep);
444  }
445 
446  mViewportListener->startListen(this->getRenderer());
447  this->scaleSphere();
448 }
449 
451 {
452  if (view == NULL)
453  return;
454 
455  this->disconnectInteractor();
456  mViewportListener->stopListen();
457  mGraphicalPoint.reset();
458 
459  if (mGlyphRep)
460  view->removeRep(mGlyphRep);
461 }
462 
464 {
465  return mPickedPoint;
466 }
467 
468 } //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()