CustusX  16.5.0-rc9
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxDataManagerImpl.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 
34 #include "cxDataManagerImpl.h"
35 
36 #include <QtCore>
37 #include <QDomDocument>
38 #include <QFileInfo>
39 #include <QFile>
40 #include <QTextStream>
41 #include <QDir>
42 
43 #include "cxTransform3D.h"
45 #include "cxLogger.h"
46 #include "cxTypeConversions.h"
47 #include "cxUtilHelpers.h"
48 #include "cxVideoSource.h"
49 #include "cxDataLocations.h"
50 
51 #include "cxImageLUT2D.h"
52 #include "cxImageTF3D.h"
53 
54 #include "cxDataReaderWriter.h"
55 #include "cxSpaceProvider.h"
56 #include "cxDataFactory.h"
57 
58 #include "cxXmlOptionItem.h"
60 #include "cxProfile.h"
61 #include "cxSettings.h"
62 #include "cxDefinitionStrings.h"
63 #include "cxActiveData.h"
64 
65 
66 namespace cx
67 {
68 
70 {
71  DataManagerImplPtr retval;
72  retval.reset(new DataManagerImpl(activeData));
73  return retval;
74 }
75 
77  mClinicalApplication(mdNEUROLOGICAL),
78  mActiveData(activeData)
79 {
83 
84  connect(settings(), SIGNAL(valueChangedFor(QString)), this, SLOT(settingsChangedSlot(QString)));
85  this->readClinicalView();
86 
87  this->clear();
88 }
89 
91 {
92 }
93 
95 {
97 }
98 
100 {
101  mDataFactory = dataFactory;
102 }
103 
105 {
106  return mSpaceProvider;
107 }
108 
110 {
111  return mDataFactory;
112 }
113 
115 {
116  mData.clear();
117  mCenter = Vector3D(0, 0, 0);
118  mLandmarkProperties.clear();
119 
120  m_rMpr_History->clear();
121  mPatientLandmarks->clear();
122 
123  emit dataAddedOrRemoved();
124  emit centerChanged();
126 }
127 
129 {
130  return mPatientLandmarks;
131 }
132 
133 // streams
135 {
136  if (mStreams.count(uid))
137  return mStreams.find(uid)->second;
138  return VideoSourcePtr();
139 }
140 
142 {
143  return mStreams;
144 }
145 
147 {
148  if (!stream)
149  return;
150  mStreams[stream->getUid()] = stream;
151  emit streamLoaded();
152 }
153 
154 std::map<QString, VideoSourcePtr> mStreams;
155 
157 {
158  return mCenter;
159 }
161 {
162  mCenter = center;
163  emit centerChanged();
164 }
165 
166 void DataManagerImpl::setLandmarkNames(std::vector<QString> names)
167 {
168  mLandmarkProperties.clear();
169  for (unsigned i = 0; i < names.size(); ++i)
170  {
171  LandmarkProperty prop(qstring_cast(i + 1), names[i]); // generate 1-indexed uids (keep users happy)
172  mLandmarkProperties[prop.getUid()] = prop;
173  }
175 }
176 
178 {
179  int max = 0;
180  std::map<QString, LandmarkProperty>::iterator iter;
181  for (iter = mLandmarkProperties.begin(); iter != mLandmarkProperties.end(); ++iter)
182  {
183  //max = std::max(max, qstring_cast(iter->second.getName()).toInt());
184  max = std::max(max, qstring_cast(iter->first).toInt());
185  }
186  QString uid = qstring_cast(max + 1);
188 
190  return uid;
191 }
192 
193 void DataManagerImpl::setLandmarkName(QString uid, QString name)
194 {
195  mLandmarkProperties[uid].setName(name);
197 }
198 
199 std::map<QString, LandmarkProperty> DataManagerImpl::getLandmarkProperties() const
200 {
201  return mLandmarkProperties;
202 }
203 
204 void DataManagerImpl::setLandmarkActive(QString uid, bool active)
205 {
206  mLandmarkProperties[uid].setActive(active);
208 }
209 
210 DataPtr DataManagerImpl::loadData(const QString& uid, const QString& path)
211 {
212  if (mData.count(uid)) // dont load same image twice
213  return mData[uid];
214 
215  QString type = DataReaderWriter().findDataTypeFromFile(path);
216  if(!mDataFactory)
217  reportError("DataManagerImpl::loadData() Got no DataFactory");
218  DataPtr data = mDataFactory->create(type, uid);
219 
220  if (!data)
221  {
222  reportError("Failed to find loaded for: [" + path + "]");
223  return DataPtr();
224  }
225 
226  bool loaded = data->load(path);
227 
228  if (!loaded)
229  {
230  reportError("Failed to load file: [" + path + "]");
231  return DataPtr();
232  }
233 
234  this->loadData(data);
235  return data;
236 }
237 
239 {
240  if (data->getUid().contains('%'))
241  {
242  QString uid = data->getUid();
243  QString name = data->getName();
244  this->generateUidAndName(&uid, &name);
245  data->setName(name);
246  data->setUid(uid);
247  }
248 
249  if (data)
250  {
251  if (mData.count(data->getUid()) && mData[data->getUid()]!=data)
252  reportError(QString("Overwriting Data with uid=%1 with new object into PasM").arg(data->getUid()));
253 // this->verifyParentFrame(data);
254  mData[data->getUid()] = data;
255  emit dataAddedOrRemoved();
256  }
257 }
258 
259 DataPtr DataManagerImpl::getData(const QString& uid) const
260 {
261  DataMap::const_iterator iter = mData.find(uid);
262  if (iter == mData.end())
263  return DataPtr();
264  return iter->second;
265 }
266 
267 std::map<QString, DataPtr> DataManagerImpl::getData() const
268 {
269  return mData;
270 }
271 
272 std::map<QString, ImagePtr> DataManagerImpl::getImages() const
273 {
274  std::map<QString, ImagePtr> retval;
275  for (DataMap::const_iterator iter = mData.begin(); iter != mData.end(); ++iter)
276  {
277  ImagePtr image = this->getImage(iter->first);
278  if (!image)
279  continue;
280  retval[iter->first] = image;
281  }
282  return retval;
283 }
284 
285 std::map<QString, MeshPtr> DataManagerImpl::getMeshes() const
286 {
287  std::map<QString, MeshPtr> retval;
288  for (DataMap::const_iterator iter = mData.begin(); iter != mData.end(); ++iter)
289  {
290  MeshPtr mesh = this->getMesh(iter->first);
291  if (!mesh)
292  continue;
293  retval[iter->first] = mesh;
294  }
295  return retval;
296 }
297 
298 void DataManagerImpl::addXml(QDomNode& parentNode)
299 {
300  QDomDocument doc = parentNode.ownerDocument();
301  QDomElement dataManagerNode = doc.createElement("datamanager");
302  parentNode.appendChild(dataManagerNode);
303 
304  m_rMpr_History->addXml(dataManagerNode);
305 
306  QDomElement landmarkPropsNode = doc.createElement("landmarkprops");
307  LandmarkPropertyMap::iterator it = mLandmarkProperties.begin();
308  for (; it != mLandmarkProperties.end(); ++it)
309  {
310  QDomElement landmarkPropNode = doc.createElement("landmarkprop");
311  it->second.addXml(landmarkPropNode);
312  landmarkPropsNode.appendChild(landmarkPropNode);
313  }
314  dataManagerNode.appendChild(landmarkPropsNode);
315 
316  QDomElement landmarksNode = doc.createElement("landmarks");
317  mPatientLandmarks->addXml(landmarksNode);
318  dataManagerNode.appendChild(landmarksNode);
319 
320  QDomElement centerNode = doc.createElement("center");
321  centerNode.appendChild(doc.createTextNode(qstring_cast(mCenter)));
322  dataManagerNode.appendChild(centerNode);
323 
324  for (DataMap::const_iterator iter = mData.begin(); iter != mData.end(); ++iter)
325  {
326  QDomElement dataNode = doc.createElement("data");
327  dataManagerNode.appendChild(dataNode);
328  iter->second->addXml(dataNode);
329  }
330 }
331 
332 void DataManagerImpl::parseXml(QDomNode& dataManagerNode, QString rootPath)
333 {
334  // look in the toolmanager, for backwards compatibility (2014-02-21)
335  QDomNode toolManagerNode = dataManagerNode.parentNode().namedItem("toolManager");
336 
337  QDomNode registrationHistory = dataManagerNode.namedItem("registrationHistory");
338  if (registrationHistory.isNull())
339  registrationHistory = toolManagerNode.namedItem("registrationHistory");
340  m_rMpr_History->parseXml(registrationHistory);
341 
342  QDomNode landmarksNode = dataManagerNode.namedItem("landmarkprops");
343  QDomElement landmarkNode = landmarksNode.firstChildElement("landmarkprop");
344  for (; !landmarkNode.isNull(); landmarkNode = landmarkNode.nextSiblingElement("landmarkprop"))
345  {
346  LandmarkProperty landmarkProp;
347  landmarkProp.parseXml(landmarkNode);
348  mLandmarkProperties[landmarkProp.getUid()] = landmarkProp;
349  //std::cout << "Loaded landmarkprop with name: " << landmarkProp.getName() << std::endl;
351  }
352 
353  QDomNode patientLandmarksNode = dataManagerNode.namedItem("landmarks");
354  if (patientLandmarksNode.isNull())
355  patientLandmarksNode = toolManagerNode.namedItem("landmarks");
356  mPatientLandmarks->parseXml(patientLandmarksNode);
357 
358  // All images must be created from the DataManager, so the image nodes are parsed here
359  std::map<DataPtr, QDomNode> datanodes;
360 
361  QDomNode child = dataManagerNode.firstChild();
362  for (; !child.isNull(); child = child.nextSibling())
363  {
364  if (child.nodeName() == "data")
365  {
366  DataPtr data = this->loadData(child.toElement(), rootPath);
367  if (data)
368  datanodes[data] = child.toElement();
369  }
370  }
371 
372  // parse xml data separately: we want to first load all data
373  // because there might be interdependencies (cx::DistanceMetric)
374  for (std::map<DataPtr, QDomNode>::iterator iter = datanodes.begin(); iter != datanodes.end(); ++iter)
375  {
376  iter->first->parseXml(iter->second);
377  }
378 
379  emit dataAddedOrRemoved();
380 
381  //we need to make sure all images are loaded before we try to set an active image
382  child = dataManagerNode.firstChild();
383  while (!child.isNull())
384  {
385  if (child.toElement().tagName() == "center")
386  {
387  const QString centerString = child.toElement().text();
388  if (!centerString.isEmpty())
389  {
390  Vector3D center = Vector3D::fromString(centerString);
391  this->setCenter(center);
392  }
393  }
394  child = child.nextSibling();
395  }
396 }
397 
398 DataPtr DataManagerImpl::loadData(QDomElement node, QString rootPath)
399 {
400  QString uid = node.toElement().attribute("uid");
401  QString name = node.toElement().attribute("name");
402  QString type = node.toElement().attribute("type");
403 
404  QDir relativePath = this->findRelativePath(node, rootPath);
405  QString absolutePath = this->findAbsolutePath(relativePath, rootPath);
406 
407  if (mData.count(uid)) // dont load same image twice
408  return mData[uid];
409 
410  DataPtr data = mDataFactory->create(type, uid, name);
411  if (!data)
412  {
413  reportWarning(QString("Unknown type: %1 for file %2").arg(type).arg(absolutePath));
414  return DataPtr();
415  }
416  bool loaded = data->load(absolutePath);
417 
418  if (!loaded)
419  {
420  reportWarning("Unknown file: " + absolutePath);
421  return DataPtr();
422  }
423 
424  if (!name.isEmpty())
425  data->setName(name);
426  data->setFilename(relativePath.path());
427 
428  this->loadData(data);
429 
430  // conversion for change in format 2013-10-29
431  QString newPath = rootPath+"/"+data->getFilename();
432  if (QDir::cleanPath(absolutePath) != QDir::cleanPath(newPath))
433  {
434  reportWarning(QString("Detected old data format, converting from %1 to %2").arg(absolutePath).arg(newPath));
435  data->save(rootPath);
436  }
437 
438  return data;
439 }
440 
441 QDir DataManagerImpl::findRelativePath(QDomElement node, QString rootPath)
442 {
443  QString path = this->findPath(node);
444  QDir relativePath = QDir(QString(path));
445 
446  QDir patientDataDir(rootPath);
447  relativePath.setPath(patientDataDir.relativeFilePath(relativePath.path()));
448 
449  return relativePath;
450 }
451 
452 QString DataManagerImpl::findPath(QDomElement node)
453 {
454  QDomElement filePathNode = node.namedItem("filePath").toElement();
455 
456  if (filePathNode.isNull())
457  return QString();
458 
459  QString path = filePathNode.text();
460  if (path.isEmpty())
461  return QString();
462  return path;
463 }
464 
465 QString DataManagerImpl::findAbsolutePath(QDir relativePath, QString rootPath)
466 {
467  QString absolutePath = relativePath.path();
468  if (!rootPath.isEmpty())
469  absolutePath = rootPath + "/" + relativePath.path();
470  return absolutePath;
471 }
472 
474 {
475  return mClinicalApplication;
476 }
477 
478 void DataManagerImpl::setClinicalApplication(CLINICAL_VIEW application)
479 {
480  if (mClinicalApplication == application)
481  return;
482  mClinicalApplication = application;
483 
484  QString val = enum2string<CLINICAL_VIEW>(mClinicalApplication);
485  settings()->setValue("View/clinicalView", val);
486 
488 }
489 
490 void DataManagerImpl::settingsChangedSlot(QString key)
491 {
492  if (key == "View/clinicalView")
493  {
494  this->readClinicalView();
495  }
496 }
497 
499 {
500  QString defVal = enum2string<CLINICAL_VIEW>(mdNEUROLOGICAL);
501  QString val = settings()->value("View/clinicalView", defVal).toString();
502  CLINICAL_VIEW view = string2enum<CLINICAL_VIEW>(val);
503 
504  this->setClinicalApplication(view);
505 }
506 
507 
508 int DataManagerImpl::findUniqueUidNumber(QString uidBase) const
509 {
510  if (!uidBase.contains("%"))
511  return -1;
512  // Find an uid that is not used before
513  size_t numMatches = 1;
514  int recNumber = 0;
515 
516  if (numMatches != 0)
517  {
518  while (numMatches != 0)
519  {
520  QString newId = qstring_cast(uidBase).arg(++recNumber);
521  numMatches = mData.count(qstring_cast(newId));
522  }
523  }
524  return recNumber;
525 }
526 
531 void DataManagerImpl::generateUidAndName(QString* _uid, QString* _name)
532 {
533  QString& uid = *_uid;
534  QString& name = *_name;
535 
536  int recNumber = this->findUniqueUidNumber(uid);
537 
538  if (uid.contains("%"))
539  {
540  uid = uid.arg(recNumber);
541  }
542 
543  if (name.contains("%"))
544  {
545  if (recNumber == 1)
546  name = name.arg("");
547  else
548  name = name.arg(recNumber);
549  }
550 }
551 
552 void DataManagerImpl::removeData(const QString& uid, QString basePath)
553 {
554  DataPtr dataToBeRemoved = this->getData(uid);
555  mActiveData->remove(dataToBeRemoved);
556 
557  mData.erase(uid);
558 
559  this->deleteFiles(dataToBeRemoved, basePath);
560 
561  emit dataAddedOrRemoved(); // this should alert everybody interested in the data as a collection.
562  report("Removed data [" + uid + "].");
563 }
564 
565 void DataManagerImpl::deleteFiles(DataPtr data, QString basePath)
566 {
567  if (!data)
568  return;
569  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
570  QStringList files;
571  if (!data->getFilename().isEmpty())
572  {
573  files << QDir(basePath).absoluteFilePath(data->getFilename());
574  if (image)
575  files << changeExtension(files[0], "raw");
576  }
577 
578  for (int i=0; i<files.size(); ++i)
579  {
580  if (!QFileInfo(files[i]).exists())
581  continue;
582  report(QString("Removing %1 from disk").arg(files[i]));
583  QFile(files[i]).remove();
584  }
585 }
586 
588 {
589  return m_rMpr_History->getCurrentRegistration().mValue;
590 }
591 
593 {
594  m_rMpr_History->setRegistration(val);
595 }
596 
598 {
599  return m_rMpr_History;
600 }
601 
603 {
605  XmlOptionFile preset(DataLocations::findConfigFilePath("presets.xml", "/transferFunctions"));
606  XmlOptionFile custom = profile()->getXmlSettings().descend("presetTransferFunctions");
607 
609  mPresetTransferFunctions3D.reset(new TransferFunctions3DPresets(preset, custom));
610 
612 }
613 
614 } // namespace cx
615 
boost::shared_ptr< class SpaceProvider > SpaceProviderPtr
QString qstring_cast(const T &val)
DataFactoryPtr mDataFactory
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:176
void rMprChanged()
emitted when the transformation between patient reference and (data) reference is set ...
int findUniqueUidNumber(QString uidBase) const
virtual void removeData(const QString &uid, QString basePath)
remove data from datamanger, emit signal
void reportError(QString msg)
Definition: cxLogger.cpp:92
virtual CLINICAL_VIEW getClinicalApplication() const
boost::shared_ptr< class RegistrationHistory > RegistrationHistoryPtr
Definition: cxDataManager.h:57
std::map< QString, VideoSourcePtr > mStreams
QString findDataTypeFromFile(QString filename)
std::map< QString, VideoSourcePtr > mStreams
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
virtual std::map< QString, LandmarkProperty > getLandmarkProperties() const
boost::shared_ptr< class TransferFunctions3DPresets > PresetTransferFunctions3DPtr
Definition: cxDataManager.h:56
virtual void setLandmarkName(QString uid, QString name)
QString getUid() const
Definition: cxLandmark.cpp:196
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
virtual VideoSourcePtr getStream(const QString &uid) const
boost::shared_ptr< class DataManagerImpl > DataManagerImplPtr
void deleteFiles(DataPtr data, QString basePath)
virtual void generateUidAndName(QString *_uid, QString *_name)
virtual MeshPtr getMesh(const QString &uid) const
boost::shared_ptr< class ActiveData > ActiveDataPtr
Definition: cxColorWidget.h:42
void landmarkPropertiesChanged()
emitted when global info about a landmark changed
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:87
void centerChanged()
emitted when center is changed.
ActiveDataPtr mActiveData
virtual LandmarksPtr getPatientLandmarks()
virtual void addXml(QDomNode &parentNode)
adds xml information about the datamanger and its variabels
boost::shared_ptr< class Landmarks > LandmarksPtr
Definition: cxData.h:61
PresetTransferFunctions3DPtr mPresetTransferFunctions3D
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:79
boost::shared_ptr< class Data > DataPtr
DataManagerImpl(ActiveDataPtr activeData)
virtual void parseXml(QDomNode &datamangerNode, QString absolutePath=QString())
Use a XML node to load data.
virtual StreamMap getStreams() const
static DataManagerImplPtr create(ActiveDataPtr activeData)
virtual std::map< QString, ImagePtr > getImages() const
virtual void setLandmarkNames(std::vector< QString > names)
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
virtual void setClinicalApplication(CLINICAL_VIEW application)
std::map< QString, DataPtr > getData() const
void dataAddedOrRemoved()
A volumetric data set.
Definition: cxImage.h:66
void parseXml(QDomNode &dataNode)
Definition: cxLandmark.cpp:217
virtual PresetTransferFunctions3DPtr getPresetTransferFunctions3D() const
boost::shared_ptr< class VideoSource > VideoSourcePtr
virtual Transform3D get_rMpr() const
get the patient registration transform
static QString findConfigFilePath(QString fileName, QString pathRelativeToConfigRoot, QString alternativeAbsolutePath="")
RegistrationHistoryPtr m_rMpr_History
transform from the patient reference to the reference, along with historical data.
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:42
virtual void setLandmarkActive(QString uid, bool active)
static LandmarksPtr create()
Definition: cxLandmark.cpp:116
LandmarksPtr mPatientLandmarks
in space patient reference.
cxLogicManager_EXPORT SpaceProviderPtr spaceProvider()
virtual Vector3D getCenter() const
current common center point for user viewing.
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
virtual void setCenter(const Vector3D &center)
virtual ImagePtr getImage(const QString &uid) const
QString changeExtension(QString name, QString ext)
void report(QString msg)
Definition: cxLogger.cpp:90
void setDataFactory(DataFactoryPtr dataFactory)
mdNEUROLOGICAL
Definition: cxDefinitions.h:75
virtual SpaceProviderPtr getSpaceProvider()
virtual void set_rMpr(const Transform3D &val)
set the transform from patient to reference space
virtual std::map< QString, MeshPtr > getMeshes() const
virtual QString addLandmark()
CLINICAL_VIEW mClinicalApplication
LandmarkPropertyMap mLandmarkProperties
uid and name
SpaceProviderPtr mSpaceProvider
boost::shared_ptr< class DataFactory > DataFactoryPtr
boost::shared_ptr< class Mesh > MeshPtr
void loadData(DataPtr data)
void clinicalApplicationChanged()
virtual void loadStream(VideoSourcePtr stream)
A history of registration events.
void setSpaceProvider(SpaceProviderPtr spaceProvider)
Helper class for xml files used to store ssc/cx data.
Handles transfer function presets.
virtual void clear()
remove all stuff from manager
virtual DataFactoryPtr getDataFactory()
virtual RegistrationHistoryPtr get_rMpr_History() const
std::map< QString, VideoSourcePtr > StreamMap
Definition: cxDataManager.h:75