Fraxinus  2023.01.05-dev+develop.0da12
An IGT application
cxViewWrapper3D.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 #include "cxViewWrapper3D.h"
13 
14 #include <vector>
15 
16 #include "boost/bind.hpp"
17 #include "boost/function.hpp"
18 
19 #include <QAction>
20 #include <QMenu>
21 
22 #include <vtkRenderWindow.h>
23 #include <vtkRenderer.h>
24 #include <vtkImageData.h>
25 
26 #include "cxView.h"
27 #include "cxSliceProxy.h"
28 #include "cxSlicerRepSW.h"
29 #include "cxToolRep2D.h"
30 #include "cxDisplayTextRep.h"
31 #include "cxLogger.h"
32 #include "cxSlicePlanes3DRep.h"
33 #include "cxMesh.h"
34 #include "cxPickerRep.h"
35 #include "cxGeometricRep.h"
36 #include "cxToolRep3D.h"
37 #include "cxTypeConversions.h"
38 #include "cxVideoSource.h"
39 #include "cxVideoRep.h"
40 #include "cxToolTracer.h"
42 #include "cxSettings.h"
43 #include "cxTrackingService.h"
44 #include "cxRepManager.h"
45 #include "cxCameraControl.h"
46 #include "cxLandmarkRep.h"
47 #include "cxPointMetricRep.h"
48 #include "cxDistanceMetricRep.h"
50 #include "cxAngleMetricRep.h"
51 #include "cxPlaneMetricRep.h"
52 #include "cxFrameMetricRep.h"
53 #include "cxToolMetricRep.h"
54 #include "cxDataMetricRep.h"
55 #include "cxDataLocations.h"
56 #include "cxManualTool.h"
57 #include "cxImage2DRep3D.h"
58 
59 #include "cxPatientModelService.h"
60 #include "cxRepContainer.h"
61 
62 
63 #include "cxData.h"
64 #include "cxAxesRep.h"
65 #include "cxViewGroup.h"
66 
67 #include "cxAngleMetric.h"
68 #include "cxDistanceMetric.h"
69 #include "cxPointMetric.h"
70 #include "cxSphereMetric.h"
71 #include "cxShapedMetric.h"
72 #include "cxCustomMetric.h"
73 #include "cxSphereMetricRep.h"
74 #include "cxDonutMetricRep.h"
75 #include "cxCustomMetricRep.h"
76 
77 #include "cxDepthPeeling.h"
78 #include "cxAxisConnector.h"
80 #include "cxMetricNamesRep.h"
81 #include "cxVisServices.h"
82 #include "cxNavigation.h"
83 
84 #include "cxTrackedStream.h"
85 #include "cxStreamRep3D.h"
86 #include "cxStream2DRep3D.h"
87 #include "cxActiveData.h"
88 
89 #include "cxSlices3DRep.h"
90 
91 namespace cx
92 {
93 
94 ViewWrapper3D::ViewWrapper3D(int startIndex, ViewPtr view, VisServicesPtr services):
95  ViewWrapper(services)
96 {
97  view->getRenderer()->GetActiveCamera()->SetClippingRange(0.1, 2000);
98  if (!view->getRenderWindow()->GetStereoCapableWindow())
99  view->getRenderWindow()->StereoCapableWindowOn(); // Just set all 3D views 3D capable
100 
101  mShowAxes = false;
102  mView = view;
103  this->connectContextMenu(mView);
104  QString index = QString::number(startIndex);
105  QColor background = settings()->value("backgroundColor").value<QColor>();
106  mView->setBackgroundColor(background);
107 
108  view->getRenderer()->GetActiveCamera()->SetParallelProjection(false);
109 // connect(settings(), SIGNAL(valueChangedFor(QString)), this, SLOT(settingsChangedSlot(QString)));
110 
111  this->initializeMultiVolume3DRepProducer();
112 
113  mLandmarkRep = LandmarkRep::New(mServices->patient());
114  mLandmarkRep->setGraphicsSize(settings()->value("View3D/sphereRadius").toDouble());
115  mLandmarkRep->setLabelSize(settings()->value("View3D/labelSize").toDouble());
116 
117  mPickerRep = PickerRep::New(mServices->patient());
118 
119  connect(mPickerRep.get(), SIGNAL(pointPicked(Vector3D)), this, SLOT(pickerRepPointPickedSlot(Vector3D)));
120 // connect(mPickerRep.get(), SIGNAL(dataPicked(QString)), this, SLOT(pickerRepDataPickedSlot(QString)));
121  mPickerRep->setSphereRadius(settings()->value("View3D/sphereRadius").toDouble());
122  mPickerRep->setEnabled(false);
123  mView->addRep(mPickerRep);
124  connect(mServices->tracking().get(), SIGNAL(activeToolChanged(const QString&)), this, SLOT(activeToolChangedSlot()));
125  this->activeToolChangedSlot();
126 
127  this->ViewWrapper::addReps();
128 
129  //data name text rep
130  this->updateMetricNamesRep();
131 
132  connect(mServices->tracking().get(), &TrackingService::stateChanged, this, &ViewWrapper3D::toolsAvailableSlot);
133  connect(mServices->patient()->getActiveData().get(), &ActiveData::activeImageChanged, this, &ViewWrapper3D::activeImageChangedSlot);
134  this->toolsAvailableSlot();
135 
137  this->settingsChangedSlot("View3D/annotationModel");
138  this->settingsChangedSlot("View3D/annotationModelSize");
139  mView->addRep(mAnnotationMarker);
140 
141 //Stereo
142 // mView->getRenderWindow()->StereoCapableWindowOn(); // Moved to cxView3D
143 // connect(settings(), SIGNAL(valueChangedFor(QString)), this, SLOT(globalConfigurationFileChangedSlot(QString)));
144  //Init 3D stereo from settings
145  this->setStereoType(settings()->value("View3D/stereoType").toInt());
146  this->setStereoEyeAngle(settings()->value("View3D/eyeAngle").toDouble());
147 
148  setupTransparentMeshes();
149 
150  this->updateView();
151 }
152 
154 {
155  if (mView)
156  {
157  mView->removeReps();
158  mMultiVolume3DRepProducer->removeRepsFromView();
159  }
160 }
161 
162 void ViewWrapper3D::setupTransparentMeshes()
163 {
164  //Setting up depth peeling in constructor fails (on Ubuntu 20.04).
165  //Delay until we get first active data to make sure VTK structures are correctly setup.
166  connect(mServices->patient()->getActiveData().get(), &ActiveData::activeDataChanged, this, &ViewWrapper3D::enableTransparentMeshesSlot);
167 }
168 
170 {
171  this->setTranslucentRenderingToDepthPeeling(settings()->value("View3D/depthPeeling").toBool());
172  disconnect(mServices->patient()->getActiveData().get(), &ActiveData::activeDataChanged, this, &ViewWrapper3D::enableTransparentMeshesSlot);
173 }
174 
175 void ViewWrapper3D::initializeMultiVolume3DRepProducer()
176 {
177  if (!mView)
178  reportError("Missing View in initializeMultiVolume3DRepProducer");
179 
180  if (!mMultiVolume3DRepProducer)
181  {
182  mMultiVolume3DRepProducer.reset(new MultiVolume3DRepProducer());
183  connect(mMultiVolume3DRepProducer.get(), SIGNAL(imagesChanged()), this, SLOT(updateView()));
184  mMultiVolume3DRepProducer->setView(mView);
185  }
186 
187  mMultiVolume3DRepProducer->setMaxRenderSize(settings()->value("View3D/maxRenderSize").toInt());
188  mMultiVolume3DRepProducer->setVisualizerType(settings()->value("View3D/ImageRender3DVisualizer").toString());
189 }
190 
192 {
194 
195  if (key == "View3D/stereoType")
196  {
197  this->setStereoType(settings()->value("View3D/stereoType").toInt());
198  }
199  if (key == "View3D/eyeAngle")
200  {
201  this->setStereoEyeAngle(settings()->value("View3D/eyeAngle").toDouble());
202  }
203  if (key == "backgroundColor")
204  {
205  QColor background = settings()->value("backgroundColor").value<QColor>();
206  mView->setBackgroundColor(background);
207  }
208  if (( key=="View3D/ImageRender3DVisualizer" )||( key=="View3D/maxRenderSize" ))
209  {
210  this->initializeMultiVolume3DRepProducer();
211  }
212  if ((key == "View/showDataText")
213  || (key == "View/showOrientationAnnotation"))
214  {
215  this->updateView();
216  }
217  if ((key == "View3D/annotationModelSize" )||( key == "View3D/annotationModel"))
218  {
219  QString annotationFile = settings()->value("View3D/annotationModel").toString();
220  mAnnotationMarker->setMarkerFilename(DataLocations::findConfigFilePath(annotationFile, "/models"));
221  mAnnotationMarker->setSize(settings()->value("View3D/annotationModelSize").toDouble());
222  }
223  if (key == "View3D/showManualTool")
224  {
225  this->toolsAvailableSlot();
226  }
227  if ((key == "View3D/sphereRadius" )
228  ||( key == "View3D/labelSize" )
229  ||( key == "View/showLabels")
230  ||( key == "View/showMetricNamesInCorner"))
231  {
232  for (RepMap::iterator iter = mDataReps.begin(); iter != mDataReps.end(); ++iter)
233  {
234  this->readDataRepSettings(iter->second);
235  }
236 
237  this->updateMetricNamesRep();
238 
239  this->toolsAvailableSlot();
240  mLandmarkRep->setGraphicsSize(settings()->value("View3D/sphereRadius").toDouble());
241  mLandmarkRep->setLabelSize(settings()->value("View3D/labelSize").toDouble());
242  }
243  if (key == "View3D/depthPeeling")
244  this->setTranslucentRenderingToDepthPeeling(settings()->value("View3D/depthPeeling").toBool());
245 }
246 
247 void ViewWrapper3D::updateMetricNamesRep()
248 {
249  bool enabled = settings()->value("View/showMetricNamesInCorner").value<bool>();
250 
251  if (enabled)
252  {
253  if (!mMetricNames)
254  {
255  mMetricNames = MetricNamesRep::New();
256  mView->addRep(mMetricNames);
257  }
258 
259  if (mGroupData)
260  mMetricNames->setData(mGroupData->getData());
261  }
262  else
263  {
264  mView->removeRep(mMetricNames);
265  mMetricNames.reset();
266  }
267 }
268 
269 void ViewWrapper3D::pickerRepPointPickedSlot(Vector3D p_r)
270 {
271  NavigationPtr nav = this->getNavigation();
272  nav->centerToPosition(p_r, Navigation::v2D);
273 }
274 
275 void ViewWrapper3D::pickerRepDataPickedSlot(QString uid)
276 {
277  //std::cout << "picked: " << uid << std::endl;
278 }
279 
280 void ViewWrapper3D::appendToContextMenu(QMenu& contextMenu)
281 {
282  QAction* slicePlanesAction = NULL;
283  QAction* fillSlicePlanesAction = NULL;
284  if (mSlicePlanes3DRep)
285  {
286  slicePlanesAction = new QAction("Show Slice Planes", &contextMenu);
287  slicePlanesAction->setCheckable(true);
288  slicePlanesAction->setChecked(mSlicePlanes3DRep->getProxy()->getVisible());
289  slicePlanesAction->setToolTip("Visialize the outline of the 2D views in 3D");
290  connect(slicePlanesAction, SIGNAL(triggered(bool)), this, SLOT(showSlicePlanesActionSlot(bool)));
291 
292  fillSlicePlanesAction = new QAction("Fill Slice Planes", &contextMenu);
293  fillSlicePlanesAction->setCheckable(true);
294  fillSlicePlanesAction->setEnabled(mSlicePlanes3DRep->getProxy()->getVisible());
295  fillSlicePlanesAction->setChecked(mSlicePlanes3DRep->getProxy()->getDrawPlanes());
296  slicePlanesAction->setToolTip("Fill the visualized 2D views with color");
297  connect(fillSlicePlanesAction, SIGNAL(triggered(bool)), this, SLOT(fillSlicePlanesActionSlot(bool)));
298  }
299 
300  QAction* resetCameraAction = new QAction("Reset Camera (r)", &contextMenu);
301  resetCameraAction->setToolTip("Zoom out, and show all objects in the view");
302  connect(resetCameraAction, SIGNAL(triggered()), this, SLOT(resetCameraActionSlot()));
303 
304  QAction* centerImageAction = new QAction("Center to image", &contextMenu);
305  centerImageAction->setToolTip("Move view to show center of active image in all views (no zoom)");
306  connect(centerImageAction, SIGNAL(triggered()), this, SLOT(centerImageActionSlot()));
307 
308  QAction* centerToolAction = new QAction("Center to tool", &contextMenu);
309  centerToolAction->setToolTip("Move view to show active tool in all views (no zoom)");
310  connect(centerToolAction, SIGNAL(triggered()), this, SLOT(centerToolActionSlot()));
311 
312  QAction* showAxesAction = new QAction("Show Coordinate Axes", &contextMenu);
313  showAxesAction->setCheckable(true);
314  showAxesAction->setChecked(mShowAxes);
315  showAxesAction->setToolTip("Show coordinate axes for all objects in 3D scene.\n"
316  "Axes are placed in obejct origin.\n"
317  "Red = X, Green = Y, Blue = Z");
318  connect(showAxesAction, SIGNAL(triggered(bool)), this, SLOT(showAxesActionSlot(bool)));
319 
320  QAction* showManualTool = new QAction("Show Manual Tool 3D", &contextMenu);
321  showManualTool->setCheckable(true);
322  showManualTool->setChecked(settings()->value("View3D/showManualTool").toBool());
323  showManualTool->setToolTip("Turn on/off visualization of the 3D vire cross");
324  connect(showManualTool, SIGNAL(triggered(bool)), this, SLOT(showManualToolSlot(bool)));
325 
326  QAction* showOrientation = new QAction("Show Orientation", &contextMenu);
327  showOrientation->setCheckable(true);
328  showOrientation->setChecked(mAnnotationMarker->getVisible());
329  showOrientation->setToolTip("Turn on/off visualization of the figure in the upper left corner in 3D,\n"
330  "and the orientation letters on the sides in 2D");
331  connect(showOrientation, SIGNAL(triggered(bool)), this, SLOT(showOrientationSlot(bool)));
332 
333  QAction* showToolPath = new QAction("Show Tool Path", &contextMenu);
334  showToolPath->setCheckable(true);
335  showToolPath->setChecked(settings()->value("showToolPath").toBool());
336  showToolPath->setToolTip("Paint a line in 3D where the tool have been, as connected dots.\n"
337  "Turn off to reset");
338  connect(showToolPath, SIGNAL(triggered(bool)), this, SLOT(showToolPathSlot(bool)));
339 
340  QMenu* show3DSlicesMenu = new QMenu("Show 3D slices");
341  show3DSlicesMenu->setToolTip("Visualize the 2D views in 3D for the selected image");
342  mShow3DSlicesInteractor->addDataActionsOfType<Image>(show3DSlicesMenu);
343 
344  QMenu* showSlicesMenu = new QMenu("Slice Type", &contextMenu);
345  showSlicesMenu->setToolTip("Specify which 2D slices to show in 3D,\n"
346  "when 3D sclices is turned on");
347  this->createSlicesActions(showSlicesMenu);
348 
349  QAction* showRefTool = new QAction("Show Reference Tool", &contextMenu);
350  showRefTool->setDisabled(true);
351  showRefTool->setCheckable(true);
352  showRefTool->setToolTip("Visualize the tool set as reference in 3D");
353  ToolPtr refTool = mServices->tracking()->getReferenceTool();
354  if (refTool)
355  {
356  showRefTool->setText("Show " + refTool->getName());
357  showRefTool->setEnabled(true);
358  showRefTool->setChecked(RepContainer(mView->getReps()).findFirst<ToolRep3D>(refTool) ? true : false);
359  connect(showRefTool, SIGNAL(toggled(bool)), this, SLOT(showRefToolSlot(bool)));
360  }
361 
362  contextMenu.addSeparator();
363  contextMenu.addMenu(show3DSlicesMenu);
364  contextMenu.addMenu(showSlicesMenu);
365  contextMenu.addSeparator();
366  contextMenu.addAction(resetCameraAction);
367  contextMenu.addAction(centerImageAction);
368  contextMenu.addAction(centerToolAction);
369  contextMenu.addAction(showAxesAction);
370  contextMenu.addAction(showOrientation);
371  contextMenu.addSeparator();
372  contextMenu.addAction(showManualTool);
373  contextMenu.addAction(showRefTool);
374  if (showToolPath)
375  contextMenu.addAction(showToolPath);
376  contextMenu.addSeparator();
377  if (slicePlanesAction)
378  contextMenu.addAction(slicePlanesAction);
379  if (fillSlicePlanesAction)
380  contextMenu.addAction(fillSlicePlanesAction);
381 }
382 
383 void ViewWrapper3D::createSlicesActions(QWidget* parent)
384 {
385  this->createSlicesAction(PlaneTypeCollection(ptAXIAL, ptCORONAL, ptSAGITTAL), parent);
386  this->createSlicesAction(PlaneTypeCollection(ptAXIAL), parent);
387  this->createSlicesAction(PlaneTypeCollection(ptCORONAL), parent);
388  this->createSlicesAction(PlaneTypeCollection(ptSAGITTAL), parent);
389  this->createSlicesAction(PlaneTypeCollection(ptANYPLANE), parent);
390  this->createSlicesAction(PlaneTypeCollection(ptINVERSEANYPLANE), parent);
391  this->createSlicesAction(PlaneTypeCollection(ptRADIALPLANE), parent);
392  this->createSlicesAction(PlaneTypeCollection(ptSIDEPLANE), parent);
393  this->createSlicesAction(PlaneTypeCollection(ptTOOLSIDEPLANE), parent);
394 }
395 
396 QAction* ViewWrapper3D::createSlicesAction(PlaneTypeCollection planes, QWidget* parent)
397 {
398  QString title = planes.toString();
399  QString active = mGroupData->getSliceDefinitions().toString();
400 
401  QAction* action = new QAction(title, parent);
402  connect(action, SIGNAL(triggered()), this, SLOT(showSlices()));
403  action->setData(title);
404  action->setCheckable(true);
405  action->setChecked(active == title);
406 
407  parent->addAction(action);
408  return action;
409 }
410 
411 void ViewWrapper3D::showSlices()
412 {
413  QAction* action = dynamic_cast<QAction*>(sender());
414  if (!action)
415  return;
416 
417  PlaneTypeCollection planes = PlaneTypeCollection::fromString(action->data().toString());
418 
419  if (!action->isChecked())
420  mGroupData->setSliceDefinitions(PlaneTypeCollection());
421  else
422  mGroupData->setSliceDefinitions(planes);
423 }
424 
426 {
428 
429  connect(group.get(), &ViewGroupData::initialized, this, &ViewWrapper3D::resetCameraActionSlot);
430  connect(group.get(), &ViewGroupData::optionsChanged, this, &ViewWrapper3D::optionChangedSlot);
431  mView->getRenderer()->SetActiveCamera(mGroupData->getCamera3D()->getCamera());
432 
433  // Set eye angle after camera change. Maybe create a cameraChangedSlot instead
434  this->setStereoEyeAngle(settings()->value("View3D/eyeAngle").toDouble());
435  this->optionChangedSlot();
436 
437 }
438 
439 void ViewWrapper3D::showToolPathSlot(bool checked)
440 {
441  ToolPtr tool = mServices->tracking()->getActiveTool();
442  ToolRep3DPtr activeRep3D = RepContainer(mView->getReps()).findFirst<ToolRep3D>(tool);
443  if (activeRep3D)
444  {
445  if(checked)
446  {
447  activeRep3D->getTracer()->start();
448  }
449  else if(!checked)
450  {
451  activeRep3D->getTracer()->stop();
452  activeRep3D->getTracer()->clear();
453  }
454  }
455 
456  settings()->setValue("showToolPath", checked);
457 }
458 
459 void ViewWrapper3D::showAxesActionSlot(bool checked)
460 {
461  if (mShowAxes == checked)
462  return;
463 
464  mShowAxes = checked;
465 
466  // clear all
467  for (unsigned i=0; i<mAxis.size(); ++i)
468  mView->removeRep(mAxis[i]->mRep);
469  mAxis.clear();
470 
471  // show all
472  if (mShowAxes)
473  {
474  AxisConnectorPtr axis;
475 
476  // reference space
477  axis.reset(new AxisConnector(CoordinateSystem(csREF), mServices->spaceProvider()));
478  axis->mRep->setAxisLength(0.12);
479  axis->mRep->setShowAxesLabels(true);
480  axis->mRep->setCaption("ref", Vector3D(1, 0, 0));
481  axis->mRep->setFontSize(0.03);
482  mAxis.push_back(axis);
483 
484  // data spaces
485  std::vector<DataPtr> data = mGroupData->getData();
486  for (unsigned i = 0; i < data.size(); ++i)
487  {
488  axis.reset(new AxisConnector(CoordinateSystem(csDATA, data[i]->getUid()), mServices->spaceProvider()));
489  axis->mRep->setAxisLength(0.08);
490  axis->mRep->setShowAxesLabels(false);
491  axis->mRep->setCaption(data[i]->getName(), Vector3D(1, 0, 0));
492  axis->mRep->setFontSize(0.03);
493  mAxis.push_back(axis);
494  }
495 
496  // tool spaces
497  TrackingService::ToolMap tools = mServices->tracking()->getTools();
498  TrackingService::ToolMap::iterator iter;
499  for (iter = tools.begin(); iter != tools.end(); ++iter)
500  {
501  ToolPtr tool = iter->second;
502 
503  axis.reset(new AxisConnector(CoordinateSystem(csTOOL, tool->getUid()), mServices->spaceProvider()));
504  axis->mRep->setAxisLength(0.08);
505  axis->mRep->setShowAxesLabels(false);
506  axis->mRep->setCaption("t", Vector3D(0.7, 1, 0.7));
507  axis->mRep->setFontSize(0.03);
508  axis->connectTo(tool);
509  SpaceListenerPtr mToolListener = axis->mListener;
510 
511  mAxis.push_back(axis);
512 
513  axis.reset(new AxisConnector(CoordinateSystem(csSENSOR, tool->getUid()), mServices->spaceProvider()));
514  axis->mRep->setAxisLength(0.05);
515  axis->mRep->setShowAxesLabels(false);
516  axis->mRep->setCaption("s", Vector3D(1, 1, 0));
517  axis->mRep->setFontSize(0.03);
518  axis->connectTo(tool);
519  axis->mergeWith(mToolListener);
520  mAxis.push_back(axis);
521  }
522 
523  for (unsigned i=0; i<mAxis.size(); ++i)
524  mView->addRep(mAxis[i]->mRep);
525  }
526 }
527 
528 void ViewWrapper3D::showManualToolSlot(bool visible)
529 {
530  settings()->setValue("View3D/showManualTool", visible);
531 }
532 
533 void ViewWrapper3D::showOrientationSlot(bool visible)
534 {
535  settings()->setValue("View/showOrientationAnnotation", visible);
536  this->updateView();
537 }
538 
539 void ViewWrapper3D::resetCameraActionSlot()
540 {
541  mView->getRenderer()->ResetCamera();
542  //Update eye angle after camera is reset
543  this->setStereoEyeAngle(settings()->value("View3D/eyeAngle").toDouble());
544 }
545 
546 NavigationPtr ViewWrapper3D::getNavigation()
547 {
548  CameraControlPtr camera3D(new CameraControl());
549  camera3D->setView(mView);
550 
551  return NavigationPtr(new Navigation(mServices, camera3D));
552 }
553 
554 void ViewWrapper3D::centerImageActionSlot()
555 {
556  NavigationPtr nav = this->getNavigation();
557  nav->centerToDataInViewGroup(mGroupData, DataViewProperties::create3D());
558 }
559 
560 void ViewWrapper3D::centerToolActionSlot()
561 {
562  NavigationPtr nav = this->getNavigation();
563  nav->centerToTooltip();
564 }
565 
566 void ViewWrapper3D::showSlicePlanesActionSlot(bool checked)
567 {
568  if (!mSlicePlanes3DRep)
569  return;
570  mSlicePlanes3DRep->getProxy()->setVisible(checked);
571  settings()->setValue("showSlicePlanes", checked);
572 }
573 
574 void ViewWrapper3D::fillSlicePlanesActionSlot(bool checked)
575 {
576  if (!mSlicePlanes3DRep)
577  return;
578  mSlicePlanes3DRep->getProxy()->setDrawPlanes(checked);
579 }
580 
582 {
583  DataPtr data = mServices->patient()->getData(uid);
584  DataViewProperties properties = mGroupData->getProperties(uid);
585 
586  if (properties.hasVolume3D())
587  this->addVolumeDataRep(data);
588  else
589  this->removeVolumeDataRep(uid);
590 
591  this->updateSlices();
592 
593  this->updateView();
594 }
595 
596 void ViewWrapper3D::addVolumeDataRep(DataPtr data)
597 {
598  if (!data)
599  return;
600  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
601  if (image)
602  {
603  mMultiVolume3DRepProducer->addImage(image);
604  }
605  else
606  {
607  if (!mDataReps.count(data->getUid()))
608  {
609  RepPtr rep = this->createDataRep3D(data);
610  if (rep)
611  {
612  mDataReps[data->getUid()] = rep;
613  mView->addRep(rep);
614  }
615  }
616  }
617 }
618 
619 void ViewWrapper3D::removeVolumeDataRep(QString uid)
620 {
621  mMultiVolume3DRepProducer->removeImage(uid);
622  if (mDataReps.count(uid))
623  {
624  mView->removeRep(mDataReps[uid]);
625  mDataReps.erase(uid);
626  }
627 }
628 
632 RepPtr ViewWrapper3D::createDataRep3D(DataPtr data)
633 {
634  if (boost::dynamic_pointer_cast<Mesh>(data))
635  {
637  rep->setMesh(boost::dynamic_pointer_cast<Mesh>(data));
638  return rep;
639  }
640  else if (boost::dynamic_pointer_cast<TrackedStream>(data))
641  {
642  TrackedStreamPtr trackedStream = boost::dynamic_pointer_cast<TrackedStream>(data);
643  return this->createTrackedStreamRep(trackedStream);
644  }
645  else
646  {
647  DataMetricRepPtr rep = this->createDataMetricRep3D(data);
648  if (rep)
649  return rep;
650  }
651 
652  return RepPtr();
653 }
654 
655 RepPtr ViewWrapper3D::createTrackedStreamRep(TrackedStreamPtr trackedStream)
656 {
657  if(!trackedStream->hasVideo())
658  {
659  connect(trackedStream.get(), &TrackedStream::streamChanged, this, &ViewWrapper3D::dataViewPropertiesChangedSlot);
660  return RepPtr();
661  }
662  else
663  disconnect(trackedStream.get(), &TrackedStream::streamChanged, this, &ViewWrapper3D::dataViewPropertiesChangedSlot);
664  if(trackedStream->is3D())
665  {
666  StreamRep3DPtr rep = StreamRep3D::New(mServices->spaceProvider(), mServices->patient());
667  rep->setTrackedStream(trackedStream);
668  return rep;
669  }
670  else if (trackedStream->is2D())
671  {
672  Stream2DRep3DPtr rep = Stream2DRep3D::New(mServices->spaceProvider());
673  rep->setTrackedStream(trackedStream);
674  return rep;
675  }
676  else
677  {
678  reportWarning("ViewWrapper3D::createDataRep3D. TrackedStream is not 2D or 3D");
679  return RepPtr();
680  }
681 }
682 
683 DataMetricRepPtr ViewWrapper3D::createDataMetricRep3D(DataPtr data)
684 {
685  DataMetricRepPtr rep;
686 
687  if (boost::dynamic_pointer_cast<PointMetric>(data))
688  rep = PointMetricRep::New();
689  else if (boost::dynamic_pointer_cast<FrameMetric>(data))
690  rep = FrameMetricRep::New();
691  else if (boost::dynamic_pointer_cast<ToolMetric>(data))
692  rep = ToolMetricRep::New();
693  else if (boost::dynamic_pointer_cast<DistanceMetric>(data))
694  rep = DistanceMetricRep::New();
695  else if (boost::dynamic_pointer_cast<AngleMetric>(data))
696  rep = AngleMetricRep::New();
697  else if (boost::dynamic_pointer_cast<PlaneMetric>(data))
698  rep = PlaneMetricRep::New();
699  else if (boost::dynamic_pointer_cast<DonutMetric>(data))
700  rep = DonutMetricRep::New();
701  else if (boost::dynamic_pointer_cast<CustomMetric>(data))
702  rep = CustomMetricRep::New();
703  else if (boost::dynamic_pointer_cast<SphereMetric>(data))
704  rep = SphereMetricRep::New();
705  else if (boost::dynamic_pointer_cast<RegionOfInterestMetric>(data))
707 
708  if (rep)
709  {
710  this->readDataRepSettings(rep);
711  rep->setDataMetric(boost::dynamic_pointer_cast<DataMetric>(data));
712  }
713  return rep;
714 }
715 
719 void ViewWrapper3D::readDataRepSettings(RepPtr rep)
720 {
721  DataMetricRepPtr val = boost::dynamic_pointer_cast<DataMetricRep>(rep);
722  if (!val)
723  return;
724 
725  val->setGraphicsSize(settings()->value("View3D/sphereRadius").toDouble());
726  val->setShowLabel(settings()->value("View/showLabels").toBool());
727  val->setLabelSize(settings()->value("View3D/labelSize").toDouble());
728  val->setShowAnnotation(!settings()->value("View/showMetricNamesInCorner").toBool());
729 }
730 
732 {
733  return this->getAllDataNames(DataViewProperties::create3D()).join("\n");
734 }
735 
737 {
738  return "3D";
739 }
740 
741 void ViewWrapper3D::updateView()
742 {
743  this->ViewWrapper::updateView();
744 
745  if (!this->getView())
746  return;
747 
748  this->updateMetricNamesRep();
749 
750  mAnnotationMarker->setVisible(settings()->value("View/showOrientationAnnotation").value<bool>());
751 
752  ToolRep3DPtr manualToolRep = RepContainer(mView->getReps()).findManualToolRep<ToolRep3D>();
753  if (manualToolRep)
754  {
755  manualToolRep->setTooltipPointColor(settings()->value("View/toolTipPointColor").value<QColor>());
756  manualToolRep->setToolOffsetPointColor(settings()->value("View/toolOffsetPointColor").value<QColor>());
757  manualToolRep->setToolOffsetLineColor(settings()->value("View/toolOffsetLineColor").value<QColor>());
758  }
759 }
760 
761 void ViewWrapper3D::activeImageChangedSlot(QString uid)
762 {
763  if(!mGroupData)
764  return;
765  ImagePtr image = mServices->patient()->getData<Image>(uid);
766 
767  // only show landmarks belonging to image visible in this view:
768  std::vector<ImagePtr> images = mGroupData->getImages(DataViewProperties::create3D());
769  if (!std::count(images.begin(), images.end(), image))
770  image.reset();
771 }
772 
773 void ViewWrapper3D::showRefToolSlot(bool checked)
774 {
775  ToolPtr refTool = mServices->tracking()->getReferenceTool();
776  if (!refTool)
777  return;
778  ToolRep3DPtr refRep = RepContainer(mView->getReps()).findFirst<ToolRep3D>(refTool);
779  if (!refRep)
780  {
781  refRep = ToolRep3D::New(mServices->spaceProvider(), refTool->getUid() + "_rep3d_" + this->mView->getUid());
782  refRep->setTool(refTool);
783  }
784 
785  if (checked) //should show
786  mView->addRep(refRep);
787  else
788  //should not show
789  mView->removeRep(refRep);
790 }
791 
792 
793 void ViewWrapper3D::updateSlices()
794 {
795  if (mSlices3DRep)
796  mView->removeRep(mSlices3DRep);
797 
798  if (!mGroupData)
799  return;
800 
801  std::vector<ImagePtr> images = mGroupData->getImages(DataViewProperties::createSlice3D());
802 // std::vector<ImagePtr> images = mGroupData->get3DSliceImages();
803  if (images.empty())
804  return;
805 
806  std::vector<PLANE_TYPE> planes = mGroupData->getSliceDefinitions().get();
807  if (planes.empty())
808  return;
809  mSlices3DRep = Slices3DRep::New(mSharedOpenGLContext, "MultiSliceRep_" + mView->getName());
810  for (unsigned i=0; i<planes.size(); ++i)
811  mSlices3DRep->addPlane(planes[i], mServices->patient());
812  mSlices3DRep->setShaderPath(DataLocations::findConfigFolder("/shaders"));
813  mSlices3DRep->setImages(images);
814  mSlices3DRep->setTool(mServices->tracking()->getActiveTool());
815  mView->addRep(mSlices3DRep);
816 }
817 
819 {
820  return mView;
821 }
822 
823 void ViewWrapper3D::activeToolChangedSlot()
824 {
825  ToolPtr controllingTool = this->getControllingTool();
826  //CX_LOG_DEBUG() << "ViewWrapper3D::activeToolChangedSlot - controllingTool: " << controllingTool->getName();
827 
828  mPickerRep->setTool(controllingTool);
829  if (mSlices3DRep)
830  mSlices3DRep->setTool(controllingTool);
831 }
832 
833 void ViewWrapper3D::toolsAvailableSlot()
834 {
835  std::vector<ToolRep3DPtr> reps = RepContainer::findReps<ToolRep3D>(mView->getReps());
836 
837  TrackingService::ToolMap tools = mServices->tracking()->getTools();
838  TrackingService::ToolMap::iterator iter;
839  for (iter = tools.begin(); iter != tools.end(); ++iter)
840  {
841  ToolPtr tool = iter->second;
842  if (tool->hasType(Tool::TOOL_REFERENCE))
843  continue;
844 
845  ToolRep3DPtr toolRep = RepContainer(mView->getReps()).findFirst<ToolRep3D>(tool);
846 
847  std::vector<ToolRep3DPtr>::iterator oldRep = std::find(reps.begin(), reps.end(), toolRep);
848  if (oldRep!=reps.end())
849  reps.erase(oldRep);
850 
851  if (tool->hasType(Tool::TOOL_MANUAL) && !settings()->value("View3D/showManualTool").toBool())
852  {
853  if (toolRep)
854  mView->removeRep(toolRep);
855  continue;
856  }
857 
858  if (!toolRep)
859  {
860  toolRep = ToolRep3D::New(mServices->spaceProvider(), tool->getUid() + "_rep3d_" + this->mView->getUid());
861  if (settings()->value("showToolPath").toBool())
862  toolRep->getTracer()->start();
863  }
864 
865  toolRep->setSphereRadius(settings()->value("View3D/sphereRadius").toDouble()); // use fraction of set size
866  toolRep->setSphereRadiusInNormalizedViewport(true);
867 
868  toolRep->setTool(tool);
869  toolRep->setOffsetPointVisibleAtZeroOffset(true);
870  mView->addRep(toolRep);
871  }
872 
873  // remove reps for tools no longer present
874  for (unsigned i=0; i<reps.size(); ++i)
875  {
876  mView->removeRep(reps[i]);
877  }
878 }
879 
880 void ViewWrapper3D::optionChangedSlot()
881 {
882  ViewGroupData::Options options = mGroupData->getOptions();
883 
884  this->showLandmarks(options.mShowLandmarks);
885  this->showPointPickerProbe(options.mShowPointPickerProbe);
886  mPickerRep->setGlyph(options.mPickerGlyph);
887 
888  this->updateSlices();
889 }
890 
891 void ViewWrapper3D::showLandmarks(bool on)
892 {
893  if (mLandmarkRep->isConnectedToView(mView) == on)
894  return;
895 
896  if (on)
897  {
898  mView->addRep(mLandmarkRep);
899  }
900  else
901  {
902  mView->removeRep(mLandmarkRep);
903  }
904 }
905 
906 void ViewWrapper3D::showPointPickerProbe(bool on)
907 {
908  mPickerRep->setEnabled(on);
909 }
910 
912 {
913  mSlicePlanes3DRep = SlicePlanes3DRep::New("uid");
914  mSlicePlanes3DRep->setProxy(proxy);
915  mSlicePlanes3DRep->setDynamicLabelSize(true);
916  bool show = settings()->value("showSlicePlanes").toBool();
917  mSlicePlanes3DRep->getProxy()->setVisible(show); // init with default value
918 
919  mView->addRep(mSlicePlanes3DRep);
920 }
921 
922 void ViewWrapper3D::setStereoType(int /*STEREOTYPE*/type)
923 {
924  switch (type)
925  //STEREOTYPE
926  {
927  case stFRAME_SEQUENTIAL:
928  mView->getRenderWindow()->SetStereoTypeToCrystalEyes();
929  break;
930  case stINTERLACED:
931  mView->getRenderWindow()->SetStereoTypeToInterlaced();
932  break;
933  case stDRESDEN:
934  mView->getRenderWindow()->SetStereoTypeToDresden();
935  break;
936  case stRED_BLUE:
937  mView->getRenderWindow()->SetStereoTypeToRedBlue();
938  break;
939  }
940 }
941 
942 void ViewWrapper3D::setStereoEyeAngle(double angle)
943 {
944  mView->getRenderer()->GetActiveCamera()->SetEyeAngle(angle);
945 }
946 
947 void ViewWrapper3D::setTranslucentRenderingToDepthPeeling(bool setDepthPeeling)
948 {
949  if(setDepthPeeling)
950  {
951  bool isDPSupported = true;
952 
953  //IsDepthPeelingSupported function don't seem to work on OSX (error messages or seg. fault)
954 #ifndef __APPLE__
955  if (!IsDepthPeelingSupported(mView->getRenderWindow(), mView->getRenderer(), true))
956  {
957  reportWarning("GPU do not support depth peeling. Rendering of translucent surfaces is not supported");
958  isDPSupported = false;
959  }
960 #endif
961 
962  if (isDPSupported && SetupEnvironmentForDepthPeeling(mView->getRenderWindow(), mView->getRenderer(), 100, 0.1))
963  {
964  report("Set GPU depth peeling");
965  }
966  else
967  {
968  reportWarning("Error setting depth peeling. The GPU or operating system might not support it.");
969  settings()->setValue("View3D/depthPeeling", false);
970  }
971  }
972  else
973  {
974  TurnOffDepthPeeling(mView->getRenderWindow(), mView->getRenderer());
975  }
976 }
977 
978 //------------------------------------------------------------------------------
979 }
bool SetupEnvironmentForDepthPeeling(vtkSmartPointer< vtkRenderWindow > renderWindow, vtkSmartPointer< vtkRenderer > renderer, int maxNoOfPeels, double occlusionRatio)
virtual QString getDataDescription()
static DataViewProperties createSlice3D()
static LandmarkRepPtr New(PatientModelServicePtr dataManager, const QString &uid="")
ToolPtr getControllingTool()
virtual void dataViewPropertiesChangedSlot(QString uid)
boost::shared_ptr< class ViewGroupData > ViewGroupDataPtr
Definition: cxViewGroup.h:29
ptCORONAL
a slice seen from the front of the patient
Definition: cxDefinitions.h:39
void reportError(QString msg)
Definition: cxLogger.cpp:71
static DonutMetricRepPtr New(const QString &uid="")
static RepManager * getInstance()
get the only instance of this class
boost::shared_ptr< class SlicePlanesProxy > SlicePlanesProxyPtr
boost::shared_ptr< class Stream2DRep3D > Stream2DRep3DPtr
boost::shared_ptr< class CameraControl > CameraControlPtr
boost::shared_ptr< class TrackedStream > TrackedStreamPtr
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
virtual ViewPtr getView()
csSENSOR
a tools sensor space (s)
Definition: cxDefinitions.h:90
void setStereoType(int type)
static SlicePlanes3DRepPtr New(const QString &uid="")
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
Superclass for ViewWrappers.
Definition: cxViewWrapper.h:89
boost::shared_ptr< REP > getCachedRep(QString uid="")
Definition: cxRepManager.h:72
SharedOpenGLContextPtr mSharedOpenGLContext
virtual void setSlicePlanesProxy(SlicePlanesProxyPtr proxy)
csREF
the data reference space (r) using LPS (left-posterior-superior) coordinates.
Definition: cxDefinitions.h:90
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:66
static PlaneMetricRepPtr New(const QString &uid="")
boost::shared_ptr< class StreamRep3D > StreamRep3DPtr
ptAXIAL
a slice seen from the top of the patient
Definition: cxDefinitions.h:39
Base class for all Data Metric reps.
static AngleMetricRepPtr New(const QString &uid="")
boost::shared_ptr< class DataMetricRep > DataMetricRepPtr
Class for display of an orientation annotation cube in 3D.
virtual void settingsChangedSlot(QString key)
void enableTransparentMeshesSlot()
A data set for video streams (2D/3D).
boost::shared_ptr< class View > ViewPtr
stFRAME_SEQUENTIAL
csDATA
a datas space (d)
Definition: cxDefinitions.h:90
static ToolMetricRepPtr New(const QString &uid="")
Reference tool.
Definition: cxTool.h:84
static DataViewProperties create3D()
static Stream2DRep3DPtr New(SpaceProviderPtr spaceProvider, const QString &uid="")
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:58
virtual void setViewGroup(ViewGroupDataPtr group)
boost::shared_ptr< class Data > DataPtr
stINTERLACED
static MetricNamesRepPtr New(const QString &uid="")
static QString findConfigFolder(QString pathRelativeToConfigRoot, QString alternativeAbsolutePath="")
void streamChanged(QString uid)
void settingsChangedSlot(QString key)
ptSAGITTAL
a slice seen from the side of the patient
Definition: cxDefinitions.h:39
static PlaneTypeCollection fromString(QString input, PlaneTypeCollection defVal=PlaneTypeCollection())
void reportWarning(QString msg)
Definition: cxLogger.cpp:70
static FrameMetricRepPtr New(const QString &uid="")
ptTOOLSIDEPLANE
z-rotated 90* relative to anyplane like side plane, but always kept oriented like the plane defined b...
Definition: cxDefinitions.h:39
ViewGroupDataPtr mGroupData
void activeDataChanged(const QString &uId)
A volumetric data set.
Definition: cxImage.h:45
Identification of a Coordinate system.
static QString findConfigFilePath(QString fileName, QString pathRelativeToConfigRoot, QString alternativeAbsolutePath="")
virtual QString getViewDescription()
Representation of a mouse/keyboard-controlled virtual tool.
Definition: cxTool.h:85
static GeometricRepPtr New(const QString &uid="")
ptINVERSEANYPLANE
a plane aligned with the tool base plane, inverse of tool direction
Definition: cxDefinitions.h:39
virtual void setViewGroup(ViewGroupDataPtr group)
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:21
static Slices3DRepPtr New(SharedOpenGLContextPtr context, const QString &uid)
static RegionOfInterestMetricRepPtr New(const QString &uid="")
std::map< QString, ToolPtr > ToolMap
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
boost::shared_ptr< class AxisConnector > AxisConnectorPtr
ptRADIALPLANE
y-rotated 90* relative to anyplane (bird&#39;s view)
Definition: cxDefinitions.h:39
bool hasVolume3D() const
bool TurnOffDepthPeeling(vtkSmartPointer< vtkRenderWindow > renderWindow, vtkSmartPointer< vtkRenderer > renderer)
Turn off depth peeling.
virtual void addReps()
void report(QString msg)
Definition: cxLogger.cpp:69
VisServicesPtr mServices
QStringList getAllDataNames(DataViewProperties properties) const
static PointMetricRepPtr New(const QString &uid="")
boost::shared_ptr< class SpaceListener > SpaceListenerPtr
stDRESDEN
virtual void updateView()
static StreamRep3DPtr New(SpaceProviderPtr spaceProvider, PatientModelServicePtr patientModelService, const QString &uid="")
static PickerRepPtr New(PatientModelServicePtr dataManager, const QString &uid="")
for creating new instances
Definition: cxPickerRep.cpp:54
DataViewPropertiesInteractorPtr mShow3DSlicesInteractor
static ToolRep3DPtr New(SpaceProviderPtr spaceProvider, const QString &uid="")
Definition: cxToolRep3D.cpp:74
boost::shared_ptr< class ToolRep3D > ToolRep3DPtr
ptANYPLANE
a plane aligned with the tool base plane
Definition: cxDefinitions.h:39
ViewWrapper3D(int startIndex, ViewPtr view, VisServicesPtr services)
boost::shared_ptr< class Navigation > NavigationPtr
bool IsDepthPeelingSupported(vtkSmartPointer< vtkRenderWindow > renderWindow, vtkSmartPointer< vtkRenderer > renderer, bool doItOffScreen)
void connectContextMenu(ViewPtr view)
csTOOL
a tools rspace (t)
Definition: cxDefinitions.h:90
boost::shared_ptr< class Rep > RepPtr
Definition: cxRepManager.h:24
static DistanceMetricRepPtr New(const QString &uid="")
static SphereMetricRepPtr New(const QString &uid="")
void setGraphicsSize(double size)
ptSIDEPLANE
z-rotated 90* relative to anyplane (dual anyplane)
Definition: cxDefinitions.h:39
static CustomMetricRepPtr New(const QString &uid="")
void activeImageChanged(const QString &uId)
boost::shared_ptr< class GeometricRep > GeometricRepPtr
Namespace for all CustusX production code.
boost::shared_ptr< class Tool > ToolPtr