Medical Imaging Interaction Toolkit  2018.4.99-064ad45c
Medical Imaging Interaction Toolkit
mitkGeometry3DToXML.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 
13 #include "mitkGeometry3DToXML.h"
14 
15 #include <mitkLexicalCast.h>
16 
17 #include <tinyxml.h>
18 
19 TiXmlElement *mitk::Geometry3DToXML::ToXML(const Geometry3D *geom3D)
20 {
21  assert(geom3D);
22 
23  // really serialize
24  const AffineTransform3D *transform = geom3D->GetIndexToWorldTransform();
25 
26  // get transform parameters that would need to be serialized
27  AffineTransform3D::MatrixType matrix = transform->GetMatrix();
28  AffineTransform3D::OffsetType offset = transform->GetOffset();
29 
30  bool isImageGeometry = geom3D->GetImageGeometry();
31  BaseGeometry::BoundsArrayType bounds = geom3D->GetBounds();
32 
33  // create XML file
34  // construct XML tree describing the geometry
35  auto *geomElem = new TiXmlElement("Geometry3D");
36  geomElem->SetAttribute("ImageGeometry", isImageGeometry ? "true" : "false");
37  geomElem->SetAttribute("FrameOfReferenceID", geom3D->GetFrameOfReferenceID());
38 
39  // coefficients are matrix[row][column]!
40  auto *matrixElem = new TiXmlElement("IndexToWorld");
41  matrixElem->SetAttribute("type", "Matrix3x3");
42  matrixElem->SetAttribute("m_0_0", boost::lexical_cast<std::string>(matrix[0][0]));
43  matrixElem->SetAttribute("m_0_1", boost::lexical_cast<std::string>(matrix[0][1]));
44  matrixElem->SetAttribute("m_0_2", boost::lexical_cast<std::string>(matrix[0][2]));
45  matrixElem->SetAttribute("m_1_0", boost::lexical_cast<std::string>(matrix[1][0]));
46  matrixElem->SetAttribute("m_1_1", boost::lexical_cast<std::string>(matrix[1][1]));
47  matrixElem->SetAttribute("m_1_2", boost::lexical_cast<std::string>(matrix[1][2]));
48  matrixElem->SetAttribute("m_2_0", boost::lexical_cast<std::string>(matrix[2][0]));
49  matrixElem->SetAttribute("m_2_1", boost::lexical_cast<std::string>(matrix[2][1]));
50  matrixElem->SetAttribute("m_2_2", boost::lexical_cast<std::string>(matrix[2][2]));
51  geomElem->LinkEndChild(matrixElem);
52 
53  auto *offsetElem = new TiXmlElement("Offset");
54  offsetElem->SetAttribute("type", "Vector3D");
55  offsetElem->SetAttribute("x", boost::lexical_cast<std::string>(offset[0]));
56  offsetElem->SetAttribute("y", boost::lexical_cast<std::string>(offset[1]));
57  offsetElem->SetAttribute("z", boost::lexical_cast<std::string>(offset[2]));
58  geomElem->LinkEndChild(offsetElem);
59 
60  auto *boundsElem = new TiXmlElement("Bounds");
61  auto *boundsMinElem = new TiXmlElement("Min");
62  boundsMinElem->SetAttribute("type", "Vector3D");
63  boundsMinElem->SetAttribute("x", boost::lexical_cast<std::string>(bounds[0]));
64  boundsMinElem->SetAttribute("y", boost::lexical_cast<std::string>(bounds[2]));
65  boundsMinElem->SetAttribute("z", boost::lexical_cast<std::string>(bounds[4]));
66  boundsElem->LinkEndChild(boundsMinElem);
67  auto *boundsMaxElem = new TiXmlElement("Max");
68  boundsMaxElem->SetAttribute("type", "Vector3D");
69  boundsMaxElem->SetAttribute("x", boost::lexical_cast<std::string>(bounds[1]));
70  boundsMaxElem->SetAttribute("y", boost::lexical_cast<std::string>(bounds[3]));
71  boundsMaxElem->SetAttribute("z", boost::lexical_cast<std::string>(bounds[5]));
72  boundsElem->LinkEndChild(boundsMaxElem);
73  geomElem->LinkEndChild(boundsElem);
74 
75  return geomElem;
76 }
77 
79 {
80  if (!geometryElement)
81  {
82  MITK_ERROR << "Cannot deserialize Geometry3D from nullptr.";
83  return nullptr;
84  }
85 
86  AffineTransform3D::MatrixType matrix;
87  AffineTransform3D::OffsetType offset;
88  bool isImageGeometry(false);
89  unsigned int frameOfReferenceID(0);
91 
92  if (TIXML_SUCCESS != geometryElement->QueryUnsignedAttribute("FrameOfReferenceID", &frameOfReferenceID))
93  {
94  MITK_WARN << "Missing FrameOfReference for Geometry3D.";
95  }
96 
97  if (TIXML_SUCCESS != geometryElement->QueryBoolAttribute("ImageGeometry", &isImageGeometry))
98  {
99  MITK_WARN << "Missing bool ImageGeometry for Geometry3D.";
100  }
101 
102  // matrix
103  if (TiXmlElement *matrixElem = geometryElement->FirstChildElement("IndexToWorld")->ToElement())
104  {
105  bool matrixComplete = true;
106  for (unsigned int r = 0; r < 3; ++r)
107  {
108  for (unsigned int c = 0; c < 3; ++c)
109  {
110  std::stringstream element_namer;
111  element_namer << "m_" << r << "_" << c;
112 
113  std::string string_value;
114  if (TIXML_SUCCESS == matrixElem->QueryStringAttribute(element_namer.str().c_str(), &string_value))
115  {
116  try
117  {
118  matrix[r][c] = boost::lexical_cast<double>(string_value);
119  }
120  catch ( const boost::bad_lexical_cast &e )
121  {
122  MITK_ERROR << "Could not parse '" << string_value << "' as number: " << e.what();
123  return nullptr;
124  }
125  }
126  else
127  {
128  matrixComplete = false;
129  }
130  }
131  }
132 
133  if (!matrixComplete)
134  {
135  MITK_ERROR << "Could not parse all Geometry3D matrix coefficients!";
136  return nullptr;
137  }
138  }
139  else
140  {
141  MITK_ERROR << "Parse error: expected Matrix3x3 child below Geometry3D node";
142  return nullptr;
143  }
144 
145  // offset
146  if (TiXmlElement *offsetElem = geometryElement->FirstChildElement("Offset")->ToElement())
147  {
148  bool vectorComplete = true;
149  std::string offset_string[3];
150  vectorComplete &= TIXML_SUCCESS == offsetElem->QueryStringAttribute("x", &offset_string[0]);
151  vectorComplete &= TIXML_SUCCESS == offsetElem->QueryStringAttribute("y", &offset_string[1]);
152  vectorComplete &= TIXML_SUCCESS == offsetElem->QueryStringAttribute("z", &offset_string[2]);
153 
154  if (!vectorComplete)
155  {
156  MITK_ERROR << "Could not parse complete Geometry3D offset!";
157  return nullptr;
158  }
159 
160  for (unsigned int d = 0; d < 3; ++d)
161  try
162  {
163  offset[d] = boost::lexical_cast<double>(offset_string[d]);
164  }
165  catch ( const boost::bad_lexical_cast &e )
166  {
167  MITK_ERROR << "Could not parse '" << offset_string[d] << "' as number: " << e.what();
168  return nullptr;
169  }
170  }
171  else
172  {
173  MITK_ERROR << "Parse error: expected Offset3D child below Geometry3D node";
174  return nullptr;
175  }
176 
177  // bounds
178  if (TiXmlElement *boundsElem = geometryElement->FirstChildElement("Bounds")->ToElement())
179  {
180  bool vectorsComplete(true);
181  std::string bounds_string[6];
182  if (TiXmlElement *minElem = boundsElem->FirstChildElement("Min")->ToElement())
183  {
184  vectorsComplete &= TIXML_SUCCESS == minElem->QueryStringAttribute("x", &bounds_string[0]);
185  vectorsComplete &= TIXML_SUCCESS == minElem->QueryStringAttribute("y", &bounds_string[2]);
186  vectorsComplete &= TIXML_SUCCESS == minElem->QueryStringAttribute("z", &bounds_string[4]);
187  }
188  else
189  {
190  vectorsComplete = false;
191  }
192 
193  if (TiXmlElement *maxElem = boundsElem->FirstChildElement("Max")->ToElement())
194  {
195  vectorsComplete &= TIXML_SUCCESS == maxElem->QueryStringAttribute("x", &bounds_string[1]);
196  vectorsComplete &= TIXML_SUCCESS == maxElem->QueryStringAttribute("y", &bounds_string[3]);
197  vectorsComplete &= TIXML_SUCCESS == maxElem->QueryStringAttribute("z", &bounds_string[5]);
198  }
199  else
200  {
201  vectorsComplete = false;
202  }
203 
204  if (!vectorsComplete)
205  {
206  MITK_ERROR << "Could not parse complete Geometry3D bounds!";
207  return nullptr;
208  }
209 
210  for (unsigned int d = 0; d < 6; ++d)
211  try
212  {
213  bounds[d] = boost::lexical_cast<double>(bounds_string[d]);
214  }
215  catch ( const boost::bad_lexical_cast &e )
216  {
217  MITK_ERROR << "Could not parse '" << bounds_string[d] << "' as number: " << e.what();
218  return nullptr;
219  }
220  }
221 
222  // build GeometryData from matrix/offset
223  AffineTransform3D::Pointer newTransform = AffineTransform3D::New();
224  newTransform->SetMatrix(matrix);
225  newTransform->SetOffset(offset);
226 
227  Geometry3D::Pointer newGeometry = Geometry3D::New();
228  newGeometry->SetFrameOfReferenceID(frameOfReferenceID);
229  newGeometry->SetImageGeometry(isImageGeometry);
230 
231  newGeometry->SetIndexToWorldTransform(newTransform);
232 
233  newGeometry->SetBounds(bounds);
234 
235  return newGeometry;
236 }
virtual bool GetImageGeometry() const
Is this an ImageGeometry?
Standard implementation of BaseGeometry.
BoundingBoxType::BoundsArrayType BoundsArrayType
#define MITK_ERROR
Definition: mitkLogMacros.h:20
static Geometry3D::Pointer FromXML(TiXmlElement *node)
Create a Geometry3D from XML. Interprets only the format created by ToXML().
static Pointer New()
static TiXmlElement * ToXML(const Geometry3D *geometry)
Serialize given geometry to XML.
static Vector3D offset
Target lexical_cast(const std::string &arg)
#define MITK_WARN
Definition: mitkLogMacros.h:19
itk::AffineGeometryFrame< ScalarType, 3 >::TransformType AffineTransform3D
virtual unsigned int GetFrameOfReferenceID() const
Get the DICOM FrameOfReferenceID referring to the used world coordinate system.
const BoundsArrayType GetBounds() const
mitk::AffineTransform3D * GetIndexToWorldTransform()
Get the transformation used to convert from index to world coordinates.