Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkGeometryDataIOTest.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 "mitkTestFixture.h"
14 #include "mitkTestingMacros.h"
15 
16 #include "mitkGeometry3D.h"
17 #include "mitkGeometryData.h"
19 
20 #include "mitkIOMimeTypes.h"
21 #include "mitkIOUtil.h"
30 class mitkGeometryDataIOTestSuite : public mitk::TestFixture
31 {
32  CPPUNIT_TEST_SUITE(mitkGeometryDataIOTestSuite);
33  MITK_TEST(StoreDefaultGeometry3D);
34  MITK_TEST(StoreImageGeometry);
35  MITK_TEST(StoreFrameOfReference);
36  MITK_TEST(StoreOrigin);
37  MITK_TEST(StoreSpacing);
38  MITK_TEST(StoreBounds);
39  MITK_TEST(StoreTransform);
40  MITK_TEST(StoreProportionalTimeGeometry);
41  CPPUNIT_TEST_SUITE_END();
42 
43  mitk::GeometryData::Pointer m_GeometryData;
46 
47  mitk::GeometryData::Pointer m_ReadGeometryData;
48  mitk::Geometry3D::Pointer m_ReadGeom3D;
49  mitk::ProportionalTimeGeometry::Pointer m_ReadProportionalTimeGeom;
50 
51 public:
52  void setUp() override
53  {
54  m_GeometryData = mitk::GeometryData::New();
55  m_Geom3D = mitk::Geometry3D::New();
56 
57  m_GeometryData->SetGeometry(m_Geom3D); // does copy!? doc says otherwise
58  // --> we reference and use the clone, not the original!
59  m_Geom3D = static_cast<mitk::Geometry3D *>(m_GeometryData->GetGeometry());
60 
61  m_TimeGeometry = dynamic_cast<mitk::ProportionalTimeGeometry *>(m_GeometryData->GetTimeGeometry());
62  CPPUNIT_ASSERT(m_TimeGeometry.IsNotNull());
63  }
64 
65  void tearDown() override
66  {
67  m_GeometryData = nullptr;
68  m_Geom3D = nullptr;
69  m_ReadGeometryData = nullptr;
70  m_ReadGeom3D = nullptr;
71  m_ReadProportionalTimeGeom = nullptr;
72  }
73 
74  void StoreDefaultGeometry3D()
75  {
76  // m_Geom3D already prepared in setUp()
77  ASSERT_Geometry3D_WriteReadLoop_Works();
78  }
79 
80  void StoreImageGeometry()
81  {
82  m_Geom3D->SetImageGeometry(true);
83  ASSERT_Geometry3D_WriteReadLoop_Works();
84 
85  m_Geom3D->SetImageGeometry(false);
86  ASSERT_Geometry3D_WriteReadLoop_Works();
87  }
88 
89  void StoreFrameOfReference()
90  {
91  m_Geom3D->SetFrameOfReferenceID(513);
92  ASSERT_Geometry3D_WriteReadLoop_Works();
93 
94  m_Geom3D->SetFrameOfReferenceID(std::numeric_limits<unsigned int>::max());
95  ASSERT_Geometry3D_WriteReadLoop_Works();
96  }
97 
98  void StoreOrigin()
99  {
100  mitk::Point3D origin;
102  m_Geom3D->SetOrigin(origin);
103  ASSERT_Geometry3D_WriteReadLoop_Works();
104 
106  m_Geom3D->SetOrigin(origin);
107  ASSERT_Geometry3D_WriteReadLoop_Works();
108  }
109 
110  void StoreSpacing()
111  {
112  mitk::Vector3D spacing;
113  // tempted to test with spacing of std::numeric_limits<mitk::ScalarType>::max()
114  // BUT that puts TinyXML into a pretty long loop counting the required numbers needed
115  // So we test a _big_ spacing
116  mitk::FillVector3D(spacing, 0.0000001, 0.0017, 918273645.18293746);
117  m_Geom3D->SetSpacing(spacing);
118  ASSERT_Geometry3D_WriteReadLoop_Works();
119 
120  // tempted to test negative spacings? they should be serialized, but
121  // there are assertions somewhere in the code that verify positive
122  // spacings, so we can skip this test.
123  }
124 
125  void StoreBounds()
126  {
129  bounds[1] = -52.723;
130  bounds[2] = -0.002;
131  bounds[3] = 918273645.18293746;
132  bounds[4] = -0.002;
133  bounds[5] = +52.723;
134  m_Geom3D->SetBounds(bounds);
135  ASSERT_Geometry3D_WriteReadLoop_Works();
136  }
137 
138  void StoreTransform()
139  {
140  mitk::ScalarType matrixCoeffs[9] = {0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8};
141 
142  mitk::AffineTransform3D::MatrixType matrix;
143  matrix.GetVnlMatrix().set(matrixCoeffs);
144 
145  mitk::AffineTransform3D::OffsetType offset;
146  offset[0] = -918273645.1829374; // don't want limits::min(), there is a minimal difference for this value.
147  // offset[1] = -0.0; // this causes problems with mitk::Equal
148  offset[1] = 0.0;
149  offset[2] = +918273645.1829374;
150 
151  mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New();
152  transform->SetMatrix(matrix);
153  transform->SetOffset(offset);
154  m_Geom3D->SetIndexToWorldTransform(transform);
155 
156  ASSERT_Geometry3D_WriteReadLoop_Works();
157  }
158 
159  void WriteAndRead_m_GeometryData()
160  {
161  // temp path
162  std::string tmpPath = mitk::IOUtil::CreateTemporaryDirectory("GeomDataIOTest_XXXXXX");
163 
164  // let IOUtil find a good file extension
165  std::string filename("geometrydata_geometry3d");
166  std::string extension(mitk::IOMimeTypes::GEOMETRY_DATA_MIMETYPE().GetExtensions().front());
167 
168  // don't specify the extension, expect that there is no other writer
169  // TODO Other than documented, Save does not add the extension. Anything missing in my MIMETYPE??
170  CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(m_GeometryData, tmpPath + "/" + filename + "." + extension));
171 
172  // read into member
173  std::vector<mitk::BaseData::Pointer> loadedData = mitk::IOUtil::Load(tmpPath + "/" + filename + "." + extension);
174  CPPUNIT_ASSERT_MESSAGE("IOUtil could read something (and just one)", loadedData.size() == 1);
175 
176  m_ReadGeometryData = dynamic_cast<mitk::GeometryData *>(loadedData.front().GetPointer());
177  CPPUNIT_ASSERT_MESSAGE("IOUtil could read _some_ GeometryData", m_ReadGeometryData.IsNotNull());
178 
179  m_ReadGeom3D = dynamic_cast<mitk::Geometry3D *>(m_ReadGeometryData->GetGeometry());
180  CPPUNIT_ASSERT_MESSAGE("IOUtil could read _some_ Geometry3D", m_ReadGeom3D.IsNotNull());
181 
182  m_ReadProportionalTimeGeom = dynamic_cast<mitk::ProportionalTimeGeometry *>(m_ReadGeometryData->GetTimeGeometry());
183  CPPUNIT_ASSERT_MESSAGE("IOUtil could read _some_ ProportionalTimeGeometry", m_ReadProportionalTimeGeom.IsNotNull());
184  }
185 
186  void ASSERT_Geometry3D_WriteReadLoop_Works()
187  {
188  WriteAndRead_m_GeometryData();
189  // Doc of mitk::Equal for BaseGeometry says
190  // "The function compares the spacing, origin, axis vectors, extents, the matrix of the
191  // IndexToWorldTransform(element wise), the bounding(element wise) and the ImageGeometry flag."
192  // This seems pretty much everything that we can have in a Geometry3D..
193  CPPUNIT_ASSERT_MESSAGE("Geometry3D > file > Geometry3D keeps geometry",
194  mitk::Equal(*m_Geom3D, *m_ReadGeom3D, 0.000001, true));
195  // Tolerance: Storing huge values 9.18274e+008 does not work at the precision of mitk::eps
196  // So the author of this test judged above tolerance sufficient. If more is
197  // required we need to inspect in more detail.
198  }
199 
200  void StoreProportionalTimeGeometry()
201  {
202  // Set Time Geometry
203  m_TimeGeometry->ClearAllGeometries(); // remove default filling from setUp();
204 
205  for (int t = 0; t < 4; ++t)
206  {
207  // add new time steps
209  vtkSmartPointer<vtkMatrix4x4> vtk_matrix = vtkSmartPointer<vtkMatrix4x4>::New();
210  for (int i = 0; i != 4; ++i)
211  {
212  for (int j = 0; j != 4; ++j)
213  {
214  vtk_matrix->SetElement(i, j, t + (i + j) / 8.0); // just insignificant values
215  }
216  }
217 
218  if (t % 2 == 0) // invert every second one
219  vtk_matrix->Invert();
220 
221  timestepGeometry->SetIndexToWorldTransformByVtkMatrix(vtk_matrix);
222  m_TimeGeometry->SetTimeStepGeometry(timestepGeometry, t);
223  }
224 
225  // time steps are handled as ScalarType, so use some negative values
226  m_TimeGeometry->SetFirstTimePoint(-5017.20);
227  m_TimeGeometry->SetStepDuration(2743.83);
228 
229  // fill m_GeometryData with something that has multiple time steps
230  ASSERT_ProportionalTimeGeometry_WriteReadLoop_Works();
231  }
232 
233  void ASSERT_ProportionalTimeGeometry_WriteReadLoop_Works()
234  {
235  WriteAndRead_m_GeometryData();
236 
237  CPPUNIT_ASSERT_MESSAGE("ProportionalTimeGeometry > file > ProportionalTimeGeometry keeps geometry",
238  mitk::Equal(*m_TimeGeometry, *m_ReadProportionalTimeGeom, 0.000001, true));
239  // Tolerance: Storing huge values 9.18274e+008 does not work at the precision of mitk::eps
240  // So the author of this test judged above tolerance sufficient. If more is
241  // required we need to inspect in more detail.
242  }
243 
244 }; // class
245 
246 MITK_TEST_SUITE_REGISTRATION(mitkGeometryDataIO)
Standard implementation of BaseGeometry.
MITK_TEST_SUITE_REGISTRATION(mitkImageToItk)
BoundingBoxType::BoundsArrayType BoundsArrayType
double ScalarType
#define MITK_TEST(TESTMETHOD)
Adds a test to the current test suite.
static Pointer New()
void FillVector3D(Tout &out, mitk::ScalarType x, mitk::ScalarType y, mitk::ScalarType z)
Definition: mitkArray.h:106
static Vector3D offset
Test fixture for parameterized tests.
static Pointer New()
static T max(T x, T y)
Definition: svm.cpp:56
Data class only having a BaseGeometry but not containing any specific data.
static std::string CreateTemporaryDirectory(const std::string &templateName="XXXXXX", std::string path=std::string())
Definition: mitkIOUtil.cpp:458
static T min(T x, T y)
Definition: svm.cpp:53
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.
static void Save(const mitk::BaseData *data, const std::string &path, bool setPathProperty=false)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:774
static CustomMimeType GEOMETRY_DATA_MIMETYPE()
static DataStorage::SetOfObjects::Pointer Load(const std::string &path, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback=nullptr)
Load a file into the given DataStorage.
Definition: mitkIOUtil.cpp:489