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