CustusX  16.5
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
59 //TODO: remove
60 #include "cxLegacySingletons.h"
61 
62 namespace cx
63 {
64 
65 ImportDataDialog::ImportDataDialog(PatientModelServicePtr patientModelService, QString filename, QWidget* parent) :
66  QDialog(parent),
67  mFilename(filename),
68  mPatientModelService(patientModelService)
69 {
70  this->setAttribute(Qt::WA_DeleteOnClose);
71 
72  QVBoxLayout* layout = new QVBoxLayout(this);
73  this->setWindowTitle("Set properties for imported data");
74 
75  mUidLabel = new QLabel("Data uid: ");
76  mNameLabel = new QLabel("Data name: ");
77 
78  layout->addWidget(mUidLabel);
79  layout->addWidget(mNameLabel);
80 
81  mModalityAdapter = StringPropertyDataModality::New(mPatientModelService);
82  mModalityCombo = new LabeledComboBoxWidget(this, mModalityAdapter);
83  layout->addWidget(mModalityCombo);
84 
85  mImageTypeAdapter = StringPropertyImageType::New(mPatientModelService);
86  mImageTypeCombo = new LabeledComboBoxWidget(this, mImageTypeAdapter);
87  layout->addWidget(mImageTypeCombo);
88 
89  mParentFrameAdapter = StringPropertySetParentFrame::New(mPatientModelService);
90  mParentFrameCombo = new LabeledComboBoxWidget(this, mParentFrameAdapter);
91  layout->addWidget(mParentFrameCombo);
92 
93  mNiftiFormatCheckBox = new QCheckBox("Convert from RAS to LPS coordinates", this);
94  mNiftiFormatCheckBox->setToolTip(""
95  "Use RAS (X=Left->Right Y=Posterior->Anterior Z=Inferior->Superior), as in ITK-Snap.\n"
96  "This is different from DICOM/CustusX, which uses LPS (left-posterior-superior).");
97  mNiftiFormatCheckBox->setChecked(false);
98  mNiftiFormatCheckBox->setEnabled(false);
99  mTransformFromParentFrameCheckBox = new QCheckBox("Import transform from Parent", this);
100  mTransformFromParentFrameCheckBox->setToolTip("Replace data transform with that of the parent data.");
101  mTransformFromParentFrameCheckBox->setChecked(false);
102 
103  mConvertToUnsignedCheckBox = new QCheckBox("Convert to unsigned", this);
104  mConvertToUnsignedCheckBox->setToolTip("Convert imported data set to unsigned values.");
105  mConvertToUnsignedCheckBox->setChecked(false);
106 
107  layout->addWidget(mNiftiFormatCheckBox);
108  layout->addWidget(mTransformFromParentFrameCheckBox);
109  layout->addWidget(mConvertToUnsignedCheckBox);
110 
111  connect(mParentFrameAdapter.get(), &Property::changed, this, &ImportDataDialog::updateImportTransformButton);
112  this->updateImportTransformButton();
113 
114  mErrorLabel = new QLabel();
115  layout->addWidget(mErrorLabel);
116 
117  QHBoxLayout* buttons = new QHBoxLayout;
118  layout->addLayout(buttons);
119  mOkButton = new QPushButton("OK", this);
120  buttons->addStretch();
121  buttons->addWidget(mOkButton);
122  connect(mOkButton, &QPushButton::clicked, this, &QDialog::accept);
123  connect(this, &QDialog::accepted, this, &ImportDataDialog::acceptedSlot);
124  connect(this, &QDialog::rejected, this, &ImportDataDialog::finishedSlot);
125  mOkButton->setDefault(true);
126  mOkButton->setFocus();
127 
128  report("Importing data...");
129 }
130 
132 {
133 }
134 
135 void ImportDataDialog::showEvent(QShowEvent* event)
136 {
137  // the import operation takes up to a few seconds. Call it AFTER the dialog is up and running its own message loop,
138  // this avoids all problems related to modal vs right-click in the main window.
139  QTimer::singleShot(0, this, SLOT(importDataSlot()));
140 }
141 
142 void ImportDataDialog::importDataSlot()
143 {
144  QString infoText;
145  mData = mPatientModelService->importData(mFilename, infoText);
146  if (!infoText.isEmpty())
147  {
148  infoText += "<font color=red><br>If these warnings are not expected the import have probably failed.</font>";
149  if(infoText.contains("File already exists", Qt::CaseInsensitive))
150  infoText += "<font color=red><br>Importing two different volumes with the same name will lead to undesired effects.</font>";
151  mErrorLabel->setText(infoText);
152  }
153 
154  if (!mData)
155  {
156  mUidLabel->setText(mFilename);
157  mNameLabel->setText("Import failed");
158  mOkButton->setText("Exit");
159  return;
160  }
161 
162  mUidLabel->setText("Data uid: " + qstring_cast(mData->getUid()));
163  mNameLabel->setText("Data name: " + qstring_cast(mData->getName()));
164 
165  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
166  mModalityAdapter->setData(image);
167  mModalityCombo->setEnabled(image!=0);
168  mImageTypeAdapter->setData(image);
169  mImageTypeCombo->setEnabled(image!=0);
170 
171  this->setInitialGuessForParentFrame();
172  mParentFrameAdapter->setData(mData);
173  mParentFrameCombo->setEnabled(mPatientModelService->getData().size()>1);
174 
175  // enable nifti imiport only for meshes. (as this is the only case we have seen)
176  mNiftiFormatCheckBox->setEnabled(mPatientModelService->getData<Mesh>(mData->getUid())!=0);
177 
178  mConvertToUnsignedCheckBox->setEnabled(false);
179  if (image && image->getBaseVtkImageData())
180  {
181 // vtkImageDataPtr img = image->getBaseVtkImageData();
182 // std::cout << "type " << img->GetScalarTypeAsString() << " -- " << img->GetScalarType() << std::endl;
183 // std::cout << "range " << img->GetScalarTypeMin() << " -- " << img->GetScalarTypeMax() << std::endl;
184  mConvertToUnsignedCheckBox->setEnabled( (image!=0) && (image->getBaseVtkImageData()->GetScalarTypeMin()<0) );
185  }
186 }
187 
188 
192 void ImportDataDialog::setInitialGuessForParentFrame()
193 {
194  if(!mData)
195  return;
196 
197  QString base = qstring_cast(mData->getName()).split(".")[0];
198 
199  std::map<QString, DataPtr> all = mPatientModelService->getData();
200  for (std::map<QString, DataPtr>::iterator iter=all.begin(); iter!=all.end(); ++iter)
201  {
202  if (iter->second==mData)
203  continue;
204  QString current = qstring_cast(iter->second->getName()).split(".")[0];
205  if (base.indexOf(current)>=0)
206  {
207  mData->get_rMd_History()->setParentSpace(iter->first);
208  break;
209  }
210  }
211 
212 }
213 
214 void ImportDataDialog::updateImportTransformButton()
215 {
216  DataPtr parent = mPatientModelService->getData(mParentFrameAdapter->getValue());
217  bool enabled = bool(parent);
218  mTransformFromParentFrameCheckBox->setEnabled(enabled);
219 }
220 
221 void ImportDataDialog::acceptedSlot()
222 {
223  this->importParentTransform();
224  this->convertFromNifti1Coordinates();
225  this->convertToUnsigned();
226 
227  mPatientModelService->autoSave();
228  viewService()->autoShowData(mData);
229  this->finishedSlot();
230 }
231 
232 void ImportDataDialog::finishedSlot()
233 {
234 }
235 
243 void ImportDataDialog::convertFromNifti1Coordinates()
244 {
245  if (!mNiftiFormatCheckBox->isChecked())
246  return;
247  if(!mData)
248  return;
249  Transform3D sMd = mData->get_rMd();
251 // rMd = createTransformRotateZ(M_PI) * rMd;
252  Transform3D rMd = sMr.inv() * sMd;
253  mData->get_rMd_History()->setRegistration(rMd);
254  report("Nifti import: Converted data " + mData->getName() + " from LPS to RAS coordinates.");
255 }
256 
260 void ImportDataDialog::importParentTransform()
261 {
262  if (!mTransformFromParentFrameCheckBox->isChecked())
263  return;
264  if(!mData)
265  return;
266  DataPtr parent = mPatientModelService->getData(mData->getParentSpace());
267  if (!parent)
268  return;
269  mData->get_rMd_History()->setRegistration(parent->get_rMd());
270  report("Assigned rMd from data [" + parent->getName() + "] to data [" + mData->getName() + "]");
271 }
272 
273 void ImportDataDialog::convertToUnsigned()
274 {
275  if (!mConvertToUnsignedCheckBox->isChecked())
276  return;
277 
278  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
279  if (!image)
280  return;
281 
282  ImagePtr converted = convertImageToUnsigned(patientService(), image);
283 
284  image->setVtkImageData(converted->getBaseVtkImageData());
285 
286  ImageTF3DPtr TF3D = converted->getTransferFunctions3D()->createCopy();
287  ImageLUT2DPtr LUT2D = converted->getLookupTable2D()->createCopy();
288  image->setLookupTable2D(LUT2D);
289  image->setTransferFunctions3D(TF3D);
290  patientService()->insertData(image);
291 }
292 
293 
294 }//namespace cx
QString qstring_cast(const T &val)
pcsRAS
Right-Anterior-Superior, used by Slicer3D, ITK-Snap, nifti.
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
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)
ImportDataDialog(PatientModelServicePtr patientModelService, QString filename, QWidget *parent=NULL)
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.
cxLogicManager_EXPORT ViewServicePtr viewService()
void report(QString msg)
Definition: cxLogger.cpp:90
cxLogicManager_EXPORT PatientModelServicePtr patientService()
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr