CustusX  15.3.4-beta
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("Use NIfTI-1/ITK-Snap axis definition", this);
94  mNiftiFormatCheckBox->setToolTip(""
95  "Use X=Left->Right Y=Posterior->Anterior Z=Inferior->Superior, as in ITK-Snap.\n"
96  "This is different from normal DICOM.");
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(""
105  "Convert imported data set to unsigned values.\n"
106  "This is recommended on Linux because the 2D overlay\n"
107  "renderer only handles unsigned.");
108  mConvertToUnsignedCheckBox->setChecked(false);
109 
110  layout->addWidget(mNiftiFormatCheckBox);
111  layout->addWidget(mTransformFromParentFrameCheckBox);
112  layout->addWidget(mConvertToUnsignedCheckBox);
113 
114  connect(mParentFrameAdapter.get(), SIGNAL(changed()), this, SLOT(updateImportTransformButton()));
115  this->updateImportTransformButton();
116 
117  mErrorLabel = new QLabel();
118  layout->addWidget(mErrorLabel);
119 
120  QHBoxLayout* buttons = new QHBoxLayout;
121  layout->addLayout(buttons);
122  mOkButton = new QPushButton("OK", this);
123  buttons->addStretch();
124  buttons->addWidget(mOkButton);
125  connect(mOkButton, SIGNAL(clicked()), this, SLOT(accept()));
126  connect(this, SIGNAL(accepted()), this, SLOT(acceptedSlot()));
127  mOkButton->setDefault(true);
128  mOkButton->setFocus();
129 
130  report("Importing data...");
131 }
132 
134 {
135 }
136 
137 void ImportDataDialog::showEvent(QShowEvent* event)
138 {
139  // the import operation takes up to a few seconds. Call it AFTER the dialog is up and running its own message loop,
140  // this avoids all problems related to modal vs right-click in the main window.
141  QTimer::singleShot(0, this, SLOT(importDataSlot()));
142 }
143 
144 void ImportDataDialog::importDataSlot()
145 {
146  QString infoText;
147  mData = mPatientModelService->importData(mFilename, infoText);
148  if (!infoText.isEmpty())
149  {
150  infoText += "<font color=red><br>If these warnings are not expected the import have probably failed.</font>";
151  if(infoText.contains("File already exists", Qt::CaseInsensitive))
152  infoText += "<font color=red><br>Importing two different volumes with the same name will lead to undesired effects.</font>";
153  mErrorLabel->setText(infoText);
154  }
155 
156  if (!mData)
157  {
158  mUidLabel->setText(mFilename);
159  mNameLabel->setText("Import failed");
160  mOkButton->setText("Exit");
161  return;
162  }
163 
164  mUidLabel->setText("Data uid: " + qstring_cast(mData->getUid()));
165  mNameLabel->setText("Data name: " + qstring_cast(mData->getName()));
166 
167  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
168  mModalityAdapter->setData(image);
169  mModalityCombo->setEnabled(image!=0);
170  mImageTypeAdapter->setData(image);
171  mImageTypeCombo->setEnabled(image!=0);
172 
173  this->setInitialGuessForParentFrame();
174  mParentFrameAdapter->setData(mData);
175  mParentFrameCombo->setEnabled(mPatientModelService->getData().size()>1);
176 
177  // enable nifti imiport only for meshes. (as this is the only case we have seen)
178  mNiftiFormatCheckBox->setEnabled(mPatientModelService->getData<Mesh>(mData->getUid())!=0);
179 
180  mConvertToUnsignedCheckBox->setEnabled(false);
181 // ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
182  if (image && image->getBaseVtkImageData())
183  {
184  vtkImageDataPtr img = image->getBaseVtkImageData();
185 // std::cout << "type " << img->GetScalarTypeAsString() << " -- " << img->GetScalarType() << std::endl;
186 // std::cout << "range " << img->GetScalarTypeMin() << " -- " << img->GetScalarTypeMax() << std::endl;
187  mConvertToUnsignedCheckBox->setEnabled( (image!=0) && (image->getBaseVtkImageData()->GetScalarTypeMin()<0) );
188 #ifndef __APPLE__
189 #ifndef WIN32
190  // i.e. LINUX:
191  if (mConvertToUnsignedCheckBox->isEnabled())
192  mConvertToUnsignedCheckBox->setChecked(true);
193 #endif // WIN32
194 #endif // __APPLE__
195  }
196 }
197 
198 
202 void ImportDataDialog::setInitialGuessForParentFrame()
203 {
204  if(!mData)
205  return;
206 
207  QString base = qstring_cast(mData->getName()).split(".")[0];
208 
209  std::map<QString, DataPtr> all = mPatientModelService->getData();
210  for (std::map<QString, DataPtr>::iterator iter=all.begin(); iter!=all.end(); ++iter)
211  {
212  if (iter->second==mData)
213  continue;
214  QString current = qstring_cast(iter->second->getName()).split(".")[0];
215  if (base.indexOf(current)>=0)
216  {
217  mData->get_rMd_History()->setParentSpace(iter->first);
218  break;
219  }
220  }
221 
222 }
223 
224 void ImportDataDialog::updateImportTransformButton()
225 {
226  DataPtr parent = mPatientModelService->getData(mParentFrameAdapter->getValue());
227  bool enabled = bool(parent);
228  mTransformFromParentFrameCheckBox->setEnabled(enabled);
229 }
230 
231 void ImportDataDialog::acceptedSlot()
232 {
233  this->importParentTransform();
234  this->convertFromNifti1Coordinates();
235  this->convertToUnsigned();
236 
237  mPatientModelService->autoSave();
238  viewService()->autoShowData(mData);
239 }
240 
248 void ImportDataDialog::convertFromNifti1Coordinates()
249 {
250  if (!mNiftiFormatCheckBox->isChecked())
251  return;
252  if(!mData)
253  return;
254  Transform3D rMd = mData->get_rMd();
255  rMd = rMd * createTransformRotateZ(M_PI);
256  mData->get_rMd_History()->setRegistration(rMd);
257  report("Nifti import: rotated input data " + mData->getName() + " 180* around Z-axis.");
258 }
259 
263 void ImportDataDialog::importParentTransform()
264 {
265  if (!mTransformFromParentFrameCheckBox->isChecked())
266  return;
267  if(!mData)
268  return;
269  DataPtr parent = mPatientModelService->getData(mData->getParentSpace());
270  if (!parent)
271  return;
272  mData->get_rMd_History()->setRegistration(parent->get_rMd());
273  report("Assigned rMd from data [" + parent->getName() + "] to data [" + mData->getName() + "]");
274 }
275 
276 void ImportDataDialog::convertToUnsigned()
277 {
278  if (!mConvertToUnsignedCheckBox->isChecked())
279  return;
280 
281  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
282  if (!image)
283  return;
284 
285  ImagePtr converted = convertImageToUnsigned(patientService(), image);
286 
287  image->setVtkImageData(converted->getBaseVtkImageData());
288 
289  ImageTF3DPtr TF3D = converted->getTransferFunctions3D()->createCopy();
290  ImageLUT2DPtr LUT2D = converted->getLookupTable2D()->createCopy();
291  image->setLookupTable2D(LUT2D);
292  image->setTransferFunctions3D(TF3D);
293  patientService()->insertData(image);
294 }
295 
296 
297 }//namespace cx
QString qstring_cast(const T &val)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
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)
cxLogicManager_EXPORT ViewServicePtr viewService()
void report(QString msg)
Definition: cxLogger.cpp:90
cxLogicManager_EXPORT PatientModelServicePtr patientService()
Transform3D createTransformRotateZ(const double angle)
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr
#define M_PI