CustusX  22.04-rc5
An IGT application
cxImportDataDialog.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 "cxImportDataDialog.h"
13 
14 #include <cmath>
15 #include <QFileDialog>
16 #include <QPushButton>
17 #include <QVBoxLayout>
18 #include <QLabel>
19 #include <Qt>
20 #include <QCheckBox>
21 #include <QTimer>
22 #include <vtkImageData.h>
24 #include "cxLogger.h"
25 #include "cxTypeConversions.h"
26 #include "cxData.h"
28 #include "cxImageAlgorithms.h"
29 #include "cxImage.h"
30 #include "cxVolumeHelpers.h"
31 #include "cxImageTF3D.h"
32 #include "cxImageLUT2D.h"
33 #include "cxPatientModelService.h"
34 #include "cxMesh.h"
35 #include "cxViewService.h"
36 
37 namespace cx
38 {
39 
40 ImportDataDialog::ImportDataDialog(PatientModelServicePtr patientModelService, ViewServicePtr viewService, QString filename, QWidget* parent) :
41  QDialog(parent),
42  mFilename(filename),
43  mPatientModelService(patientModelService),
44  mViewService(viewService)
45 {
46  this->setAttribute(Qt::WA_DeleteOnClose);
47 
48  QVBoxLayout* layout = new QVBoxLayout(this);
49  this->setWindowTitle("Set properties for imported data");
50 
51  mUidLabel = new QLabel("Data uid: ");
52  mNameLabel = new QLabel("Data name: ");
53 
54  layout->addWidget(mUidLabel);
55  layout->addWidget(mNameLabel);
56 
57  mModalityAdapter = StringPropertyDataModality::New(mPatientModelService);
58  mModalityCombo = new LabeledComboBoxWidget(this, mModalityAdapter);
59  layout->addWidget(mModalityCombo);
60 
61  mImageTypeAdapter = StringPropertyImageType::New(mPatientModelService);
62  mImageTypeCombo = new LabeledComboBoxWidget(this, mImageTypeAdapter);
63  layout->addWidget(mImageTypeCombo);
64 
65  mParentFrameAdapter = StringPropertySetParentFrame::New(mPatientModelService);
66  mParentFrameCombo = new LabeledComboBoxWidget(this, mParentFrameAdapter);
67  layout->addWidget(mParentFrameCombo);
68 
69  mNiftiFormatCheckBox = new QCheckBox("Convert from RAS to LPS coordinates", this);
70  mNiftiFormatCheckBox->setToolTip(""
71  "Use RAS (X=Left->Right Y=Posterior->Anterior Z=Inferior->Superior), as in ITK-Snap.\n"
72  "This is different from DICOM/CustusX, which uses LPS (left-posterior-superior).");
73  mNiftiFormatCheckBox->setChecked(false);
74  mNiftiFormatCheckBox->setEnabled(true);
75  mTransformFromParentFrameCheckBox = new QCheckBox("Import transform from Parent", this);
76  mTransformFromParentFrameCheckBox->setToolTip("Replace data transform with that of the parent data.");
77  mTransformFromParentFrameCheckBox->setChecked(false);
78 
79  mConvertToUnsignedCheckBox = new QCheckBox("Convert to unsigned", this);
80  mConvertToUnsignedCheckBox->setToolTip("Convert imported data set to unsigned values.");
81  mConvertToUnsignedCheckBox->setChecked(false);
82 
83  layout->addWidget(mNiftiFormatCheckBox);
84  layout->addWidget(mTransformFromParentFrameCheckBox);
85  layout->addWidget(mConvertToUnsignedCheckBox);
86 
87  connect(mParentFrameAdapter.get(), &Property::changed, this, &ImportDataDialog::updateImportTransformButton);
88  this->updateImportTransformButton();
89 
90  mErrorLabel = new QLabel();
91  layout->addWidget(mErrorLabel);
92 
93  QHBoxLayout* buttons = new QHBoxLayout;
94  layout->addLayout(buttons);
95  mOkButton = new QPushButton("OK", this);
96  buttons->addStretch();
97  buttons->addWidget(mOkButton);
98  connect(mOkButton, &QPushButton::clicked, this, &QDialog::accept);
99  connect(this, &QDialog::accepted, this, &ImportDataDialog::acceptedSlot);
100  connect(this, &QDialog::rejected, this, &ImportDataDialog::finishedSlot);
101  mOkButton->setDefault(true);
102  mOkButton->setFocus();
103 
104  report("Importing data...");
105 }
106 
108 {
109 }
110 
111 void ImportDataDialog::showEvent(QShowEvent* event)
112 {
113  // the import operation takes up to a few seconds. Call it AFTER the dialog is up and running its own message loop,
114  // this avoids all problems related to modal vs right-click in the main window.
115  QTimer::singleShot(0, this, SLOT(importDataSlot()));
116 }
117 
118 void ImportDataDialog::importDataSlot()
119 {
120  QString infoText;
121  mData = mPatientModelService->importData(mFilename, infoText);
122  if (!infoText.isEmpty())
123  {
124  infoText += "<font color=red><br>If these warnings are not expected the import have probably failed.</font>";
125  if(infoText.contains("File already exists", Qt::CaseInsensitive))
126  infoText += "<font color=red><br>Importing two different volumes with the same name will lead to undesired effects.</font>";
127  mErrorLabel->setText(infoText);
128  }
129 
130  if (!mData)
131  {
132  mUidLabel->setText(mFilename);
133  mNameLabel->setText("Import failed");
134  mOkButton->setText("Exit");
135  return;
136  }
137 
138  mUidLabel->setText("Data uid: " + qstring_cast(mData->getUid()));
139  mNameLabel->setText("Data name: " + qstring_cast(mData->getName()));
140 
141  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
142  mModalityAdapter->setData(image);
143  mModalityCombo->setEnabled(image!=0);
144  mImageTypeAdapter->setData(image);
145  mImageTypeCombo->setEnabled(image!=0);
146 
147  this->setInitialGuessForParentFrame();
148  mParentFrameAdapter->setData(mData);
149  mParentFrameCombo->setEnabled(mPatientModelService->getDatas().size()>1);
150 
151  //NIfTI files are assumed to be in the RAS (right-anterior-superior) coordinate system,
152  //CX requires LPS (left-posterior-superio)
153  if(mFilename.endsWith(".nii", Qt::CaseInsensitive))
154  mNiftiFormatCheckBox->setChecked(true);
155 
156  mConvertToUnsignedCheckBox->setEnabled(false);
157  if (image && image->getBaseVtkImageData())
158  {
159  mConvertToUnsignedCheckBox->setEnabled( (image!=0) && (image->getBaseVtkImageData()->GetScalarTypeMin()<0) );
160  }
161 }
162 
163 
167 void ImportDataDialog::setInitialGuessForParentFrame()
168 {
169  if(!mData)
170  return;
171 
172  QString base = qstring_cast(mData->getName()).split(".")[0];
173 
174  std::map<QString, DataPtr> all = mPatientModelService->getDatas();
175  for (std::map<QString, DataPtr>::iterator iter=all.begin(); iter!=all.end(); ++iter)
176  {
177  if (iter->second==mData)
178  continue;
179  QString current = qstring_cast(iter->second->getName()).split(".")[0];
180  if (base.indexOf(current)>=0)
181  {
182  mData->get_rMd_History()->setParentSpace(iter->first);
183  break;
184  }
185  }
186 
187 }
188 
189 void ImportDataDialog::updateImportTransformButton()
190 {
191  DataPtr parent = mPatientModelService->getData(mParentFrameAdapter->getValue());
192  bool enabled = bool(parent);
193  mTransformFromParentFrameCheckBox->setEnabled(enabled);
194 }
195 
196 void ImportDataDialog::acceptedSlot()
197 {
198  this->importParentTransform();
199  this->convertFromNifti1Coordinates();
200  this->convertToUnsigned();
201 
202  mPatientModelService->autoSave();
203  mViewService->autoShowData(mData);
204  this->finishedSlot();
205 }
206 
207 void ImportDataDialog::finishedSlot()
208 {
209 }
210 
218 void ImportDataDialog::convertFromNifti1Coordinates()
219 {
220  if (!mNiftiFormatCheckBox->isChecked())
221  return;
222  if(!mData)
223  return;
224  Transform3D sMd = mData->get_rMd();
226 // rMd = createTransformRotateZ(M_PI) * rMd;
227  Transform3D rMd = sMr.inv() * sMd;
228  mData->get_rMd_History()->setRegistration(rMd);
229  report("Nifti import: Converted data " + mData->getName() + " from LPS to RAS coordinates.");
230 }
231 
235 void ImportDataDialog::importParentTransform()
236 {
237  if (!mTransformFromParentFrameCheckBox->isChecked())
238  return;
239  if(!mData)
240  return;
241  DataPtr parent = mPatientModelService->getData(mData->getParentSpace());
242  if (!parent)
243  return;
244  mData->get_rMd_History()->setRegistration(parent->get_rMd());
245  report("Assigned rMd from data [" + parent->getName() + "] to data [" + mData->getName() + "]");
246 }
247 
248 void ImportDataDialog::convertToUnsigned()
249 {
250  if (!mConvertToUnsignedCheckBox->isChecked())
251  return;
252 
253  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
254  if (!image)
255  return;
256 
257  ImagePtr converted = convertImageToUnsigned(mPatientModelService, image);
258 
259  image->setVtkImageData(converted->getBaseVtkImageData());
260 
261  ImageTF3DPtr TF3D = converted->getTransferFunctions3D()->createCopy();
262  ImageLUT2DPtr LUT2D = converted->getLookupTable2D()->createCopy();
263  image->setLookupTable2D(LUT2D);
264  image->setTransferFunctions3D(TF3D);
265  mPatientModelService->insertData(image);
266 }
267 
268 
269 }//namespace cx
QString qstring_cast(const T &val)
pcsRAS
Right-Anterior-Superior, used by Slicer3D, ITK-Snap, nifti, MINC.
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
cxResource_EXPORT Transform3D createTransformFromReferenceToExternal(PATIENT_COORDINATE_SYSTEM external)
static StringPropertyDataModalityPtr New(PatientModelServicePtr patientModelService)
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
boost::shared_ptr< class ViewService > ViewServicePtr
ImportDataDialog(PatientModelServicePtr patientModelService, ViewServicePtr viewService, QString filename, QWidget *parent=NULL)
Composite widget for string selection.
ImagePtr convertImageToUnsigned(PatientModelServicePtr dataManager, ImagePtr image, vtkImageDataPtr suggestedConvertedVolume, bool verbose)
boost::shared_ptr< class Data > DataPtr
static StringPropertyImageTypePtr New(PatientModelServicePtr patientModelService)
boost::shared_ptr< class ImageLUT2D > ImageLUT2DPtr
void showEvent(QShowEvent *event)
A volumetric data set.
Definition: cxImage.h:45
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
static StringPropertySetParentFramePtr New(PatientModelServicePtr patientModelService)
void changed()
emit when the underlying data value is changed: The user interface will be updated.
void report(QString msg)
Definition: cxLogger.cpp:69
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr
Namespace for all CustusX production code.