Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
mitkPointSetReaderService.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 // MITK
15 #include "mitkGeometry3DToXML.h"
16 #include "mitkIOMimeTypes.h"
18 
19 // STL
20 #include <fstream>
21 #include <iostream>
22 #include <mitkLocaleSwitch.h>
23 
24 #include <tinyxml.h>
25 
27  : AbstractFileReader(CustomMimeType(IOMimeTypes::POINTSET_MIMETYPE()), "MITK Point Set Reader")
28 {
30 }
31 
33 {
34 }
35 
36 std::vector<itk::SmartPointer<mitk::BaseData>> mitk::PointSetReaderService::Read()
37 {
38  // Switch the current locale to "C"
39  LocaleSwitch localeSwitch("C");
40 
41  std::vector<itk::SmartPointer<mitk::BaseData>> result;
42 
43  InputStream stream(this);
44 
45  TiXmlDocument doc;
46  stream >> doc;
47  if (!doc.Error())
48  {
49  TiXmlHandle docHandle(&doc);
50  // unsigned int pointSetCounter(0);
51  for (TiXmlElement *currentPointSetElement =
52  docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement();
53  currentPointSetElement != nullptr;
54  currentPointSetElement = currentPointSetElement->NextSiblingElement())
55  {
57 
58  // time geometry assembled for addition after all points
59  // else the SetPoint method would already transform the points that we provide it
61 
62  if (currentPointSetElement->FirstChildElement("time_series") != nullptr)
63  {
64  for (TiXmlElement *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement();
65  currentTimeSeries != nullptr;
66  currentTimeSeries = currentTimeSeries->NextSiblingElement())
67  {
68  unsigned int currentTimeStep(0);
69  TiXmlElement *currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id");
70 
71  currentTimeStep = atoi(currentTimeSeriesID->GetText());
72 
73  timeGeometry->Expand(currentTimeStep + 1); // expand (default to identity) in any case
74  TiXmlElement *geometryElem = currentTimeSeries->FirstChildElement("Geometry3D");
75  if (geometryElem)
76  {
77  Geometry3D::Pointer geometry = Geometry3DToXML::FromXML(geometryElem);
78  if (geometry.IsNotNull())
79  {
80  timeGeometry->SetTimeStepGeometry(geometry, currentTimeStep);
81  }
82  else
83  {
84  MITK_ERROR << "Could not deserialize Geometry3D element.";
85  }
86  }
87  else
88  {
89  MITK_WARN << "Fallback to legacy behavior: defining PointSet geometry as identity";
90  }
91 
92  newPointSet = this->ReadPoints(newPointSet, currentTimeSeries, currentTimeStep);
93  }
94  }
95  else
96  {
97  newPointSet = this->ReadPoints(newPointSet, currentPointSetElement, 0);
98  }
99 
100  newPointSet->SetTimeGeometry(timeGeometry);
101 
102  result.push_back(newPointSet.GetPointer());
103  }
104  }
105  else
106  {
107  mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc();
108  }
109 
110  return result;
111 }
112 
113 mitk::BaseGeometry::Pointer mitk::PointSetReaderService::ReadGeometry(TiXmlElement *parentElement)
114 {
115  TiXmlElement *geometryElem = parentElement->FirstChildElement("geometry3d");
116  if (!geometryElem)
117  return nullptr;
118 
119  // data to generate
120  AffineTransform3D::MatrixType matrix;
121  AffineTransform3D::OffsetType offset;
122  bool isImageGeometry(false);
123  unsigned int frameOfReferenceID(0);
125 
126  bool somethingMissing(false);
127 
128  // find data in xml structure
129  TiXmlElement *imageGeometryElem = geometryElem->FirstChildElement("image_geometry");
130  if (imageGeometryElem)
131  {
132  std::string igs = imageGeometryElem->GetText();
133  isImageGeometry = igs == "true" || igs == "TRUE" || igs == "1";
134  }
135  else
136  somethingMissing = true;
137 
138  TiXmlElement *frameOfReferenceElem = geometryElem->FirstChildElement("frame_of_reference_id");
139  if (frameOfReferenceElem)
140  {
141  frameOfReferenceID = atoi(frameOfReferenceElem->GetText());
142  }
143  else
144  somethingMissing = true;
145 
146  TiXmlElement *indexToWorldElem = geometryElem->FirstChildElement("index_to_world");
147  if (indexToWorldElem)
148  {
149  TiXmlElement *matrixElem = indexToWorldElem->FirstChildElement("matrix3x3");
150  TiXmlElement *offsetElem = indexToWorldElem->FirstChildElement("offset");
151  if (indexToWorldElem && offsetElem)
152  {
153  TiXmlElement *col0 = matrixElem->FirstChildElement("column_0");
154  TiXmlElement *col1 = matrixElem->FirstChildElement("column_1");
155  TiXmlElement *col2 = matrixElem->FirstChildElement("column_2");
156 
157  if (col0 && col1 && col2)
158  {
159  somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("x", &matrix[0][0]);
160  somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("y", &matrix[1][0]);
161  somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("z", &matrix[2][0]);
162 
163  somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("x", &matrix[0][1]);
164  somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("y", &matrix[1][1]);
165  somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("z", &matrix[2][1]);
166 
167  somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("x", &matrix[0][2]);
168  somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("y", &matrix[1][2]);
169  somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("z", &matrix[2][2]);
170  }
171  else
172  somethingMissing = true;
173 
174  somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("x", &offset[0]);
175  somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("y", &offset[1]);
176  somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("z", &offset[2]);
177  }
178  else
179  somethingMissing = true;
180 
181  TiXmlElement *boundsElem = geometryElem->FirstChildElement("bounds");
182  if (boundsElem)
183  {
184  TiXmlElement *minBoundsElem = boundsElem->FirstChildElement("min");
185  TiXmlElement *maxBoundsElem = boundsElem->FirstChildElement("max");
186 
187  if (minBoundsElem && maxBoundsElem)
188  {
189  somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("x", &bounds[0]);
190  somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("y", &bounds[2]);
191  somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("z", &bounds[4]);
192 
193  somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("x", &bounds[1]);
194  somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("y", &bounds[3]);
195  somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("z", &bounds[5]);
196  }
197  else
198  somethingMissing = true;
199  }
200  else
201  somethingMissing = true;
202  }
203  else
204  somethingMissing = true;
205 
206  if (somethingMissing)
207  {
208  MITK_ERROR << "XML structure of geometry inside a PointSet file broken. Refusing to build Geometry3D";
209  return nullptr;
210  }
211  else
212  {
214  g->SetImageGeometry(isImageGeometry);
215  g->SetFrameOfReferenceID(frameOfReferenceID);
216  g->SetBounds(bounds);
217 
218  AffineTransform3D::Pointer transform = AffineTransform3D::New();
219  transform->SetMatrix(matrix);
220  transform->SetOffset(offset);
221 
222  g->SetIndexToWorldTransform(transform);
223 
224  return g.GetPointer();
225  }
226 }
227 
228 mitk::PointSet::Pointer mitk::PointSetReaderService::ReadPoints(mitk::PointSet::Pointer newPointSet,
229  TiXmlElement *currentTimeSeries,
230  unsigned int currentTimeStep)
231 {
232  if (currentTimeSeries->FirstChildElement("point") != nullptr)
233  {
234  for (TiXmlElement *currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); currentPoint != nullptr;
235  currentPoint = currentPoint->NextSiblingElement())
236  {
237  unsigned int id(0);
238  auto spec((mitk::PointSpecificationType)0);
239  double x(0.0);
240  double y(0.0);
241  double z(0.0);
242 
243  id = atoi(currentPoint->FirstChildElement("id")->GetText());
244  if (currentPoint->FirstChildElement("specification") != nullptr)
245  {
246  spec = (mitk::PointSpecificationType)atoi(currentPoint->FirstChildElement("specification")->GetText());
247  }
248  x = atof(currentPoint->FirstChildElement("x")->GetText());
249  y = atof(currentPoint->FirstChildElement("y")->GetText());
250  z = atof(currentPoint->FirstChildElement("z")->GetText());
251 
252  mitk::Point3D point;
253  mitk::FillVector3D(point, x, y, z);
254  newPointSet->SetPoint(id, point, spec, currentTimeStep);
255  }
256  }
257  else
258  {
259  if (currentTimeStep != newPointSet->GetTimeSteps() + 1)
260  {
261  newPointSet->Expand(currentTimeStep + 1); // expand time step series with empty time step
262  }
263  }
264  return newPointSet;
265 }
266 
268  : mitk::AbstractFileReader(other)
269 {
270 }
271 
272 mitk::PointSetReaderService *mitk::PointSetReaderService::Clone() const
273 {
274  return new mitk::PointSetReaderService(*this);
275 }
The IOMimeTypes class.
BoundingBoxType::BoundsArrayType BoundsArrayType
#define MITK_ERROR
Definition: mitkLogMacros.h:20
static Pointer New()
static Geometry3D::Pointer FromXML(TiXmlElement *node)
Create a Geometry3D from XML. Interprets only the format created by ToXML().
static Pointer New()
void FillVector3D(Tout &out, mitk::ScalarType x, mitk::ScalarType y, mitk::ScalarType z)
Definition: mitkArray.h:106
The CustomMimeType class represents a custom mime-type which may be registered as a service object...
static Vector3D offset
us::ServiceRegistration< IFileReader > RegisterService(us::ModuleContext *context=us::GetModuleContext())
#define MITK_WARN
Definition: mitkLogMacros.h:19
Convenience class to temporarily change the current locale.
#define mitkThrow()
std::vector< itk::SmartPointer< BaseData > > Read() override
Reads a path or stream and creates a list of BaseData objects.
Base class for creating mitk::BaseData objects from files or streams.
PointSpecificationType
enumeration of the type a point can be
Definition: mitkPoint.h:26