CustusX  15.3.4-beta
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxLandmarkRegistrationWidget.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 
34 
35 #include <sstream>
36 #include <QVBoxLayout>
37 #include <QPushButton>
38 #include <QTableWidget>
39 #include <QTableWidgetItem>
40 #include <QHeaderView>
41 #include <QLabel>
42 #include <QSlider>
43 #include <vtkDoubleArray.h>
44 #include <vtkImageData.h>
45 
46 #include "cxTypeConversions.h"
47 #include "cxManualTool.h"
48 #include "cxPatientModelService.h"
49 #include "cxRegistrationService.h"
50 #include"cxData.h"
51 #include "cxLogger.h"
52 #include "cxLandmark.h"
53 #include "cxTrackingService.h"
54 
55 namespace cx
56 {
57 LandmarkRegistrationWidget::LandmarkRegistrationWidget(RegServices services, QWidget* parent,
58  QString objectName, QString windowTitle) :
59  RegistrationBaseWidget(services, parent, objectName, windowTitle), mVerticalLayout(new QVBoxLayout(this)),
60  mLandmarkTableWidget(new QTableWidget(this)), mAvarageAccuracyLabel(new QLabel(QString(" "), this))
61 {
62  //table widget
63  connect(mLandmarkTableWidget, SIGNAL(cellClicked(int, int)), this, SLOT(cellClickedSlot(int, int)));
64  connect(mLandmarkTableWidget, SIGNAL(cellChanged(int,int)), this, SLOT(cellChangedSlot(int,int)));
65 
66  this->setLayout(mVerticalLayout);
67 }
68 
70 {
71 }
72 
74 {
75  return "<html>"
76  "<h3>Registration.</h3>"
77  "<p>Interface for registrating.</p>"
78  "<p><i></i></p>"
79  "</html>";
80 }
81 
83 {
84  if (row < 0 || column < 0)
85  return;
86 
88  reportDebug("mLandmarkTableWidget is null");
89 
90  mActiveLandmark = mLandmarkTableWidget->item(row, column)->data(Qt::UserRole).toString();
91 
92 
93  LandmarkMap targetData = this->getTargetLandmarks();
94  if (targetData.count(mActiveLandmark))
95  {
96  Vector3D p_d = targetData[mActiveLandmark].getCoord();
97  Vector3D p_r = this->getTargetTransform().coord(p_d);
98  Vector3D p_pr = mServices.patientModelService->get_rMpr().coord(p_r);
99  this->setManualToolPosition(p_r);
100  }
101 
102 }
103 
105 {
106  Transform3D rMpr = mServices.patientModelService->get_rMpr();
107  Vector3D p_pr = rMpr.inv().coord(p_r);
108 
109  // set the picked point as offset tip
110  ToolPtr tool = mServices.trackingService->getManualTool();
111  Vector3D offset = tool->get_prMt().vector(Vector3D(0, 0, tool->getTooltipOffset()));
112  p_pr -= offset;
113  p_r = rMpr.coord(p_pr);
114 
115  // TODO set center here will not do: must handle
116  mServices.patientModelService->setCenter(p_r);
117  Vector3D p0_pr = tool->get_prMt().coord(Vector3D(0, 0, 0));
118  tool->set_prMt(createTransformTranslate(p_pr - p0_pr) * tool->get_prMt());
119 }
120 
122 {
123  QWidget::showEvent(event);
126 
127 // mManager->restart();
128  mServices.registrationService->setLastRegistrationTime(QDateTime::currentDateTime());
129  this->setModified();
130 }
131 
133 {
134  QWidget::hideEvent(event);
137 }
138 
140 {
141  mLandmarkTableWidget->blockSignals(true);
142  mLandmarkTableWidget->clear();
143 
144  QString fixedName;
145  DataPtr fixedData = boost::dynamic_pointer_cast<Data>(mServices.registrationService->getFixedData());
146  if (fixedData)
147  fixedName = fixedData->getName();
148 
149  std::vector<Landmark> landmarks = this->getAllLandmarks();
150  LandmarkMap targetData = this->getTargetLandmarks();
151  Transform3D rMtarget = this->getTargetTransform();
152 
153  //ready the table widget
154  mLandmarkTableWidget->setRowCount((int)landmarks.size());
155  mLandmarkTableWidget->setColumnCount(4);
156  QStringList headerItems(QStringList() << "Name" << "Status" << "Coordinates" << "Accuracy (mm)");
157  mLandmarkTableWidget->setHorizontalHeaderLabels(headerItems);
158  mLandmarkTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
159  mLandmarkTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
160 
161  for (unsigned i = 0; i < landmarks.size(); ++i)
162  {
163  std::vector<QTableWidgetItem*> items(4); // name, status, coordinates, accuracy
164 
165  LandmarkProperty prop = mServices.patientModelService->getLandmarkProperties()[landmarks[i].getUid()];
166  Vector3D coord = landmarks[i].getCoord();
167  coord = rMtarget.coord(coord); // display coordinates in space r (in principle, this means all coords should be equal)
168 
169  items[0] = new QTableWidgetItem(qstring_cast(prop.getName()));
170  items[0]->setToolTip(QString("Landmark name. Double-click to rename."));
171 
172  items[1] = new QTableWidgetItem;
173 
174  if (prop.getActive())
175  items[1]->setCheckState(Qt::Checked);
176  else
177  items[1]->setCheckState(Qt::Unchecked);
178  items[1]->setToolTip(QString("Check to use landmark in current registration."));
179 
180  QString coordText = "Not sampled";
181  if (targetData.count(prop.getUid()))
182  {
183  int width = 5;
184  int prec = 1;
185  coordText = tr("(%1, %2, %3)").arg(coord[0], width, 'f', prec).arg(coord[1], width, 'f', prec).arg(
186  coord[2], width, 'f', prec);
187  }
188 
189  items[2] = new QTableWidgetItem(coordText);
190  items[2]->setToolTip(QString("Landmark coordinates of target [%1] in reference space.").arg(this->getTargetName()));
191 
192  items[3] = new QTableWidgetItem(tr("%1").arg(this->getAccuracy(landmarks[i].getUid())));
193  items[3]->setToolTip(QString("Distance from target [%1] to fixed [%2].").arg(this->getTargetName()).arg(fixedName));
194 
195  for (unsigned j = 0; j < items.size(); ++j)
196  {
197  items[j]->setData(Qt::UserRole, qstring_cast(prop.getUid()));
198  mLandmarkTableWidget->setItem(i, j, items[j]);
199  }
200 
201  //highlight selected row
202  if (prop.getUid() == mActiveLandmark)
203  {
204  mLandmarkTableWidget->setCurrentItem(items[2]);
205  }
206  }
207 
209  mLandmarkTableWidget->blockSignals(false);
210 }
211 
213 {
214  mActiveLandmark = uid;
215  this->setModified();
216 }
217 
222 {
223  std::vector<Landmark> lm = this->getAllLandmarks();
224 
225  for (int i=0; i<lm.size()-1; ++i)
226  {
227  if (lm[i].getUid()==mActiveLandmark)
228  {
229  return lm[i+1].getUid();
230  }
231  }
232 
233  return "";
234 }
235 
236 std::vector<Landmark> LandmarkRegistrationWidget::getAllLandmarks() const
237 {
238  std::vector<Landmark> retval;
239  LandmarkMap targetData = this->getTargetLandmarks();
240  std::map<QString, LandmarkProperty> dataData = mServices.patientModelService->getLandmarkProperties();
241  std::map<QString, LandmarkProperty>::iterator iter;
242 
243  for (iter = dataData.begin(); iter != dataData.end(); ++iter)
244  {
245  if (targetData.count(iter->first))
246  retval.push_back(targetData[iter->first]);
247  else
248  retval.push_back(Landmark(iter->first));
249  }
250 
251  std::sort(retval.begin(), retval.end());
252 
253  return retval;
254 }
255 
257 {
258  QTableWidgetItem* item = mLandmarkTableWidget->item(row, column);
259  QString uid = item->data(Qt::UserRole).toString();
260 
261  if (column == 0)
262  {
263  QString name = item->text();
264  mServices.patientModelService->setLandmarkName(uid, name);
265  }
266  if (column == 1)
267  {
268  Qt::CheckState state = item->checkState();
269  mServices.patientModelService->setLandmarkActive(uid, state == Qt::Checked);
270  this->performRegistration(); // automatic when changing active state (Mantis #0000674)s
271  }
272  if (column == 2)
273  {
274  QString val = item->text();
275  // remove formatting stuff:
276  val = val.replace('(', " ");
277  val = val.replace(')', " ");
278  val = val.replace(',', " ");
279 
280  Transform3D rMtarget = this->getTargetTransform();
281 
282  Vector3D p_r = Vector3D::fromString(val);
283  Vector3D p_target = rMtarget.inv().coord(p_r);
284  this->setTargetLandmark(uid, p_target);
285  }
286 }
287 
289 {
290 // - This has too many side effects when we use the landmarks for several different registrations,
291 // i.e. image2image, patient, fast... Rather register explicitly, and add it to the buttons where you
292 // want the automation, such as in the patient reg sampler. (Mantis #0000674)
293 // this->performRegistration();
294  this->setModified();
295 }
296 
298 {
299  QString fixedName;
300  DataPtr fixedData = boost::dynamic_pointer_cast<Data>(mServices.registrationService->getFixedData());
301  if (fixedData)
302  fixedName = fixedData->getName();
303 
304  if(this->isAverageAccuracyValid())
305  {
306  mAvarageAccuracyLabel->setText(tr("Mean accuracy %1 mm").arg(this->getAverageAccuracy(), 0, 'f', 2));
307  mAvarageAccuracyLabel->setToolTip(QString("Average landmark accuracy from target [%1] to fixed [%2].").arg(this->getTargetName()).arg(fixedName));
308  }
309  else
310  {
311  mAvarageAccuracyLabel->setText(" ");
312  mAvarageAccuracyLabel->setToolTip("");
313  }
314 }
315 
316 bool LandmarkRegistrationWidget::isAverageAccuracyValid()
317 {
318  int numActiveLandmarks = 0;
319  this->getAverageAccuracy(numActiveLandmarks);
320  if(numActiveLandmarks < 3)
321  return false;
322  return true;
323 }
324 
326 {
327  int numActiveLandmarks = 0;
328  return this->getAverageAccuracy(numActiveLandmarks);
329 }
330 
331 double LandmarkRegistrationWidget::getAverageAccuracy(int& numActiveLandmarks)
332 {
333  std::map<QString, LandmarkProperty> props = mServices.patientModelService->getLandmarkProperties();
334 
335  double sum = 0;
336  numActiveLandmarks = 0;
337  std::map<QString, LandmarkProperty>::iterator it = props.begin();
338  for (; it != props.end(); ++it)
339  {
340  if (!it->second.getActive()) //we don't want to take into account not active landmarks
341  continue;
342  QString uid = it->first;
343  double val = this->getAccuracy(uid);
344  if (!similar(val, 1000.0))
345  {
346  sum = sum + val;
347  numActiveLandmarks++;
348  }
349  }
350  if (numActiveLandmarks == 0)
351  return 1000;
352  return sum / numActiveLandmarks;
353 }
354 
356 {
357  DataPtr fixedData = mServices.registrationService->getFixedData();
358  if (!fixedData)
359  return 1000.0;
360 
361  Landmark masterLandmark = fixedData->getLandmarks()->getLandmarks()[uid];
362  Landmark targetLandmark = this->getTargetLandmarks()[uid];
363  if (masterLandmark.getUid().isEmpty() || targetLandmark.getUid().isEmpty())
364  return 1000.0;
365 
366  Vector3D p_master_master = masterLandmark.getCoord();
367  Vector3D p_target_target = targetLandmark.getCoord();
368  Transform3D rMmaster = fixedData->get_rMd();
369  Transform3D rMtarget = this->getTargetTransform();
370 
371  Vector3D p_target_r = rMtarget.coord(p_target_target);
372  Vector3D p_master_r = rMmaster.coord(p_master_master);
373 
374  return (p_target_r - p_master_r).length();
375 }
376 
377 }//namespace cx
QString qstring_cast(const T &val)
QString getUid() const
Definition: cxLandmark.cpp:54
virtual void performRegistration()=0
virtual void showEvent(QShowEvent *event)
updates internal info before showing the widget
QLabel * mAvarageAccuracyLabel
label showing the average accuracy
void landmarkPropertiesChanged()
emitted when global info about a landmark changed
One landmark, or fiducial, coordinate.
Definition: cxLandmark.h:61
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
QString getUid() const
Definition: cxLandmark.cpp:196
QVBoxLayout * mVerticalLayout
vertical layout is used
bool similar(const DoubleBoundingBox3D &a, const DoubleBoundingBox3D &b, double tol)
virtual void hideEvent(QHideEvent *event)
boost::shared_ptr< class Data > DataPtr
virtual Transform3D getTargetTransform() const =0
Return transform from target space to reference space.
virtual QString getName() const
Definition: cxData.cpp:83
virtual void cellClickedSlot(int row, int column)
when a landmark i selected from the table
Vector3d coord(const Vector3d &v) const
transform a coordinate [x,y,z,1].
Transform3D createTransformTranslate(const Vector3D &translation)
virtual void prePaintEvent()
populates the table widget
Vector3D getCoord() const
Definition: cxLandmark.cpp:59
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
virtual LandmarkMap getTargetLandmarks() const =0
Superclass for all data objects.
Definition: cxData.h:69
std::map< QString, class Landmark > LandmarkMap
QString mActiveLandmark
uid of surrently selected landmark.
TrackingServicePtr trackingService
QString getName() const
Definition: cxLandmark.cpp:206
std::vector< Landmark > getAllLandmarks() const
get all the landmarks from the image and the datamanager
virtual QString defaultWhatsThis() const
Returns a short description of what this widget will do for you.
virtual void setTargetLandmark(QString uid, Vector3D p_target)=0
PatientModelServicePtr patientModelService
virtual QString getTargetName() const =0
bool getActive() const
Definition: cxLandmark.cpp:201
void reportDebug(QString msg)
Definition: cxLogger.cpp:89
RegistrationServicePtr registrationService
Definition: cxRegServices.h:60
QTableWidget * mLandmarkTableWidget
the table widget presenting the landmarks
void cellChangedSlot(int row, int column)
reacts when the user types in a (landmark) name
boost::shared_ptr< class Tool > ToolPtr