CustusX  15.4.0-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  if (row < 0 || column < 0)
76  return;
77 
79  reportDebug("mLandmarkTableWidget is null");
80 
81  mActiveLandmark = mLandmarkTableWidget->item(row, column)->data(Qt::UserRole).toString();
82 
83 
84  LandmarkMap targetData = this->getTargetLandmarks();
85  if (targetData.count(mActiveLandmark))
86  {
87  Vector3D p_d = targetData[mActiveLandmark].getCoord();
88  Vector3D p_r = this->getTargetTransform().coord(p_d);
89  Vector3D p_pr = mServices.patientModelService->get_rMpr().coord(p_r);
90  this->setManualToolPosition(p_r);
91  }
92 
93 }
94 
96 {
97  Transform3D rMpr = mServices.patientModelService->get_rMpr();
98  Vector3D p_pr = rMpr.inv().coord(p_r);
99 
100  // set the picked point as offset tip
101  ToolPtr tool = mServices.trackingService->getManualTool();
102  Vector3D offset = tool->get_prMt().vector(Vector3D(0, 0, tool->getTooltipOffset()));
103  p_pr -= offset;
104  p_r = rMpr.coord(p_pr);
105 
106  // TODO set center here will not do: must handle
107  mServices.patientModelService->setCenter(p_r);
108  Vector3D p0_pr = tool->get_prMt().coord(Vector3D(0, 0, 0));
109  tool->set_prMt(createTransformTranslate(p_pr - p0_pr) * tool->get_prMt());
110 }
111 
113 {
114  QWidget::showEvent(event);
117 
118 // mManager->restart();
119  mServices.registrationService->setLastRegistrationTime(QDateTime::currentDateTime());
120  this->setModified();
121 }
122 
124 {
125  QWidget::hideEvent(event);
128 }
129 
131 {
132  mLandmarkTableWidget->blockSignals(true);
133  mLandmarkTableWidget->clear();
134 
135  QString fixedName;
136  DataPtr fixedData = boost::dynamic_pointer_cast<Data>(mServices.registrationService->getFixedData());
137  if (fixedData)
138  fixedName = fixedData->getName();
139 
140  std::vector<Landmark> landmarks = this->getAllLandmarks();
141  LandmarkMap targetData = this->getTargetLandmarks();
142  Transform3D rMtarget = this->getTargetTransform();
143 
144  //ready the table widget
145  mLandmarkTableWidget->setRowCount((int)landmarks.size());
146  mLandmarkTableWidget->setColumnCount(4);
147  QStringList headerItems(QStringList() << "Name" << "Status" << "Coordinates" << "Accuracy (mm)");
148  mLandmarkTableWidget->setHorizontalHeaderLabels(headerItems);
149  mLandmarkTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
150  mLandmarkTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
151 
152  for (unsigned i = 0; i < landmarks.size(); ++i)
153  {
154  std::vector<QTableWidgetItem*> items(4); // name, status, coordinates, accuracy
155 
156  LandmarkProperty prop = mServices.patientModelService->getLandmarkProperties()[landmarks[i].getUid()];
157  Vector3D coord = landmarks[i].getCoord();
158  coord = rMtarget.coord(coord); // display coordinates in space r (in principle, this means all coords should be equal)
159 
160  items[0] = new QTableWidgetItem(qstring_cast(prop.getName()));
161  items[0]->setToolTip(QString("Landmark name. Double-click to rename."));
162 
163  items[1] = new QTableWidgetItem;
164 
165  if (prop.getActive())
166  items[1]->setCheckState(Qt::Checked);
167  else
168  items[1]->setCheckState(Qt::Unchecked);
169  items[1]->setToolTip(QString("Check to use landmark in current registration."));
170 
171  QString coordText = "Not sampled";
172  if (targetData.count(prop.getUid()))
173  {
174  int width = 5;
175  int prec = 1;
176  coordText = tr("(%1, %2, %3)").arg(coord[0], width, 'f', prec).arg(coord[1], width, 'f', prec).arg(
177  coord[2], width, 'f', prec);
178  }
179 
180  items[2] = new QTableWidgetItem(coordText);
181  items[2]->setToolTip(QString("Landmark coordinates of target [%1] in reference space.").arg(this->getTargetName()));
182 
183  items[3] = new QTableWidgetItem(tr("%1").arg(this->getAccuracy(landmarks[i].getUid())));
184  items[3]->setToolTip(QString("Distance from target [%1] to fixed [%2].").arg(this->getTargetName()).arg(fixedName));
185 
186  for (unsigned j = 0; j < items.size(); ++j)
187  {
188  items[j]->setData(Qt::UserRole, qstring_cast(prop.getUid()));
189  mLandmarkTableWidget->setItem(i, j, items[j]);
190  }
191 
192  //highlight selected row
193  if (prop.getUid() == mActiveLandmark)
194  {
195  mLandmarkTableWidget->setCurrentItem(items[2]);
196  }
197  }
198 
200  mLandmarkTableWidget->blockSignals(false);
201 }
202 
204 {
205  mActiveLandmark = uid;
206  this->setModified();
207 }
208 
213 {
214  std::vector<Landmark> lm = this->getAllLandmarks();
215 
216  for (int i=0; i<lm.size()-1; ++i)
217  {
218  if (lm[i].getUid()==mActiveLandmark)
219  {
220  return lm[i+1].getUid();
221  }
222  }
223 
224  return "";
225 }
226 
227 std::vector<Landmark> LandmarkRegistrationWidget::getAllLandmarks() const
228 {
229  std::vector<Landmark> retval;
230  LandmarkMap targetData = this->getTargetLandmarks();
231  std::map<QString, LandmarkProperty> dataData = mServices.patientModelService->getLandmarkProperties();
232  std::map<QString, LandmarkProperty>::iterator iter;
233 
234  for (iter = dataData.begin(); iter != dataData.end(); ++iter)
235  {
236  if (targetData.count(iter->first))
237  retval.push_back(targetData[iter->first]);
238  else
239  retval.push_back(Landmark(iter->first));
240  }
241 
242  std::sort(retval.begin(), retval.end());
243 
244  return retval;
245 }
246 
248 {
249  QTableWidgetItem* item = mLandmarkTableWidget->item(row, column);
250  QString uid = item->data(Qt::UserRole).toString();
251 
252  if (column == 0)
253  {
254  QString name = item->text();
255  mServices.patientModelService->setLandmarkName(uid, name);
256  }
257  if (column == 1)
258  {
259  Qt::CheckState state = item->checkState();
260  mServices.patientModelService->setLandmarkActive(uid, state == Qt::Checked);
261  this->performRegistration(); // automatic when changing active state (Mantis #0000674)s
262  }
263  if (column == 2)
264  {
265  QString val = item->text();
266  // remove formatting stuff:
267  val = val.replace('(', " ");
268  val = val.replace(')', " ");
269  val = val.replace(',', " ");
270 
271  Transform3D rMtarget = this->getTargetTransform();
272 
273  Vector3D p_r = Vector3D::fromString(val);
274  Vector3D p_target = rMtarget.inv().coord(p_r);
275  this->setTargetLandmark(uid, p_target);
276  }
277 }
278 
280 {
281 // - This has too many side effects when we use the landmarks for several different registrations,
282 // i.e. image2image, patient, fast... Rather register explicitly, and add it to the buttons where you
283 // want the automation, such as in the patient reg sampler. (Mantis #0000674)
284 // this->performRegistration();
285  this->setModified();
286 }
287 
289 {
290  QString fixedName;
291  DataPtr fixedData = boost::dynamic_pointer_cast<Data>(mServices.registrationService->getFixedData());
292  if (fixedData)
293  fixedName = fixedData->getName();
294 
295  if(this->isAverageAccuracyValid())
296  {
297  mAvarageAccuracyLabel->setText(tr("Mean accuracy %1 mm").arg(this->getAverageAccuracy(), 0, 'f', 2));
298  mAvarageAccuracyLabel->setToolTip(QString("Average landmark accuracy from target [%1] to fixed [%2].").arg(this->getTargetName()).arg(fixedName));
299  }
300  else
301  {
302  mAvarageAccuracyLabel->setText(" ");
303  mAvarageAccuracyLabel->setToolTip("");
304  }
305 }
306 
307 bool LandmarkRegistrationWidget::isAverageAccuracyValid()
308 {
309  int numActiveLandmarks = 0;
310  this->getAverageAccuracy(numActiveLandmarks);
311  if(numActiveLandmarks < 3)
312  return false;
313  return true;
314 }
315 
317 {
318  int numActiveLandmarks = 0;
319  return this->getAverageAccuracy(numActiveLandmarks);
320 }
321 
322 double LandmarkRegistrationWidget::getAverageAccuracy(int& numActiveLandmarks)
323 {
324  std::map<QString, LandmarkProperty> props = mServices.patientModelService->getLandmarkProperties();
325 
326  double sum = 0;
327  numActiveLandmarks = 0;
328  std::map<QString, LandmarkProperty>::iterator it = props.begin();
329  for (; it != props.end(); ++it)
330  {
331  if (!it->second.getActive()) //we don't want to take into account not active landmarks
332  continue;
333  QString uid = it->first;
334  double val = this->getAccuracy(uid);
335  if (!similar(val, 1000.0))
336  {
337  sum = sum + val;
338  numActiveLandmarks++;
339  }
340  }
341  if (numActiveLandmarks == 0)
342  return 1000;
343  return sum / numActiveLandmarks;
344 }
345 
347 {
348  DataPtr fixedData = mServices.registrationService->getFixedData();
349  if (!fixedData)
350  return 1000.0;
351 
352  Landmark masterLandmark = fixedData->getLandmarks()->getLandmarks()[uid];
353  Landmark targetLandmark = this->getTargetLandmarks()[uid];
354  if (masterLandmark.getUid().isEmpty() || targetLandmark.getUid().isEmpty())
355  return 1000.0;
356 
357  Vector3D p_master_master = masterLandmark.getCoord();
358  Vector3D p_target_target = targetLandmark.getCoord();
359  Transform3D rMmaster = fixedData->get_rMd();
360  Transform3D rMtarget = this->getTargetTransform();
361 
362  Vector3D p_target_r = rMtarget.coord(p_target_target);
363  Vector3D p_master_r = rMmaster.coord(p_master_master);
364 
365  return (p_target_r - p_master_r).length();
366 }
367 
368 }//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
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 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