Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.