Line data Source code
1 : /**
2 : * @file test_StrongTypes.cpp
3 : *
4 : * @brief Test for Strong type classes
5 : *
6 : * @author David Frank - initial code
7 : */
8 :
9 : #include "doctest/doctest.h"
10 : #include "StrongTypes.h"
11 :
12 : using namespace elsa;
13 : using namespace doctest;
14 :
15 : TEST_SUITE_BEGIN("core");
16 :
17 4 : TEST_CASE("StrongTypes: Testing RotationAngles")
18 : {
19 :
20 : using namespace geometry;
21 : using namespace geometry::detail;
22 :
23 5 : GIVEN("A 1D RotationAngles")
24 : {
25 1 : RotationAngles<1> angle{Degree{90}};
26 :
27 1 : THEN("The value and size are correct") { CHECK_EQ(angle[0], Radian{pi_t / 2}); }
28 : }
29 :
30 5 : GIVEN("A 2D RotationAngles")
31 : {
32 1 : RotationAngles<2> angle{Degree{90}, Radian{pi_t / 4}};
33 :
34 2 : THEN("The value and size are correct")
35 : {
36 1 : CHECK_EQ(angle[0], Radian{pi_t / 2});
37 1 : CHECK_EQ(angle[1], Radian{pi_t / 4});
38 : }
39 : }
40 :
41 5 : GIVEN("A 3D RotationAngles")
42 : {
43 1 : RotationAngles<3> angle{Degree{90}, Radian{pi_t / 4}, Degree{180}};
44 :
45 2 : THEN("The value and size are correct")
46 : {
47 1 : CHECK_EQ(angle[0], Radian{pi_t / 2});
48 1 : CHECK_EQ(angle[1], Radian{pi_t / 4});
49 1 : CHECK_EQ(angle[2], Radian{pi_t});
50 : }
51 : }
52 :
53 5 : GIVEN("A RotationAngles3D")
54 : {
55 1 : RotationAngles3D angle{Degree{90}, Radian{pi_t / 4}, Degree{180}};
56 :
57 2 : THEN("The value and size are correct")
58 : {
59 1 : auto [g, b, a] = angle;
60 :
61 1 : CHECK_EQ(angle[0], Radian{pi_t / 2});
62 1 : CHECK_EQ(angle.gamma(), Radian{pi_t / 2});
63 1 : CHECK_EQ(g, Radian{pi_t / 2});
64 :
65 1 : CHECK_EQ(angle[1], Radian{pi_t / 4});
66 1 : CHECK_EQ(angle.beta(), Radian{pi_t / 4});
67 1 : CHECK_EQ(b, Radian{pi_t / 4});
68 :
69 1 : CHECK_EQ(angle[2], Radian{pi_t});
70 1 : CHECK_EQ(angle.alpha(), Radian{pi_t});
71 1 : CHECK_EQ(a, Radian{pi_t});
72 : }
73 : }
74 4 : }
75 :
76 5 : TEST_CASE("StrongTypes: Testing StaticRealVector")
77 : {
78 : using namespace geometry;
79 : using namespace geometry::detail;
80 :
81 6 : GIVEN("A default constructed StaticRealVector")
82 : {
83 2 : StaticRealVector<0> vec;
84 :
85 2 : THEN("The Eigen Vector is of size 0")
86 : {
87 1 : auto eigenVec = vec.get();
88 1 : REQUIRE_EQ(eigenVec.size(), 0);
89 : }
90 : }
91 :
92 6 : GIVEN("A 1D StaticRealVector")
93 : {
94 2 : StaticRealVector<1> vec{1};
95 :
96 2 : THEN("The value and size are correct")
97 : {
98 1 : auto eigenVec = vec.get();
99 1 : CHECK_EQ(eigenVec.size(), 1);
100 :
101 1 : CHECK_EQ(vec[0], Approx(1));
102 : }
103 : }
104 :
105 6 : GIVEN("A 2D StaticRealVector")
106 : {
107 2 : StaticRealVector<2> vec{1, 2};
108 :
109 2 : THEN("The value and size are correct")
110 : {
111 1 : auto eigenVec = vec.get();
112 1 : CHECK_EQ(eigenVec.size(), 2);
113 :
114 1 : CHECK_EQ(vec[0], Approx(1));
115 1 : CHECK_EQ(vec[1], Approx(2));
116 : }
117 : }
118 :
119 6 : GIVEN("A 3D StaticRealVector")
120 : {
121 2 : StaticRealVector<3> vec{1, 2, 3};
122 :
123 2 : THEN("The value and size are correct")
124 : {
125 1 : auto eigenVec = vec.get();
126 1 : CHECK_EQ(eigenVec.size(), 3);
127 :
128 1 : CHECK_EQ(vec[0], Approx(1));
129 1 : CHECK_EQ(vec[1], Approx(2));
130 1 : CHECK_EQ(vec[2], Approx(3));
131 : }
132 : }
133 :
134 6 : GIVEN("A 4D StaticRealVector")
135 : {
136 2 : StaticRealVector<4> vec{1, 2, 3, 6};
137 :
138 2 : THEN("The value and size are correct")
139 : {
140 1 : auto eigenVec = vec.get();
141 1 : CHECK_EQ(eigenVec.size(), 4);
142 :
143 1 : CHECK_EQ(vec[0], Approx(1));
144 1 : CHECK_EQ(vec[1], Approx(2));
145 1 : CHECK_EQ(vec[2], Approx(3));
146 1 : CHECK_EQ(vec[3], Approx(6));
147 : }
148 : }
149 5 : }
150 :
151 5 : TEST_CASE("StrongTypes: Testing GeometryData")
152 : {
153 : using namespace geometry;
154 : using namespace geometry::detail;
155 :
156 6 : GIVEN("A default constructed GeometryData")
157 : {
158 2 : GeometryData<0> data;
159 :
160 2 : THEN("The Eigen Vector is of size 0")
161 : {
162 1 : CHECK_EQ(data.getSpacing().size(), 0);
163 1 : CHECK_EQ(data.getLocationOfOrigin().size(), 0);
164 : }
165 : }
166 :
167 7 : GIVEN("A GeometryData for 1D data")
168 : {
169 6 : GeometryData data{Spacing1D{1}, OriginShift1D{0}};
170 :
171 3 : THEN("Spacing and Origin is of correct size and correct values")
172 : {
173 1 : CHECK_EQ(data.getSpacing().size(), 1);
174 1 : CHECK_EQ(data.getSpacing()[0], Approx(1));
175 :
176 1 : CHECK_EQ(data.getLocationOfOrigin().size(), 1);
177 1 : CHECK_EQ(data.getLocationOfOrigin()[0], Approx(0));
178 : }
179 :
180 3 : THEN("We can construct it from coefficients")
181 : {
182 1 : auto coeffs = IndexVector_t::Constant(1, 5);
183 :
184 2 : GeometryData<1> data2{Size1D{coeffs}};
185 :
186 1 : CHECK_EQ(data2.getSpacing().size(), 1);
187 1 : CHECK_EQ(data2.getSpacing()[0], Approx(1));
188 :
189 1 : CHECK_EQ(data2.getLocationOfOrigin().size(), 1);
190 1 : CHECK_EQ(data2.getLocationOfOrigin()[0], Approx(2.5));
191 : }
192 : }
193 :
194 7 : GIVEN("A GeometryData for 2D data")
195 : {
196 6 : GeometryData data{Spacing2D{1, 0.5}, OriginShift2D{0, 0.2}};
197 :
198 3 : THEN("Spacing and Origin is of correct size and correct values")
199 : {
200 1 : CHECK_EQ(data.getSpacing().size(), 2);
201 1 : CHECK_EQ(data.getSpacing()[0], Approx(1));
202 1 : CHECK_EQ(data.getSpacing()[1], Approx(0.5));
203 :
204 1 : CHECK_EQ(data.getLocationOfOrigin().size(), 2);
205 1 : CHECK_EQ(data.getLocationOfOrigin()[0], Approx(0));
206 1 : CHECK_EQ(data.getLocationOfOrigin()[1], Approx(0.2));
207 : }
208 :
209 3 : THEN("We can construct it from coefficients")
210 : {
211 1 : auto coeffs = IndexVector_t::Constant(2, 5);
212 :
213 2 : GeometryData<2> data2{Size2D{coeffs}, Spacing2D{2, 2}};
214 :
215 1 : CHECK_EQ(data2.getSpacing().size(), 2);
216 1 : CHECK_EQ(data2.getSpacing()[0], Approx(2));
217 1 : CHECK_EQ(data2.getSpacing()[1], Approx(2));
218 :
219 1 : CHECK_EQ(data2.getLocationOfOrigin().size(), 2);
220 1 : CHECK_EQ(data2.getLocationOfOrigin()[0], Approx(5));
221 1 : CHECK_EQ(data2.getLocationOfOrigin()[1], Approx(5));
222 : }
223 : }
224 5 : }
225 :
226 5 : TEST_CASE("StrongTypes: Testing VolumeData")
227 : {
228 : using namespace geometry;
229 :
230 6 : GIVEN("Size coefficients for 2D")
231 : {
232 2 : IndexVector_t size(2);
233 1 : size << 10, 10;
234 :
235 2 : THEN("Then Spacing and location of origin is calculated correctly")
236 : {
237 2 : VolumeData2D volData{Size2D{size}};
238 :
239 1 : CHECK_EQ(volData.getSpacing().size(), 2);
240 1 : CHECK_EQ(volData.getSpacing()[0], Approx(1));
241 1 : CHECK_EQ(volData.getSpacing()[1], Approx(1));
242 :
243 1 : CHECK_EQ(volData.getLocationOfOrigin().size(), 2);
244 1 : CHECK_EQ(volData.getLocationOfOrigin()[0], Approx(5));
245 1 : CHECK_EQ(volData.getLocationOfOrigin()[1], Approx(5));
246 : }
247 : }
248 :
249 7 : GIVEN("Size coefficients and Spacing for 2D")
250 : {
251 4 : IndexVector_t size(2);
252 2 : size << 10, 10;
253 :
254 4 : RealVector_t spacing(2);
255 2 : spacing << 0.5, 2;
256 :
257 3 : THEN("Then Spacing and location of origin is calculated correctly")
258 : {
259 2 : VolumeData2D volData{Size2D{size}, Spacing2D{spacing}};
260 :
261 1 : CHECK_EQ(volData.getSpacing().size(), 2);
262 1 : CHECK_EQ(volData.getSpacing()[0], Approx(0.5));
263 1 : CHECK_EQ(volData.getSpacing()[1], Approx(2));
264 :
265 1 : CHECK_EQ(volData.getLocationOfOrigin().size(), 2);
266 1 : CHECK_EQ(volData.getLocationOfOrigin()[0], Approx(2.5));
267 1 : CHECK_EQ(volData.getLocationOfOrigin()[1], Approx(10));
268 : }
269 3 : THEN("Structured bindings produce correct results")
270 : {
271 2 : auto [sp, o] = VolumeData2D{Size2D{size}, Spacing2D{spacing}};
272 :
273 1 : CHECK_EQ(sp.size(), 2);
274 1 : CHECK_EQ(sp[0], Approx(0.5));
275 1 : CHECK_EQ(sp[1], Approx(2));
276 :
277 1 : CHECK_EQ(o.size(), 2);
278 1 : CHECK_EQ(o[0], Approx(2.5));
279 1 : CHECK_EQ(o[1], Approx(10));
280 : }
281 : }
282 :
283 6 : GIVEN("Size coefficients for 3D")
284 : {
285 2 : IndexVector_t size(3);
286 1 : size << 10, 10, 10;
287 :
288 2 : THEN("Then Spacing and location of origin is calculated correctly")
289 : {
290 2 : VolumeData3D volData{Size3D{size}};
291 :
292 1 : CHECK_EQ(volData.getSpacing().size(), 3);
293 1 : CHECK_EQ(volData.getSpacing()[0], Approx(1));
294 1 : CHECK_EQ(volData.getSpacing()[1], Approx(1));
295 1 : CHECK_EQ(volData.getSpacing()[2], Approx(1));
296 :
297 1 : CHECK_EQ(volData.getLocationOfOrigin().size(), 3);
298 1 : CHECK_EQ(volData.getLocationOfOrigin()[0], Approx(5));
299 1 : CHECK_EQ(volData.getLocationOfOrigin()[1], Approx(5));
300 1 : CHECK_EQ(volData.getLocationOfOrigin()[2], Approx(5));
301 : }
302 : }
303 :
304 6 : GIVEN("Size coefficients and Spacing for 2D")
305 : {
306 2 : IndexVector_t size(3);
307 1 : size << 10, 10, 10;
308 :
309 2 : RealVector_t spacing(3);
310 1 : spacing << 0.5, 2, 1;
311 :
312 2 : THEN("Then Spacing and location of origin is calculated correctly")
313 : {
314 2 : VolumeData3D volData{Size3D{size}, Spacing3D{spacing}};
315 :
316 1 : CHECK_EQ(volData.getSpacing().size(), 3);
317 1 : CHECK_EQ(volData.getSpacing()[0], Approx(0.5));
318 1 : CHECK_EQ(volData.getSpacing()[1], Approx(2));
319 1 : CHECK_EQ(volData.getSpacing()[2], Approx(1));
320 :
321 1 : CHECK_EQ(volData.getLocationOfOrigin().size(), 3);
322 1 : CHECK_EQ(volData.getLocationOfOrigin()[0], Approx(2.5));
323 1 : CHECK_EQ(volData.getLocationOfOrigin()[1], Approx(10));
324 1 : CHECK_EQ(volData.getLocationOfOrigin()[2], Approx(5));
325 : }
326 : }
327 5 : }
328 :
329 6 : TEST_CASE("StrongTypes: Testing SinogramData")
330 : {
331 : using namespace geometry;
332 :
333 7 : GIVEN("Size coefficients for 2D")
334 : {
335 2 : IndexVector_t size(2);
336 1 : size << 10, 10;
337 :
338 2 : THEN("Then Spacing and location of origin is calculated correctly")
339 : {
340 2 : SinogramData2D volData{Size2D{size}};
341 :
342 1 : CHECK_EQ(volData.getSpacing().size(), 2);
343 1 : CHECK_EQ(volData.getSpacing()[0], Approx(1));
344 1 : CHECK_EQ(volData.getSpacing()[1], Approx(1));
345 :
346 1 : CHECK_EQ(volData.getLocationOfOrigin().size(), 2);
347 1 : CHECK_EQ(volData.getLocationOfOrigin()[0], Approx(5));
348 1 : CHECK_EQ(volData.getLocationOfOrigin()[1], Approx(5));
349 : }
350 : }
351 :
352 7 : GIVEN("Size coefficients and Spacing for 2D")
353 : {
354 2 : IndexVector_t size(2);
355 1 : size << 10, 10;
356 :
357 2 : RealVector_t spacing(2);
358 1 : spacing << 0.5, 2;
359 :
360 2 : THEN("Then Spacing and location of origin is calculated correctly")
361 : {
362 3 : SinogramData2D sinoData{Size2D{size}, Spacing2D{spacing}};
363 :
364 1 : CHECK_EQ(sinoData.getSpacing().size(), 2);
365 1 : CHECK_EQ(sinoData.getSpacing()[0], Approx(0.5));
366 1 : CHECK_EQ(sinoData.getSpacing()[1], Approx(2));
367 :
368 1 : CHECK_EQ(sinoData.getLocationOfOrigin().size(), 2);
369 1 : CHECK_EQ(sinoData.getLocationOfOrigin()[0], Approx(2.5));
370 1 : CHECK_EQ(sinoData.getLocationOfOrigin()[1], Approx(10));
371 :
372 5 : CHECK_THROWS(SinogramData2D{Size2D{size}, Spacing2D{RealVector_t(3)}});
373 : }
374 : }
375 :
376 7 : GIVEN("Spacing and Origin shift in 2D")
377 : {
378 2 : RealVector_t spacing(2);
379 1 : spacing << 1, 1;
380 :
381 2 : RealVector_t shift(2);
382 1 : shift << 1, 1;
383 :
384 2 : THEN("Then Spacing and location of origin is calculated correctly")
385 : {
386 3 : auto [s, o] = SinogramData2D{Spacing2D{spacing}, OriginShift2D{shift}};
387 :
388 1 : CHECK_EQ(s.size(), 2);
389 1 : CHECK_EQ(s[0], Approx(1));
390 1 : CHECK_EQ(s[1], Approx(1));
391 :
392 1 : CHECK_EQ(o.size(), 2);
393 1 : CHECK_EQ(o[0], Approx(1));
394 1 : CHECK_EQ(o[1], Approx(1));
395 :
396 : // Test that exceptions are thrown
397 5 : CHECK_THROWS(SinogramData2D{Spacing2D{spacing}, RealVector_t(3)});
398 5 : CHECK_THROWS(SinogramData2D{RealVector_t(3), OriginShift2D{shift}});
399 4 : CHECK_THROWS(SinogramData2D{RealVector_t(3), RealVector_t(3)});
400 : }
401 : }
402 :
403 7 : GIVEN("Size coefficients for 3D")
404 : {
405 2 : IndexVector_t size(3);
406 1 : size << 10, 10, 10;
407 :
408 2 : THEN("Then Spacing and location of origin is calculated correctly")
409 : {
410 2 : SinogramData3D sinoData{Size3D{size}};
411 :
412 1 : CHECK_EQ(sinoData.getSpacing().size(), 3);
413 1 : CHECK_EQ(sinoData.getSpacing()[0], Approx(1));
414 1 : CHECK_EQ(sinoData.getSpacing()[1], Approx(1));
415 1 : CHECK_EQ(sinoData.getSpacing()[2], Approx(1));
416 :
417 1 : CHECK_EQ(sinoData.getLocationOfOrigin().size(), 3);
418 1 : CHECK_EQ(sinoData.getLocationOfOrigin()[0], Approx(5));
419 1 : CHECK_EQ(sinoData.getLocationOfOrigin()[1], Approx(5));
420 1 : CHECK_EQ(sinoData.getLocationOfOrigin()[2], Approx(5));
421 : }
422 : }
423 :
424 7 : GIVEN("Size coefficients and Spacing for 2D")
425 : {
426 2 : IndexVector_t size(3);
427 1 : size << 10, 10, 10;
428 :
429 2 : RealVector_t spacing(3);
430 1 : spacing << 0.5, 2, 1;
431 :
432 2 : THEN("Then Spacing and location of origin is calculated correctly")
433 : {
434 2 : auto [s, o] = SinogramData3D{Size3D{size}, Spacing3D{spacing}};
435 :
436 1 : CHECK_EQ(s.size(), 3);
437 1 : CHECK_EQ(s[0], Approx(0.5));
438 1 : CHECK_EQ(s[1], Approx(2));
439 1 : CHECK_EQ(s[2], Approx(1));
440 :
441 1 : CHECK_EQ(o.size(), 3);
442 1 : CHECK_EQ(o[0], Approx(2.5));
443 1 : CHECK_EQ(o[1], Approx(10));
444 1 : CHECK_EQ(o[2], Approx(5));
445 : }
446 : }
447 :
448 7 : GIVEN("Spacing and Origin shift in 3D")
449 : {
450 2 : RealVector_t spacing(3);
451 1 : spacing << 1, 1, 1;
452 :
453 2 : RealVector_t shift(3);
454 1 : shift << 1, 1, 1;
455 :
456 2 : THEN("Then Spacing and location of origin is calculated correctly")
457 : {
458 3 : SinogramData3D volData{Spacing3D{spacing}, OriginShift3D{shift}};
459 :
460 1 : CHECK_EQ(volData.getSpacing().size(), 3);
461 1 : CHECK_EQ(volData.getSpacing()[0], Approx(1));
462 1 : CHECK_EQ(volData.getSpacing()[1], Approx(1));
463 1 : CHECK_EQ(volData.getSpacing()[2], Approx(1));
464 :
465 1 : CHECK_EQ(volData.getLocationOfOrigin().size(), 3);
466 1 : CHECK_EQ(volData.getLocationOfOrigin()[0], Approx(1));
467 1 : CHECK_EQ(volData.getLocationOfOrigin()[1], Approx(1));
468 1 : CHECK_EQ(volData.getLocationOfOrigin()[2], Approx(1));
469 :
470 : // Test that exceptions are thrown
471 5 : CHECK_THROWS(SinogramData3D{Spacing3D{spacing}, RealVector_t(2)});
472 5 : CHECK_THROWS(SinogramData3D{RealVector_t(4), OriginShift3D{shift}});
473 4 : CHECK_THROWS(SinogramData3D{RealVector_t(1), RealVector_t(3)});
474 : }
475 : }
476 6 : }
477 :
478 2 : TEST_CASE("StrongTypes: Testing Threshold")
479 : {
480 : using namespace geometry;
481 :
482 3 : GIVEN("Valid arguments for Thresholds")
483 : {
484 1 : real_t one = 1;
485 1 : real_t half = 1.0 / 2;
486 1 : real_t nine = 9;
487 :
488 2 : THEN("Overloaded relational operators are implemented correctly")
489 : {
490 1 : Threshold<real_t> tOne{one};
491 1 : Threshold<real_t> tHalf{half};
492 1 : Threshold<real_t> tNine{nine};
493 :
494 1 : CHECK_EQ(tOne, one);
495 1 : CHECK_GT((nine - tOne), tOne);
496 1 : CHECK_GE(nine, tHalf);
497 1 : CHECK_NE(tNine, half);
498 1 : CHECK_LT(tHalf, (one + tNine));
499 1 : CHECK_LE((tHalf + half), (one + tNine));
500 : }
501 : }
502 :
503 3 : GIVEN("Invalid arguments for Thresholds")
504 : {
505 1 : real_t zero = 0;
506 1 : real_t neg1 = -1;
507 :
508 2 : THEN("An exception is thrown as such Thresholds cannot be constructed")
509 : {
510 2 : CHECK_THROWS(Threshold<real_t>{zero});
511 2 : CHECK_THROWS(Threshold<real_t>{neg1});
512 : }
513 : }
514 2 : }
515 :
516 : TEST_SUITE_END();
|