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