CustusX  2021.09.21-dev+develop.e3cd0
An IGT application
cxImageLandmarksWidget.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 "cxImageLandmarksWidget.h"
13 
14 #include <sstream>
15 #include <QVBoxLayout>
16 #include <QPushButton>
17 #include <QTableWidget>
18 #include <QTableWidgetItem>
19 #include <QHeaderView>
20 #include <QLabel>
21 #include <QSlider>
22 #include <vtkDoubleArray.h>
23 #include <vtkImageData.h>
24 #include "cxLogger.h"
25 #include "cxPickerRep.h"
27 #include "cxSettings.h"
28 #include "cxLandmarkRep.h"
29 #include "cxView.h"
30 #include "cxTypeConversions.h"
32 #include "cxRegistrationService.h"
33 #include "cxPatientModelService.h"
34 #include "cxViewService.h"
35 #include "cxRepContainer.h"
36 #include "cxTrackingService.h"
37 #include "cxLandmarkListener.h"
38 #include "cxActiveData.h"
39 #include "cxPointMetric.h"
40 #include "cxSpaceProvider.h"
41 
42 namespace cx
43 {
44 ImageLandmarksWidget::ImageLandmarksWidget(RegServicesPtr services, QWidget* parent,
45  QString objectName, QString windowTitle, bool useRegistrationFixedPropertyInsteadOfActiveImage) :
46  LandmarkRegistrationWidget(services, parent, objectName, windowTitle),
47  mUseRegistrationFixedPropertyInsteadOfActiveImage(useRegistrationFixedPropertyInsteadOfActiveImage),
48  mLandmarksShowAdvancedSettingsString("Landmarks/ShowAdvanced")
49 {
50  if(mUseRegistrationFixedPropertyInsteadOfActiveImage)
51  mCurrentProperty.reset(new StringPropertyRegistrationFixedImage(services->registration(), services->patient()));
52  else
55 
56  mLandmarkListener->useOnlyOneSourceUpdatedFromOutside();
57 
58  mActiveToolProxy = ActiveToolProxy::New(services->tracking());
59  connect(mActiveToolProxy.get(), SIGNAL(toolVisible(bool)), this, SLOT(enableButtons()));
60  connect(mActiveToolProxy.get(), SIGNAL(activeToolChanged(const QString&)), this, SLOT(enableButtons()));
61 
62  //pushbuttons
63  mAddLandmarkButton = new QPushButton("New Landmark", this);
64  mAddLandmarkButton->setToolTip("Add landmark");
65  mAddLandmarkButton->setDisabled(true);
66  connect(mAddLandmarkButton, SIGNAL(clicked()), this, SLOT(addLandmarkButtonClickedSlot()));
67 
68  mEditLandmarkButton = new QPushButton("Resample", this);
69  mEditLandmarkButton->setToolTip("Resample the selected landmark");
70  mEditLandmarkButton->setDisabled(true);
71  connect(mEditLandmarkButton, SIGNAL(clicked()), this, SLOT(editLandmarkButtonClickedSlot()));
72 
73  mRemoveLandmarkButton = new QPushButton("Clear", this);
74  mRemoveLandmarkButton->setToolTip("Clear the selected landmark");
75  mRemoveLandmarkButton->setDisabled(true);
76  connect(mRemoveLandmarkButton, SIGNAL(clicked()), this, SLOT(removeLandmarkButtonClickedSlot()));
77 
78  mDeleteLandmarksButton = new QPushButton("Delete All", this);
79  mDeleteLandmarksButton->setToolTip("Delete all landmarks");
80  connect(mDeleteLandmarksButton, SIGNAL(clicked()), this, SLOT(deleteLandmarksButtonClickedSlot()));
81 
82  mImportLandmarksFromPointMetricsButton = new QPushButton("Import Point Metrics", this);
83  mImportLandmarksFromPointMetricsButton->setToolTip("Import point metrics as landmarks. See the help pages for the details.");
85 
86  //layout
90 
91  QHBoxLayout* landmarkButtonsLayout = new QHBoxLayout;
92  landmarkButtonsLayout->addWidget(mAddLandmarkButton);
93  landmarkButtonsLayout->addWidget(mEditLandmarkButton);
94  landmarkButtonsLayout->addWidget(mRemoveLandmarkButton);
95  landmarkButtonsLayout->addWidget(mDeleteLandmarksButton);
96  mDetailsAction = this->createAction(this,
97  QIcon(":/icons/open_icon_library/system-run-5.png"),
98  "Advanced", "Toggle advanced options",
99  SLOT(toggleDetailsSlot()),
100  landmarkButtonsLayout);
101  mVerticalLayout->addLayout(landmarkButtonsLayout);
102 
103  QHBoxLayout* landmarkAdvancedButtonsLayout = new QHBoxLayout;
104  landmarkAdvancedButtonsLayout = new QHBoxLayout;
105  landmarkAdvancedButtonsLayout->addWidget(mImportLandmarksFromPointMetricsButton);
106  mVerticalLayout->addLayout(landmarkAdvancedButtonsLayout);
107 
108  this->showOrHideDetails();
109 }
110 
112 {
113 }
114 
116 {
117  DataPtr data = mCurrentProperty->getData();
118 
119  mLandmarkListener->setLandmarkSource(data);
120  this->enableButtons();
121 
122  if (data && !mServices->registration()->getFixedData())
123  mServices->registration()->setFixedData(data);
124 
125  this->setModified();
126 }
127 
129 {
130  bool newShowAdvancedValue = !settings()->value(mLandmarksShowAdvancedSettingsString, "true").toBool();
131  settings()->setValue(mLandmarksShowAdvancedSettingsString, newShowAdvancedValue);
132  this->showOrHideDetails();
133 }
134 
135 void ImageLandmarksWidget::showOrHideDetails()
136 {
137  bool showAdvanced = settings()->value(mLandmarksShowAdvancedSettingsString).toBool();
138  mImportLandmarksFromPointMetricsButton->setVisible(showAdvanced);
139 }
140 
142 {
143  return mServices->view()->get3DReps(0, 0)->findFirst<PickerRep>();
144 }
145 
146 DataPtr ImageLandmarksWidget::getCurrentData() const
147 {
148  return mLandmarkListener->getLandmarkSource();
149 }
150 
152 {
154  if (!PickerRep)
155  {
156  reportError("Need a 3D view to set landmarks.");
157  return;
158  }
159 
160  DataPtr image = this->getCurrentData();
161  if (!image)
162  return;
163 
164  QString uid = mServices->patient()->addLandmark();
165  Vector3D pos_r = PickerRep->getPosition();
166  Vector3D pos_d = image->get_rMd().inv().coord(pos_r);
167  image->getLandmarks()->setLandmark(Landmark(uid, pos_d));
168 
169  this->activateLandmark(uid);
170 }
171 
172 
174 {
176  if (!PickerRep)
177  {
178  reportError("Need a 3D view to edit landmarks.");
179  return;
180  }
181 
182  DataPtr image = this->getCurrentData();
183  if (!image)
184  return;
185 
186  QString uid = mActiveLandmark;
187  Vector3D pos_r = PickerRep->getPosition();
188  Vector3D pos_d = image->get_rMd().inv().coord(pos_r);
189  image->getLandmarks()->setLandmark(Landmark(uid, pos_d));
190 
191  this->activateLandmark(this->getNextLandmark());
192 }
193 
195 {
196  DataPtr image = this->getCurrentData();
197  if (!image)
198  return;
199 
200  QString next = this->getNextLandmark();
201  image->getLandmarks()->removeLandmark(mActiveLandmark);
202  this->activateLandmark(next);
203 }
204 
206 {
207  DataPtr image = this->getCurrentData();
208  if (!image)
209  return;
210 
211  image->getLandmarks()->clear();
212  this->setModified();
213  mServices->patient()->deleteLandmarks();
214 }
215 
217 {
218  DataPtr image = this->getCurrentData();
219  if(!image)
220  return;
221 
222  std::map<QString, DataPtr> point_metrics = mServices->patient()->getChildren(image->getUid(), PointMetric::getTypeName());
223  std::map<QString, DataPtr>::iterator it = point_metrics.begin();
224 
225  //Make sure we have enough landmarks
226  int number_of_landmarks = mServices->patient()->getLandmarkProperties().size();
227  int number_of_metrics = point_metrics.size();
228  for(int i=number_of_landmarks; i<number_of_metrics; ++i)
229  {
230  QString uid = mServices->patient()->addLandmark();
231  }
232 
233  for(; it != point_metrics.end(); ++it)
234  {
235  PointMetricPtr point_metric = boost::static_pointer_cast<PointMetric>(it->second);
236  if(!point_metric)
237  continue;
238 
239  Vector3D pos_x = point_metric->getCoordinate();
240  //Transform3D d_M_x = mServices->spaceProvider()->get_toMfrom(CoordinateSystem::fromString(image->getSpace()), point_metric->getSpace());
241  //Vector3D pos_d = d_M_x.coord(pos_x);
242  QString point_metric_name = point_metric->getName();
243  image->getLandmarks()->setLandmark(Landmark(point_metric_name, pos_x));
244  this->activateLandmark(point_metric_name);
245  }
246 }
247 
248 void ImageLandmarksWidget::cellClickedSlot(int row, int column)
249 {
251  this->enableButtons();
252 }
253 
255 {
256  bool selected = !mLandmarkTableWidget->selectedItems().isEmpty();
257  bool loaded = this->getCurrentData() != 0;
258 
259  mEditLandmarkButton->setEnabled(selected);
260  mRemoveLandmarkButton->setEnabled(selected);
261  mDeleteLandmarksButton->setEnabled(loaded);
262  mAddLandmarkButton->setEnabled(loaded);
263  mImportLandmarksFromPointMetricsButton->setEnabled(loaded);
264 
265  DataPtr image = this->getCurrentData();
266  if (image)
267  {
268  mAddLandmarkButton->setToolTip(QString("Add landmark to image %1").arg(image->getName()));
269  mEditLandmarkButton->setToolTip(QString("Resample landmark in image %1").arg(image->getName()));
270  }
271 }
272 
273 void ImageLandmarksWidget::showEvent(QShowEvent* event)
274 {
275  mServices->view()->setRegistrationMode(rsIMAGE_REGISTRATED);
277 
278  if(!mUseRegistrationFixedPropertyInsteadOfActiveImage)
279  {
280  ActiveDataPtr activeData = mServices->patient()->getActiveData();
281  ImagePtr image = activeData->getActive<Image>();
282  if (image)
283  mCurrentProperty->setValue(image->getUid());
284  }
285 }
286 
287 void ImageLandmarksWidget::hideEvent(QHideEvent* event)
288 {
289  mServices->view()->setRegistrationMode(rsNOT_REGISTRATED);
291 
292 }
293 
295 {
297 
298  std::vector<Landmark> landmarks = this->getAllLandmarks();
299 
300  //update buttons
301  mRemoveLandmarkButton->setEnabled(!landmarks.empty() && !mActiveLandmark.isEmpty());
302  mEditLandmarkButton->setEnabled(!landmarks.empty() && !mActiveLandmark.isEmpty());
303  this->showOrHideDetails();
304 }
305 
307 {
308  DataPtr image = this->getCurrentData();
309  if (!image)
310  return LandmarkMap();
311 
312  return image->getLandmarks()->getLandmarks();
313 }
314 
319 {
320  DataPtr image = this->getCurrentData();
321  if (!image)
322  return Transform3D::Identity();
323  return image->get_rMd();
324 }
325 
327 {
328  DataPtr image = this->getCurrentData();
329  if (!image)
330  return;
331  image->getLandmarks()->setLandmark(Landmark(uid, p_target));
332 }
333 
335 {
336  DataPtr image = this->getCurrentData();
337  if (!image)
338  return "None";
339  return image->getName();
340 }
341 
342 
343 }//namespace cx
void deleteLandmarksButtonClickedSlot()
reacts when the Delete Landmarks button is clicked
virtual void showEvent(QShowEvent *event)
updates internal info before showing the widget
virtual void editLandmarkButtonClickedSlot()
reacts when the Edit Landmark button is clicked
QPushButton * mRemoveLandmarkButton
the Remove Landmark button
void reportError(QString msg)
Definition: cxLogger.cpp:71
void removeLandmarkButtonClickedSlot()
reacts when the Remove Landmark button is clicked
QPushButton * mEditLandmarkButton
the Edit Landmark button
QLabel * mAvarageAccuracyLabel
label showing the average accuracy
QPushButton * mAddLandmarkButton
the Add Landmark button
One landmark, or fiducial, coordinate.
Definition: cxLandmark.h:40
virtual Transform3D getTargetTransform() const
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
virtual void showEvent(QShowEvent *event)
updates internal info before showing the widget
static StringPropertySelectDataPtr New(PatientModelServicePtr patientModelService, QString typeRegexp=".*")
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
virtual void hideEvent(QHideEvent *event)
boost::shared_ptr< class ActiveData > ActiveDataPtr
Definition: cxColorWidget.h:21
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:66
Composite widget for string selection.
QVBoxLayout * mVerticalLayout
vertical layout is used
virtual void setTargetLandmark(QString uid, Vector3D p_target)
QAction * createAction(QObject *parent, QIcon iconName, QString text, QString tip, T slot, QLayout *layout=NULL, QToolButton *button=new QToolButton())
Definition: cxBaseWidget.h:129
virtual void hideEvent(QHideEvent *event)
static ActiveToolProxyPtr New(TrackingServicePtr trackingService)
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:58
boost::shared_ptr< class Data > DataPtr
boost::shared_ptr< class PickerRep > PickerRepPtr
ActiveToolProxyPtr mActiveToolProxy
Picking of points in an image.
Definition: cxPickerRep.h:49
void addLandmarkButtonClickedSlot()
reacts when the Add Landmark button is clicked
QPushButton * mImportLandmarksFromPointMetricsButton
the Import Landmarks button
A volumetric data set.
Definition: cxImage.h:45
virtual void cellClickedSlot(int row, int column)
when a landmark is selected from the table
Vector3D getCoordinate() const
boost::shared_ptr< class RegServices > RegServicesPtr
Definition: cxRegServices.h:20
virtual void prePaintEvent()
populates the table widget
rsNOT_REGISTRATED
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:21
virtual void prePaintEvent()
populates the table widget
void changed()
emit when the underlying data value is changed: The user interface will be updated.
virtual QString getTargetName() const
Data class that represents a single point.
Definition: cxPointMetric.h:42
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
std::map< QString, class Landmark > LandmarkMap
QString mActiveLandmark
uid of surrently selected landmark.
static QString getTypeName()
Definition: cxPointMetric.h:58
std::vector< Landmark > getAllLandmarks() const
get all the landmarks from the image and the datamanager
SelectDataStringPropertyBasePtr mCurrentProperty
QPushButton * mDeleteLandmarksButton
the Delete Landmarks button
virtual LandmarkMap getTargetLandmarks() const
virtual void cellClickedSlot(int row, int column)
when a landmark is selected from the table
rsIMAGE_REGISTRATED
QTableWidget * mLandmarkTableWidget
the table widget presenting the landmarks
Namespace for all CustusX production code.
boost::shared_ptr< class PointMetric > PointMetricPtr