Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkProportionalTimeGeometryToXML.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include "mitkGeometry3DToXML.h"
16 
17 #include <tinyxml.h>
18 
19 #include <mitkLexicalCast.h>
20 
22 {
23  assert(timeGeom);
24 
25  auto *timeGeomElem = new TiXmlElement("ProportionalTimeGeometry");
26  timeGeomElem->SetAttribute("NumberOfTimeSteps", timeGeom->CountTimeSteps());
27  // TinyXML cannot serialize infinity (default value for time step)
28  // So we guard this value and the first time point against serialization problems
29  // by not writing them. The reader can then tell that absence of those values
30  // means "keep the default values"
32  timeGeomElem->SetAttribute("FirstTimePoint", boost::lexical_cast<std::string>(timeGeom->GetFirstTimePoint()));
33  if (timeGeom->GetStepDuration() != std::numeric_limits<TimePointType>::infinity())
34  timeGeomElem->SetAttribute("StepDuration", boost::lexical_cast<std::string>(timeGeom->GetStepDuration()));
35 
36  for (TimeStepType t = 0; t < timeGeom->CountTimeSteps(); ++t)
37  {
38  // add a node for the geometry of each time step
39  const Geometry3D *geom3D(nullptr);
40  if ((geom3D = dynamic_cast<const Geometry3D *>(timeGeom->GetGeometryForTimeStep(t).GetPointer())))
41  {
42  TiXmlElement *geom3DElement = Geometry3DToXML::ToXML(geom3D);
43  geom3DElement->SetAttribute("TimeStep", t); // mark order for us
44  timeGeomElem->LinkEndChild(geom3DElement);
45  }
46  else
47  {
48  MITK_WARN << "Serializing a ProportionalTimeGeometry that contains something other than Geometry3D!"
49  << " (in time step " << t << ")"
50  << " File will miss information!";
51  }
52  }
53 
54  return timeGeomElem;
55 }
56 
58 {
59  if (!timeGeometryElement)
60  {
61  MITK_ERROR << "Cannot deserialize ProportionalTimeGeometry from nullptr.";
62  return nullptr;
63  }
64 
65  int numberOfTimeSteps = 0;
66 
67  if (TIXML_SUCCESS != timeGeometryElement->QueryIntAttribute("NumberOfTimeSteps", &numberOfTimeSteps))
68  {
69  MITK_WARN << "<ProportionalTimeGeometry> found without NumberOfTimeSteps attribute. Counting...";
70  }
71 
72  // might be missing!
73  TimePointType firstTimePoint;
74  std::string firstTimePoint_s;
75  TimePointType stepDuration;
76  std::string stepDuration_s;
77  try
78  {
79  if (TIXML_SUCCESS == timeGeometryElement->QueryStringAttribute("FirstTimePoint", &firstTimePoint_s))
80  {
81  firstTimePoint = boost::lexical_cast<double>(firstTimePoint_s);
82  }
83  else
84  {
85  firstTimePoint = -std::numeric_limits<TimePointType>::max();
86  }
87 
88  if (TIXML_SUCCESS == timeGeometryElement->QueryStringAttribute("StepDuration", &stepDuration_s))
89  {
90  stepDuration = boost::lexical_cast<double>(stepDuration_s);
91  }
92  else
93  {
94  stepDuration = std::numeric_limits<TimePointType>::infinity();
95  }
96  }
97  catch ( const boost::bad_lexical_cast &e )
98  {
99  MITK_ERROR << "Could not parse string as number: " << e.what();
100  return nullptr;
101  }
102 
103  // list of all geometries with their time steps
104  std::multimap<TimeStepType, BaseGeometry::Pointer> allReadGeometries;
105 
106  int indexForUnlabeledTimeStep(-1);
107  for (TiXmlElement *currentElement = timeGeometryElement->FirstChildElement(); currentElement != nullptr;
108  currentElement = currentElement->NextSiblingElement())
109  {
110  // different geometries could have been inside a ProportionalTimeGeometry.
111  // By now, we only support Geometry3D
112  std::string tagName = currentElement->Value();
113  if (tagName == "Geometry3D")
114  {
115  Geometry3D::Pointer restoredGeometry = Geometry3DToXML::FromXML(currentElement);
116  if (restoredGeometry.IsNotNull())
117  {
118  int timeStep(-1);
119  if (TIXML_SUCCESS != currentElement->QueryIntAttribute("TimeStep", &timeStep))
120  {
121  timeStep = indexForUnlabeledTimeStep--; // decrement index for next one
122  MITK_WARN << "Found <Geometry3D> without 'TimeStep' attribute in <ProportionalTimeGeometry>. No guarantees "
123  "on order anymore.";
124  }
125 
126  if (allReadGeometries.count(static_cast<TimeStepType>(timeStep)) > 0)
127  {
128  MITK_WARN << "Found <Geometry3D> tags with identical 'TimeStep' attribute in <ProportionalTimeGeometry>. No "
129  "guarantees on order anymore.";
130  }
131 
132  allReadGeometries.insert(std::make_pair(static_cast<TimeStepType>(timeStep), restoredGeometry.GetPointer()));
133  }
134  }
135  else
136  {
137  MITK_WARN << "Found unsupported tag <" << tagName << "> inside <ProportionalTimeGeometry>. Ignoring.";
138  }
139  }
140 
141  // now add all BaseGeometries that were read to a new instance
142  // of ProportionalTimeGeometry
144  newTimeGeometry->SetFirstTimePoint(firstTimePoint);
145  newTimeGeometry->SetStepDuration(stepDuration);
146  newTimeGeometry->ReserveSpaceForGeometries(allReadGeometries.size());
147 
148  TimeStepType t(0);
149  for (auto entry : allReadGeometries)
150  {
151  // We add items with newly assigned time steps.
152  // This avoids great confusion when a file contains
153  // bogus numbers.
154  newTimeGeometry->SetTimeStepGeometry(entry.second, t++);
155  }
156 
157  // Need to re-calculate global bounding box.
158  // This is neither stored in a file, nor done by SetTimeStepGeometry
159  newTimeGeometry->UpdateBoundingBox();
160 
161  return newTimeGeometry;
162 }
TimeStepType CountTimeSteps() const override
Returns the number of time steps.
Standard implementation of BaseGeometry.
BaseGeometry::Pointer GetGeometryForTimeStep(TimeStepType timeStep) const override
Returns the geometry which corresponds to the given time step.
#define MITK_ERROR
Definition: mitkLogMacros.h:20
static TiXmlElement * ToXML(const ProportionalTimeGeometry *geometry)
Serialize given geometry to XML.
static Geometry3D::Pointer FromXML(TiXmlElement *node)
Create a Geometry3D from XML. Interprets only the format created by ToXML().
static TiXmlElement * ToXML(const Geometry3D *geometry)
Serialize given geometry to XML.
Target lexical_cast(const std::string &arg)
#define MITK_WARN
Definition: mitkLogMacros.h:19
virtual TimePointType GetStepDuration() const
mitk::ScalarType TimePointType
std::vcl_size_t TimeStepType
static T max(T x, T y)
Definition: svm.cpp:56
virtual TimePointType GetFirstTimePoint() const
static ProportionalTimeGeometry::Pointer FromXML(TiXmlElement *node)
Create a ProportionalTimeGeometry from XML. Interprets only the format created by ToXML()...