Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkPlanarFigureWriter.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 "mitkPlanarFigureWriter.h"
15 #include "mitkPlaneGeometry.h"
16 #include <tinyxml.h>
17 
19  : m_FileName(""),
20  m_FilePrefix(""),
21  m_FilePattern(""),
22  m_Extension(".pf"),
23  m_MimeType("application/MITK.PlanarFigure"),
24  m_Success(false)
25 {
26  this->SetNumberOfRequiredInputs(1);
27  this->SetNumberOfIndexedOutputs(0);
28  // this->SetNthOutput( 0, mitk::PlanarFigure::New().GetPointer() );
29 
30  m_CanWriteToMemory = true;
31 }
32 
34 {
35 }
36 
38 {
39  m_Success = false;
40 
41  if (!m_WriteToMemory && m_FileName.empty())
42  {
43  MITK_ERROR << "Could not write planar figures. File name is invalid";
44  throw std::invalid_argument("file name is empty");
45  }
46 
47  TiXmlDocument document;
48  auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
49  document.LinkEndChild(decl);
50 
51  auto version = new TiXmlElement("Version");
52  version->SetAttribute("Writer", __FILE__);
53  version->SetAttribute("CVSRevision", "$Revision: 17055 $");
54  version->SetAttribute("FileVersion", 1);
55  document.LinkEndChild(version);
56 
57  /* create xml element for each input */
58  for (unsigned int i = 0; i < this->GetNumberOfInputs(); ++i)
59  {
60  // Create root element for this PlanarFigure
61  InputType::Pointer pf = this->GetInput(i);
62  if (pf.IsNull())
63  continue;
64  auto pfElement = new TiXmlElement("PlanarFigure");
65  pfElement->SetAttribute("type", pf->GetNameOfClass());
66  document.LinkEndChild(pfElement);
67 
68  if (pf->GetNumberOfControlPoints() == 0)
69  continue;
70 
71  // PlanarFigure::VertexContainerType* vertices = pf->GetControlPoints();
72  // if (vertices == nullptr)
73  // continue;
74 
75  // Serialize property list of PlanarFigure
76  mitk::PropertyList::Pointer propertyList = pf->GetPropertyList();
77  mitk::PropertyList::PropertyMap::const_iterator it;
78  for (it = propertyList->GetMap()->begin(); it != propertyList->GetMap()->end(); ++it)
79  {
80  // Create seralizer for this property
81  const mitk::BaseProperty *prop = it->second;
82  std::string serializerName = std::string(prop->GetNameOfClass()) + "Serializer";
83  std::list<itk::LightObject::Pointer> allSerializers =
84  itk::ObjectFactoryBase::CreateAllInstance(serializerName.c_str());
85 
86  if (allSerializers.size() != 1)
87  {
88  // No or too many serializer(s) found, skip this property
89  continue;
90  }
91 
92  auto *serializer =
93  dynamic_cast<mitk::BasePropertySerializer *>(allSerializers.begin()->GetPointer());
94  if (serializer == nullptr)
95  {
96  // Serializer not valid; skip this property
97  }
98 
99  auto keyElement = new TiXmlElement("property");
100  keyElement->SetAttribute("key", it->first);
101  keyElement->SetAttribute("type", prop->GetNameOfClass());
102 
103  serializer->SetProperty(prop);
104  TiXmlElement *valueElement = nullptr;
105  try
106  {
107  valueElement = serializer->Serialize();
108  }
109  catch (...)
110  {
111  }
112 
113  if (valueElement == nullptr)
114  {
115  // Serialization failed; skip this property
116  continue;
117  }
118 
119  // Add value to property element
120  keyElement->LinkEndChild(valueElement);
121 
122  // Append serialized property to property list
123  pfElement->LinkEndChild(keyElement);
124  }
125 
126  // Serialize control points of PlanarFigure
127  auto controlPointsElement = new TiXmlElement("ControlPoints");
128  pfElement->LinkEndChild(controlPointsElement);
129  for (unsigned int i = 0; i < pf->GetNumberOfControlPoints(); i++)
130  {
131  auto vElement = new TiXmlElement("Vertex");
132  vElement->SetAttribute("id", i);
133  vElement->SetDoubleAttribute("x", pf->GetControlPoint(i)[0]);
134  vElement->SetDoubleAttribute("y", pf->GetControlPoint(i)[1]);
135  controlPointsElement->LinkEndChild(vElement);
136  }
137  auto geoElement = new TiXmlElement("Geometry");
138  const auto *planeGeo = dynamic_cast<const PlaneGeometry *>(pf->GetPlaneGeometry());
139  if (planeGeo != nullptr)
140  {
141  // Write parameters of IndexToWorldTransform of the PlaneGeometry
142  typedef mitk::Geometry3D::TransformType TransformType;
143  const TransformType *affineGeometry = planeGeo->GetIndexToWorldTransform();
144  const TransformType::ParametersType &parameters = affineGeometry->GetParameters();
145  auto vElement = new TiXmlElement("transformParam");
146  for (unsigned int i = 0; i < affineGeometry->GetNumberOfParameters(); ++i)
147  {
148  std::stringstream paramName;
149  paramName << "param" << i;
150  vElement->SetDoubleAttribute(paramName.str().c_str(), parameters.GetElement(i));
151  }
152  geoElement->LinkEndChild(vElement);
153 
154  // Write bounds of the PlaneGeometry
156  const BoundsArrayType &bounds = planeGeo->GetBounds();
157  vElement = new TiXmlElement("boundsParam");
158  for (unsigned int i = 0; i < 6; ++i)
159  {
160  std::stringstream boundName;
161  boundName << "bound" << i;
162  vElement->SetDoubleAttribute(boundName.str().c_str(), bounds.GetElement(i));
163  }
164  geoElement->LinkEndChild(vElement);
165 
166  // Write spacing and origin of the PlaneGeometry
167  Vector3D spacing = planeGeo->GetSpacing();
168  Point3D origin = planeGeo->GetOrigin();
169  geoElement->LinkEndChild(this->CreateXMLVectorElement("Spacing", spacing));
170  geoElement->LinkEndChild(this->CreateXMLVectorElement("Origin", origin));
171 
172  pfElement->LinkEndChild(geoElement);
173  }
174  }
175 
176  if (m_WriteToMemory)
177  {
178  // Declare a printer
179  TiXmlPrinter printer;
180  // attach it to the document you want to convert in to a std::string
181  document.Accept(&printer);
182 
183  // Create memory buffer and print tinyxmldocument there...
184  m_MemoryBufferSize = printer.Size() + 1;
186  strcpy(m_MemoryBuffer, printer.CStr());
187  }
188  else
189  {
190  if (document.SaveFile(m_FileName) == false)
191  {
192  MITK_ERROR << "Could not write planar figures to " << m_FileName << "\nTinyXML reports '" << document.ErrorDesc()
193  << "'";
194  throw std::ios_base::failure("Error during writing of planar figure xml file.");
195  }
196  }
197  m_Success = true;
198 }
199 
201 {
202  if (m_MemoryBuffer != nullptr)
203  {
204  delete[] m_MemoryBuffer;
205  }
206 }
207 
208 TiXmlElement *mitk::PlanarFigureWriter::CreateXMLVectorElement(const char *name, itk::FixedArray<mitk::ScalarType, 3> v)
209 {
210  auto vElement = new TiXmlElement(name);
211  vElement->SetDoubleAttribute("x", v.GetElement(0));
212  vElement->SetDoubleAttribute("y", v.GetElement(1));
213  vElement->SetDoubleAttribute("z", v.GetElement(2));
214  return vElement;
215 }
216 
217 void mitk::PlanarFigureWriter::ResizeInputs(const unsigned int &num)
218 {
219  // unsigned int prevNum = this->GetNumberOfInputs();
220  this->SetNumberOfIndexedInputs(num);
221  // for ( unsigned int i = prevNum; i < num; ++i )
222  //{
223  // this->SetNthInput( i, mitk::PlanarFigure::New().GetPointer() );
224  //}
225 }
226 
228 {
229  this->ProcessObject::SetNthInput(0, PlanarFigure);
230 }
231 
233 {
234  if (id >= this->GetNumberOfInputs())
235  this->ResizeInputs(id + 1);
236  this->ProcessObject::SetNthInput(id, PlanarFigure);
237 }
238 
240 {
241  if (this->GetNumberOfInputs() < 1)
242  return nullptr;
243  else
244  return dynamic_cast<InputType *>(this->GetInput(0));
245 }
246 
248 {
249  return dynamic_cast<InputType *>(this->ProcessObject::GetInput(num));
250 }
251 
253 {
254  if (input == nullptr)
255  return false;
256 
257  mitk::BaseData *data = input->GetData();
258  if (data == nullptr)
259  return false;
260 
262  if (PlanarFigure.IsNull())
263  return false;
264  // add code for special subclasses here
265  return true;
266 }
267 
269 {
270  if (this->CanWriteDataType(input))
271  this->ProcessObject::SetNthInput(0, dynamic_cast<mitk::PlanarFigure *>(input->GetData()));
272 }
273 
275 {
277 }
278 
280 {
281  return m_MimeType;
282 }
283 
285 {
286  std::vector<std::string> possibleFileExtensions;
287  possibleFileExtensions.push_back(m_Extension);
288  return possibleFileExtensions;
289 }
290 
292 {
293  return m_Extension;
294 }
BoundingBoxType::BoundsArrayType BoundsArrayType
void ReleaseMemory() override
CAUTION: It&#39;s up to the user to call this function to release the memory buffer after use in case the...
Base of all data objects.
Definition: mitkBaseData.h:37
virtual void ResizeInputs(const unsigned int &num)
#define MITK_ERROR
Definition: mitkLogMacros.h:20
std::string GetFileExtension() override
Return the extension to be added to the filename.
unsigned int m_MemoryBufferSize
std::string GetWritenMIMEType() override
Return the MimeType of the saved File.
GeometryTransformHolder::TransformType TransformType
std::vector< std::string > GetPossibleFileExtensions() override
Return the possible file extensions for the data type associated with the writer. ...
static const char * GetStaticNameOfClass()
Definition: mitkBaseData.h:41
bool CanWriteDataType(DataNode *) override
Check if the Writer can write the Content of the.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
Abstract base class for properties.
TiXmlElement * CreateXMLVectorElement(const char *name, itk::FixedArray< mitk::ScalarType, 3 > v)
creates a TinyXML element that contains x, y, and z values
Base class for objects that serialize BaseProperty types.
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
void SetInput(InputType *input)
Describes a two-dimensional, rectangular plane.
std::string GetSupportedBaseData() const override
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
mitk::AffineTransform3D * GetIndexToWorldTransform()
Get the transformation used to convert from index to world coordinates.
BoundingBoxType::BoundsArrayType BoundsArrayType