CustusX  2023.01.05-dev+develop.0da12
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 "cxSpaceProvider.h"
34 #include "cxDataFactory.h"
35 
36 #include "cxXmlOptionItem.h"
38 #include "cxProfile.h"
39 #include "cxSettings.h"
40 #include "cxActiveData.h"
41 #include "cxFileManagerService.h"
42 #include "cxEnumConversion.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  mFileManagerService = filemanager;
77 }
78 
80 {
81  mDataFactory = dataFactory;
82 }
83 
85 {
86  return mSpaceProvider;
87 }
88 
90 {
91  return mDataFactory;
92 }
93 
95 {
96  mData.clear();
97  mCenter = Vector3D(0, 0, 0);
98  mLandmarkProperties.clear();
99 
100  m_rMpr_History->clear();
101  mPatientLandmarks->clear();
102 
103  emit dataAddedOrRemoved();
104  emit centerChanged();
106 }
107 
109 {
110  return mPatientLandmarks;
111 }
112 
113 // streams
115 {
116  if (mStreams.count(uid))
117  return mStreams.find(uid)->second;
118  return VideoSourcePtr();
119 }
120 
122 {
123  return mStreams;
124 }
125 
127 {
128  if (!stream)
129  return;
130  mStreams[stream->getUid()] = stream;
131  emit streamLoaded();
132 }
133 
134 std::map<QString, VideoSourcePtr> mStreams;
135 
137 {
138  return mCenter;
139 }
141 {
142  if (similar(mCenter, center))
143  return;
144  mCenter = center;
145  emit centerChanged();
146 }
147 
149 {
150  mOperatingTable = ot;
151  emit operatingTableChanged();
152 }
153 
155 {
156  return mOperatingTable;
157 }
158 
159 
160 void DataManagerImpl::setLandmarkNames(std::vector<QString> names)
161 {
162  mLandmarkProperties.clear();
163  for (unsigned i = 0; i < names.size(); ++i)
164  {
165  LandmarkProperty prop(qstring_cast(i + 1), names[i]); // generate 1-indexed uids (keep users happy)
166  mLandmarkProperties[prop.getUid()] = prop;
167  }
169 }
170 
172 {
173  int max = 0;
174  std::map<QString, LandmarkProperty>::iterator iter;
175  for (iter = mLandmarkProperties.begin(); iter != mLandmarkProperties.end(); ++iter)
176  {
177  //max = std::max(max, qstring_cast(iter->second.getName()).toInt());
178  max = std::max(max, qstring_cast(iter->first).toInt());
179  }
180  QString uid = qstring_cast(max + 1);
182 
184  return uid;
185 }
186 
188 {
189  mLandmarkProperties.clear();
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 = mFileManagerService->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, mFileManagerService);
227  //TODO FIX
228  //bool loaded = mFileManagerService->load(path, data);
229 
230  if (!loaded)
231  {
232  reportError("Failed to load file: [" + path + "]");
233  return DataPtr();
234  }
235 
236  this->loadData(data);
237  return data;
238 }
239 
240 void DataManagerImpl::loadData(DataPtr data, bool overWrite)
241 {
242  if (data->getUid().contains('%'))
243  {
244  QString uid = data->getUid();
245  QString name = data->getName();
246  this->generateUidAndName(&uid, &name);
247  data->setName(name);
248  data->setUid(uid);
249  }
250 
251  if (data)
252  {
253  if (!overWrite && mData.count(data->getUid()) && mData[data->getUid()]!=data)
254  reportError(QString("Overwriting Data with uid=%1 with new object into PasM").arg(data->getUid()));
255  //this->verifyParentFrame(data);
256  mData[data->getUid()] = data;
257  emit dataAddedOrRemoved();
258  }
259 }
260 
261 DataPtr DataManagerImpl::getData(const QString& uid) const
262 {
263  DataMap::const_iterator iter = mData.find(uid);
264  if (iter == mData.end())
265  return DataPtr();
266  return iter->second;
267 }
268 
269 std::map<QString, DataPtr> DataManagerImpl::getData() const
270 {
271  return mData;
272 }
273 
274 std::map<QString, ImagePtr> DataManagerImpl::getImages() const
275 {
276  std::map<QString, ImagePtr> retval;
277  for (DataMap::const_iterator iter = mData.begin(); iter != mData.end(); ++iter)
278  {
279  ImagePtr image = this->getImage(iter->first);
280  if (!image)
281  continue;
282  retval[iter->first] = image;
283  }
284  return retval;
285 }
286 
287 std::map<QString, MeshPtr> DataManagerImpl::getMeshes() const
288 {
289  std::map<QString, MeshPtr> retval;
290  for (DataMap::const_iterator iter = mData.begin(); iter != mData.end(); ++iter)
291  {
292  MeshPtr mesh = this->getMesh(iter->first);
293  if (!mesh)
294  continue;
295  retval[iter->first] = mesh;
296  }
297  return retval;
298 }
299 
300 void DataManagerImpl::addXml(QDomNode& parentNode)
301 {
302  QDomDocument doc = parentNode.ownerDocument();
303  QDomElement dataManagerNode = doc.createElement("datamanager");
304  parentNode.appendChild(dataManagerNode);
305 
306  m_rMpr_History->addXml(dataManagerNode);
307 
308  QDomElement landmarkPropsNode = doc.createElement("landmarkprops");
309  LandmarkPropertyMap::iterator it = mLandmarkProperties.begin();
310  for (; it != mLandmarkProperties.end(); ++it)
311  {
312  QDomElement landmarkPropNode = doc.createElement("landmarkprop");
313  it->second.addXml(landmarkPropNode);
314  landmarkPropsNode.appendChild(landmarkPropNode);
315  }
316  dataManagerNode.appendChild(landmarkPropsNode);
317 
318  QDomElement landmarksNode = doc.createElement("landmarks");
319  mPatientLandmarks->addXml(landmarksNode);
320  dataManagerNode.appendChild(landmarksNode);
321 
322  QDomElement centerNode = doc.createElement("center");
323  centerNode.appendChild(doc.createTextNode(qstring_cast(mCenter)));
324  dataManagerNode.appendChild(centerNode);
325 
326  QDomElement otNode = doc.createElement("operatingTable");
327  otNode.appendChild(doc.createTextNode(qstring_cast(mOperatingTable.rMot)));
328  dataManagerNode.appendChild(otNode);
329 
330  for (DataMap::const_iterator iter = mData.begin(); iter != mData.end(); ++iter)
331  {
332  QDomElement dataNode = doc.createElement("data");
333  dataManagerNode.appendChild(dataNode);
334  iter->second->addXml(dataNode);
335  }
336 }
337 
338 void DataManagerImpl::parseXml(QDomNode& dataManagerNode, QString rootPath)
339 {
340  // look in the toolmanager, for backwards compatibility (2014-02-21)
341  QDomNode toolManagerNode = dataManagerNode.parentNode().namedItem("toolManager");
342 
343  QDomNode registrationHistory = dataManagerNode.namedItem("registrationHistory");
344  if (registrationHistory.isNull())
345  registrationHistory = toolManagerNode.namedItem("registrationHistory");
346  m_rMpr_History->parseXml(registrationHistory);
347 
348  QDomNode landmarksNode = dataManagerNode.namedItem("landmarkprops");
349  QDomElement landmarkNode = landmarksNode.firstChildElement("landmarkprop");
350  for (; !landmarkNode.isNull(); landmarkNode = landmarkNode.nextSiblingElement("landmarkprop"))
351  {
352  LandmarkProperty landmarkProp;
353  landmarkProp.parseXml(landmarkNode);
354  mLandmarkProperties[landmarkProp.getUid()] = landmarkProp;
355  //std::cout << "Loaded landmarkprop with name: " << landmarkProp.getName() << std::endl;
357  }
358 
359  QDomNode patientLandmarksNode = dataManagerNode.namedItem("landmarks");
360  if (patientLandmarksNode.isNull())
361  patientLandmarksNode = toolManagerNode.namedItem("landmarks");
362  mPatientLandmarks->parseXml(patientLandmarksNode);
363 
364  // All images must be created from the DataManager, so the image nodes are parsed here
365  std::map<DataPtr, QDomNode> datanodes;
366 
367  QDomNode child = dataManagerNode.firstChild();
368  for (; !child.isNull(); child = child.nextSibling())
369  {
370  if (child.nodeName() == "data")
371  {
372  DataPtr data = this->loadData(child.toElement(), rootPath);
373  if (data)
374  datanodes[data] = child.toElement();
375  }
376  }
377 
378  // parse xml data separately: we want to first load all data
379  // because there might be interdependencies (cx::DistanceMetric)
380  for (std::map<DataPtr, QDomNode>::iterator iter = datanodes.begin(); iter != datanodes.end(); ++iter)
381  {
382  iter->first->parseXml(iter->second);
383  }
384 
385  emit dataAddedOrRemoved();
386 
387  //we need to make sure all images are loaded before we try to set an active image
388  child = dataManagerNode.firstChild();
389  while (!child.isNull())
390  {
391  if (child.toElement().tagName() == "center")
392  {
393  const QString centerString = child.toElement().text();
394  if (!centerString.isEmpty())
395  {
396  Vector3D center = Vector3D::fromString(centerString);
397  this->setCenter(center);
398  }
399  }
400  if (child.toElement().tagName() == "operatingTable")
401  {
402  const QString ot = child.toElement().text();
403  if (!ot.isEmpty())
404  {
405  Transform3D tr = Transform3D::fromString(ot);
406  OperatingTable t(tr);
407  this->setOperatingTable(t);
408  }
409  }
410  child = child.nextSibling();
411  }
412 }
413 
414 DataPtr DataManagerImpl::loadData(QDomElement node, QString rootPath)
415 {
416  QString uid = node.toElement().attribute("uid");
417  QString name = node.toElement().attribute("name");
418  QString type = node.toElement().attribute("type");
419 
420  QDir relativePath = this->findRelativePath(node, rootPath);
421  QString absolutePath = this->findAbsolutePath(relativePath, rootPath);
422 
423  if (mData.count(uid)) // dont load same image twice
424  return mData[uid];
425 
426  DataPtr data = mDataFactory->create(type, uid, name);
427  if (!data)
428  {
429  reportWarning(QString("Unknown type: %1 for file %2").arg(type).arg(absolutePath));
430  return DataPtr();
431  }
432  bool loaded = data->load(absolutePath, mFileManagerService);
433 
434  if (!loaded)
435  {
436  reportWarning("Unknown file: " + absolutePath);
437  return DataPtr();
438  }
439 
440  if (!name.isEmpty())
441  data->setName(name);
442  data->setFilename(relativePath.path());
443 
444  this->loadData(data);
445 
446  // conversion for change in format 2013-10-29
447  QString newPath = rootPath+"/"+data->getFilename();
448  if (QDir::cleanPath(absolutePath) != QDir::cleanPath(newPath))
449  {
450  reportWarning(QString("Detected old data format, converting from %1 to %2").arg(absolutePath).arg(newPath));
451  data->save(rootPath, mFileManagerService);
452  }
453 
454  return data;
455 }
456 
457 QDir DataManagerImpl::findRelativePath(QDomElement node, QString rootPath)
458 {
459  QString path = this->findPath(node);
460  QDir relativePath = QDir(QString(path));
461 
462  QDir patientDataDir(rootPath);
463  relativePath.setPath(patientDataDir.relativeFilePath(relativePath.path()));
464 
465  return relativePath;
466 }
467 
468 QString DataManagerImpl::findPath(QDomElement node)
469 {
470  QDomElement filePathNode = node.namedItem("filePath").toElement();
471 
472  if (filePathNode.isNull())
473  return QString();
474 
475  QString path = filePathNode.text();
476  if (path.isEmpty())
477  return QString();
478  return path;
479 }
480 
481 QString DataManagerImpl::findAbsolutePath(QDir relativePath, QString rootPath)
482 {
483  QString absolutePath = relativePath.path();
484  if (!rootPath.isEmpty())
485  absolutePath = rootPath + "/" + relativePath.path();
486  return absolutePath;
487 }
488 
490 {
491  return mClinicalApplication;
492 }
493 
494 void DataManagerImpl::setClinicalApplication(CLINICAL_VIEW application)
495 {
496  if (mClinicalApplication == application)
497  return;
498  mClinicalApplication = application;
499 
500  QString val = enum2string<CLINICAL_VIEW>(mClinicalApplication);
501  settings()->setValue("View/clinicalView", val);
502 
504 }
505 
506 void DataManagerImpl::settingsChangedSlot(QString key)
507 {
508  if (key == "View/clinicalView")
509  {
510  this->readClinicalView();
511  }
512 }
513 
515 {
516  QString defVal = enum2string<CLINICAL_VIEW>(mdNEUROLOGICAL);
517  QString val = settings()->value("View/clinicalView", defVal).toString();
518  CLINICAL_VIEW view = string2enum<CLINICAL_VIEW>(val);
519 
520  this->setClinicalApplication(view);
521 }
522 
523 
524 int DataManagerImpl::findUniqueUidNumber(QString uidBase) const
525 {
526  if (!uidBase.contains("%"))
527  return -1;
528  // Find an uid that is not used before
529  size_t numMatches = 1;
530  int recNumber = 0;
531 
532  if (numMatches != 0)
533  {
534  while (numMatches != 0)
535  {
536  QString newId = qstring_cast(uidBase).arg(++recNumber);
537  numMatches = mData.count(qstring_cast(newId));
538  }
539  }
540  return recNumber;
541 }
542 
547 void DataManagerImpl::generateUidAndName(QString* _uid, QString* _name)
548 {
549  QString& uid = *_uid;
550  QString& name = *_name;
551 
552  int recNumber = this->findUniqueUidNumber(uid);
553 
554  if (uid.contains("%"))
555  {
556  uid = uid.arg(recNumber);
557  }
558 
559  if (name.contains("%"))
560  {
561  if (recNumber == 1)
562  name = name.arg("");
563  else
564  name = name.arg(recNumber);
565  }
566 }
567 
568 void DataManagerImpl::removeData(const QString& uid, QString basePath)
569 {
570  DataPtr dataToBeRemoved = this->getData(uid);
571  mActiveData->remove(dataToBeRemoved);
572 
573  mData.erase(uid);
574 
575  this->deleteFiles(dataToBeRemoved, basePath);
576 
577  emit dataAddedOrRemoved(); // this should alert everybody interested in the data as a collection.
578  report("Removed data [" + uid + "].");
579 }
580 
581 void DataManagerImpl::deleteFiles(DataPtr data, QString basePath)
582 {
583  if (!data)
584  return;
585  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
586  QStringList files;
587  if (!data->getFilename().isEmpty())
588  {
589  files << QDir(basePath).absoluteFilePath(data->getFilename());
590  if (image)
591  files << changeExtension(files[0], "raw");
592  }
593 
594  for (int i=0; i<files.size(); ++i)
595  {
596  if (!QFileInfo(files[i]).exists())
597  continue;
598  report(QString("Removing %1 from disk").arg(files[i]));
599  QFile(files[i]).remove();
600  }
601 }
602 
604 {
605  return m_rMpr_History->getCurrentRegistration().mValue;
606 }
607 
609 {
610  m_rMpr_History->setRegistration(val);
611 }
612 
614 {
615  return m_rMpr_History;
616 }
617 
619 {
621  XmlOptionFile preset(DataLocations::findConfigFilePath("presets.xml", "/transferFunctions"));
622  XmlOptionFile custom = profile()->getXmlSettings().descend("presetTransferFunctions");
623 
625  mPresetTransferFunctions3D.reset(new TransferFunctions3DPresets(preset, custom));
626 
628 }
629 
630 } // namespace cx
631 
boost::shared_ptr< class SpaceProvider > SpaceProviderPtr
QString qstring_cast(const T &val)
DataFactoryPtr mDataFactory
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:160
boost::shared_ptr< class FileManagerService > FileManagerServicePtr
void rMprChanged()
emitted when the transformation between patient reference and (data) reference is set ...
FileManagerServicePtr mFileManagerService
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
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
void setServices(SpaceProviderPtr spaceProvider, FileManagerServicePtr filemanager)
boost::shared_ptr< class Landmarks > LandmarksPtr
Definition: cxData.h:41
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
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 loadData(DataPtr data, bool overWrite=false)
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:60
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 clinicalApplicationChanged()
virtual void loadStream(VideoSourcePtr stream)
A history of registration events.
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