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