Line data Source code
1 : /**
2 : * @file test_TraverseAABB.cpp
3 : *
4 : * @brief Test for TraverseAABB class
5 : *
6 : * @author David Frank - initial code
7 : * @author Maximilian Hornung - modularization, fixes
8 : * @author Tobias Lasser - minor fixes
9 : */
10 :
11 : #include "doctest/doctest.h"
12 :
13 : #include "TraverseAABB.h"
14 : #include "Intersection.h"
15 :
16 : using namespace elsa;
17 : using namespace doctest;
18 :
19 : bool intersect(const RealVector_t& voxel, const RealRay_t& r)
20 1691 : {
21 : // pre-check parallel rays
22 4689 : for (index_t i = 0; i < r.dim(); ++i) {
23 3254 : real_t tmp = std::abs(r.origin()(i) - voxel(i));
24 :
25 3254 : if (std::abs(r.direction()(i)) < 0.0000001 && tmp >= 0.0 && tmp < 1.0)
26 256 : return true;
27 3254 : }
28 :
29 : // check if ray intersects pixel
30 1691 : IndexVector_t ones(voxel.size());
31 1435 : ones.setOnes();
32 1435 : BoundingBox bb(ones);
33 1435 : bb._min += voxel;
34 1435 : bb._max += voxel;
35 :
36 1435 : return Intersection::withRay(bb, r).operator bool();
37 1691 : }
38 :
39 : TEST_CASE("TraverseAABB: Construction of a 2D traversal object")
40 28 : {
41 : // setup
42 28 : size_t dim = 2;
43 28 : index_t x = 3;
44 28 : index_t y = 3;
45 28 : IndexVector_t volumeDims(dim);
46 28 : volumeDims << x, y;
47 :
48 28 : RealVector_t spacing(dim);
49 :
50 28 : RealVector_t ro(dim);
51 28 : RealVector_t rd(dim);
52 :
53 28 : GIVEN("A 3x3 aabb with standard spacing")
54 28 : {
55 28 : BoundingBox aabb(volumeDims);
56 :
57 : //================================
58 : // intersection from straight rays from the bottom
59 : //================================
60 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (0.5, "
61 28 : "-0.5) and direction (0, 1)")
62 28 : {
63 1 : ro << 0.5, -0.5;
64 1 : rd << 0.0, 1.0;
65 1 : RealRay_t r(ro, rd);
66 :
67 1 : TraverseAABB traverse(aabb, r);
68 1 : CHECK_UNARY(traverse.isInBoundingBox());
69 1 : THEN("The ray intersects the aabb at the bottom left pixel")
70 1 : {
71 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
72 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
73 1 : }
74 1 : }
75 :
76 28 : WHEN("A ray with origin = (1.0, -0.5) and direction (0, 1), hits the boundary between 2 "
77 28 : "voxels")
78 28 : {
79 1 : ro << 1.0, -0.5;
80 1 : rd << 0.0, 1.0;
81 1 : RealRay_t r(ro, rd);
82 :
83 1 : TraverseAABB traverse(aabb, r);
84 1 : CHECK_UNARY(traverse.isInBoundingBox());
85 1 : THEN("The ray intersects the aabb at the bottom left pixel")
86 1 : {
87 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 1);
88 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
89 1 : }
90 1 : }
91 :
92 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (1.5, "
93 28 : "-0.5) and direction (0, 1)")
94 28 : {
95 1 : ro << 1.5, -0.5;
96 1 : rd << 0.0, 1.0;
97 1 : RealRay_t r(ro, rd);
98 :
99 1 : TraverseAABB traverse(aabb, r);
100 1 : CHECK_UNARY(traverse.isInBoundingBox());
101 1 : THEN("The ray intersects the aabb at the bottom left pixel")
102 1 : {
103 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 1);
104 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
105 1 : }
106 1 : }
107 :
108 28 : WHEN("A ray with origin = (2.0, -0.5) and direction (0, 1), hits the boundary between 2 "
109 28 : "voxels")
110 28 : {
111 1 : ro << 2.0, -0.5;
112 1 : rd << 0.0, 1.0;
113 1 : RealRay_t r(ro, rd);
114 :
115 1 : TraverseAABB traverse(aabb, r);
116 1 : CHECK_UNARY(traverse.isInBoundingBox());
117 1 : THEN("The ray intersects the aabb at the bottom left pixel")
118 1 : {
119 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
120 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
121 1 : }
122 1 : }
123 :
124 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (2.5, "
125 28 : "-0.5) and direction (0, 1)")
126 28 : {
127 1 : ro << 2.5, -0.5;
128 1 : rd << 0.0, 1.0;
129 1 : RealRay_t r(ro, rd);
130 :
131 1 : TraverseAABB traverse(aabb, r);
132 1 : CHECK_UNARY(traverse.isInBoundingBox());
133 1 : THEN("The ray intersects the aabb at the bottom left pixel")
134 1 : {
135 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
136 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
137 1 : }
138 1 : }
139 :
140 : //================================
141 : // intersection from straight rays from the left
142 : //================================
143 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (-0.5, "
144 28 : "0.5) and direction (1, 0)")
145 28 : {
146 1 : ro << -0.5, 0.5;
147 1 : rd << 1.0, 0.0;
148 1 : RealRay_t r(ro, rd);
149 :
150 1 : TraverseAABB traverse(aabb, r);
151 1 : CHECK_UNARY(traverse.isInBoundingBox());
152 1 : THEN("The ray intersects the aabb at the bottom left pixel")
153 1 : {
154 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
155 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
156 1 : }
157 1 : }
158 :
159 28 : WHEN("A ray with origin = (1.0, -0.5) and direction (0, 1), hits the boundary between 2 "
160 28 : "voxels")
161 28 : {
162 1 : ro << -0.5, 1.0;
163 1 : rd << 1.0, 0.0;
164 1 : RealRay_t r(ro, rd);
165 :
166 1 : TraverseAABB traverse(aabb, r);
167 1 : CHECK_UNARY(traverse.isInBoundingBox());
168 1 : THEN("The ray intersects the aabb at the bottom left pixel")
169 1 : {
170 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
171 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
172 1 : }
173 1 : }
174 :
175 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (-0.5, "
176 28 : "1.5) and direction (1, 0)")
177 28 : {
178 1 : ro << -0.5, 1.5;
179 1 : rd << 1.0, 0.0;
180 1 : RealRay_t r(ro, rd);
181 :
182 1 : TraverseAABB traverse(aabb, r);
183 1 : CHECK_UNARY(traverse.isInBoundingBox());
184 1 : THEN("The ray intersects the aabb at the bottom left pixel")
185 1 : {
186 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
187 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
188 1 : }
189 1 : }
190 :
191 28 : WHEN("A ray with origin = (2.0, -0.5) and direction (0, 1), hits the boundary between 2 "
192 28 : "voxels")
193 28 : {
194 1 : ro << -0.5, 2.0;
195 1 : rd << 1.0, 0.0;
196 1 : RealRay_t r(ro, rd);
197 :
198 1 : TraverseAABB traverse(aabb, r);
199 1 : CHECK_UNARY(traverse.isInBoundingBox());
200 1 : THEN("The ray intersects the aabb at the bottom left pixel")
201 1 : {
202 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
203 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
204 1 : }
205 1 : }
206 :
207 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (-0.5, "
208 28 : "2.5) and direction (1, 0)")
209 28 : {
210 1 : ro << -0.5, 2.5;
211 1 : rd << 1.0, 0.0;
212 1 : RealRay_t r(ro, rd);
213 :
214 1 : TraverseAABB traverse(aabb, r);
215 1 : CHECK_UNARY(traverse.isInBoundingBox());
216 1 : THEN("The ray intersects the aabb at the bottom left pixel")
217 1 : {
218 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
219 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
220 1 : }
221 1 : }
222 :
223 : //================================
224 : // intersection from straight rays from the right
225 : //================================
226 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (3.5, "
227 28 : "0.5) and direction (-1, 0)")
228 28 : {
229 1 : ro << 3.5, 0.5;
230 1 : rd << -1.0, 0.0;
231 1 : RealRay_t r(ro, rd);
232 :
233 1 : TraverseAABB traverse(aabb, r);
234 1 : CHECK_UNARY(traverse.isInBoundingBox());
235 1 : THEN("The ray intersects the aabb at the bottom left pixel")
236 1 : {
237 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
238 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
239 1 : }
240 1 : }
241 :
242 28 : WHEN("A ray with origin = (3.5, 1.0) and direction (-1, 0), hits the boundary between 2 "
243 28 : "voxels")
244 28 : {
245 1 : ro << 3.5, 1.0;
246 1 : rd << -1.0, 0.0;
247 1 : RealRay_t r(ro, rd);
248 :
249 1 : TraverseAABB traverse(aabb, r);
250 1 : CHECK_UNARY(traverse.isInBoundingBox());
251 1 : THEN("The ray intersects the aabb at the bottom left pixel")
252 1 : {
253 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
254 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
255 1 : }
256 1 : }
257 :
258 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (3.5, "
259 28 : "1.5) and direction (-1, 0)")
260 28 : {
261 1 : ro << 3.5, 1.5;
262 1 : rd << -1.0, 0.0;
263 1 : RealRay_t r(ro, rd);
264 :
265 1 : TraverseAABB traverse(aabb, r);
266 1 : CHECK_UNARY(traverse.isInBoundingBox());
267 1 : THEN("The ray intersects the aabb at the bottom left pixel")
268 1 : {
269 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
270 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
271 1 : }
272 1 : }
273 :
274 28 : WHEN("A ray with origin = (3.5, 2.0) and direction (-1, 0), hits the boundary between 2 "
275 28 : "voxels")
276 28 : {
277 1 : ro << 3.5, 2.0;
278 1 : rd << -1.0, 0.0;
279 1 : RealRay_t r(ro, rd);
280 :
281 1 : TraverseAABB traverse(aabb, r);
282 1 : CHECK_UNARY(traverse.isInBoundingBox());
283 1 : THEN("The ray intersects the aabb at the bottom left pixel")
284 1 : {
285 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
286 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
287 1 : }
288 1 : }
289 :
290 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (3.5, "
291 28 : "2.5) and direction (-1, 0)")
292 28 : {
293 1 : ro << 3.5, 2.5;
294 1 : rd << -1.0, 0.0;
295 1 : RealRay_t r(ro, rd);
296 :
297 1 : TraverseAABB traverse(aabb, r);
298 1 : CHECK_UNARY(traverse.isInBoundingBox());
299 1 : THEN("The ray intersects the aabb at the bottom left pixel")
300 1 : {
301 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
302 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
303 1 : }
304 1 : }
305 :
306 : //================================
307 : // intersection from straight rays from the top
308 : //================================
309 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (0.5, "
310 28 : "3.5) and direction (0, -1)")
311 28 : {
312 1 : ro << 0.5, 3.5;
313 1 : rd << 0.0, -1.0;
314 1 : RealRay_t r(ro, rd);
315 :
316 1 : TraverseAABB traverse(aabb, r);
317 1 : CHECK_UNARY(traverse.isInBoundingBox());
318 1 : THEN("The ray intersects the aabb at the bottom left pixel")
319 1 : {
320 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
321 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
322 1 : }
323 1 : }
324 :
325 28 : WHEN("A ray with origin = (1.0, 3.5) and direction (-1, 0), hits the boundary between 2 "
326 28 : "voxels")
327 28 : {
328 1 : ro << 1.0, 3.5;
329 1 : rd << 0.0, -1.0;
330 1 : RealRay_t r(ro, rd);
331 :
332 1 : TraverseAABB traverse(aabb, r);
333 1 : CHECK_UNARY(traverse.isInBoundingBox());
334 1 : THEN("The ray intersects the aabb at the bottom left pixel")
335 1 : {
336 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 1);
337 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
338 1 : }
339 1 : }
340 :
341 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (1.5, "
342 28 : "3.5) and direction (0, -1)")
343 28 : {
344 1 : ro << 1.5, 3.5;
345 1 : rd << 0.0, -1.0;
346 1 : RealRay_t r(ro, rd);
347 :
348 1 : TraverseAABB traverse(aabb, r);
349 1 : CHECK_UNARY(traverse.isInBoundingBox());
350 1 : THEN("The ray intersects the aabb at the bottom left pixel")
351 1 : {
352 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 1);
353 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
354 1 : }
355 1 : }
356 :
357 28 : WHEN("A ray with origin = (2.0, 3.5) and direction (-1, 0), hits the boundary between 2 "
358 28 : "voxels")
359 28 : {
360 1 : ro << 2.0, 3.5;
361 1 : rd << 0.0, -1.0;
362 1 : RealRay_t r(ro, rd);
363 :
364 1 : TraverseAABB traverse(aabb, r);
365 1 : CHECK_UNARY(traverse.isInBoundingBox());
366 1 : THEN("The ray intersects the aabb at the bottom left pixel")
367 1 : {
368 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
369 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
370 1 : }
371 1 : }
372 :
373 28 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (2.5, "
374 28 : "3.5) and direction (0, -1)")
375 28 : {
376 1 : ro << 2.5, 3.5;
377 1 : rd << 0.0, -1.0;
378 1 : RealRay_t r(ro, rd);
379 :
380 1 : TraverseAABB traverse(aabb, r);
381 1 : CHECK_UNARY(traverse.isInBoundingBox());
382 1 : THEN("The ray intersects the aabb at the bottom left pixel")
383 1 : {
384 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
385 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
386 1 : }
387 1 : }
388 :
389 : //
390 : // Some edge cases
391 : //
392 28 : WHEN("A ray with origin = (-0.5, 0.0) and direction (1, 0) hits the left edge of aabb")
393 28 : {
394 1 : ro << -0.5, 0.0;
395 1 : rd << 1.0, 0.0;
396 1 : RealRay_t r(ro, rd);
397 :
398 1 : TraverseAABB traverse(aabb, r);
399 1 : CHECK_UNARY(traverse.isInBoundingBox());
400 1 : THEN("The ray intersects the aabb at the bottom left pixel")
401 1 : {
402 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
403 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
404 1 : }
405 1 : }
406 :
407 28 : WHEN("A ray with origin = (3.5, 0.0) and direction (-1, 0) hits the left edge of aabb")
408 28 : {
409 1 : ro << 3.5, 0.0;
410 1 : rd << -1.0, 0.0;
411 1 : RealRay_t r(ro, rd);
412 :
413 1 : TraverseAABB traverse(aabb, r);
414 1 : CHECK_UNARY(traverse.isInBoundingBox());
415 1 : THEN("The ray intersects the aabb at the top left pixel")
416 1 : {
417 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 2);
418 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
419 1 : }
420 1 : }
421 :
422 28 : WHEN("A ray with origin = (-0.5, 3.0) and direction (1, 0) hits the top edge of aabb")
423 28 : {
424 1 : ro << -0.5, 3.0;
425 1 : rd << 1.0, 0.0;
426 1 : RealRay_t r(ro, rd);
427 :
428 1 : TraverseAABB traverse(aabb, r);
429 :
430 1 : THEN("the the aabb is not hit") { REQUIRE_UNARY_FALSE(traverse.isInBoundingBox()); }
431 1 : }
432 :
433 28 : WHEN("A ray with origin = (3.5, 3.0) and direction (-1, 0) hits the top edge of aabb")
434 28 : {
435 1 : ro << 3.5, 3.0;
436 1 : rd << -1.0, 0.0;
437 1 : RealRay_t r(ro, rd);
438 :
439 1 : TraverseAABB traverse(aabb, r);
440 :
441 1 : THEN("the the aabb is not hit") { REQUIRE_UNARY_FALSE(traverse.isInBoundingBox()); }
442 1 : }
443 :
444 28 : WHEN("A ray with origin = (0.0, -0.5) and direction (0, 1) hits the bottom edge of aabb)")
445 28 : {
446 1 : ro << 0.0, -0.5;
447 1 : rd << 0.0, 1.0;
448 1 : RealRay_t r(ro, rd);
449 :
450 1 : TraverseAABB traverse(aabb, r);
451 1 : CHECK_UNARY(traverse.isInBoundingBox());
452 1 : THEN("The ray intersects the aabb at the bottom left pixel")
453 1 : {
454 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
455 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
456 1 : }
457 1 : }
458 :
459 28 : WHEN("A ray with origin = (0.0, 3.5) and direction (0, -1) hits the top edge of aabb)")
460 28 : {
461 1 : ro << 0.0, 3.5;
462 1 : rd << 0.0, -1.0;
463 1 : RealRay_t r(ro, rd);
464 :
465 1 : TraverseAABB traverse(aabb, r);
466 1 : CHECK_UNARY(traverse.isInBoundingBox());
467 1 : THEN("The ray intersects the aabb at the top left pixel")
468 1 : {
469 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
470 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
471 1 : }
472 1 : }
473 :
474 28 : WHEN("A ray with origin = (3.0, -0.5) and direction (0, 1) hits the right edge of aabb)")
475 28 : {
476 1 : ro << 3.0, -0.5;
477 1 : rd << 0.0, 1.0;
478 1 : RealRay_t r(ro, rd);
479 :
480 1 : TraverseAABB traverse(aabb, r);
481 :
482 1 : THEN("the the aabb is not hit") { REQUIRE_UNARY_FALSE(traverse.isInBoundingBox()); }
483 1 : }
484 :
485 28 : WHEN("A ray with origin = (3.0, 3.5) and direction (0, -1) hits the top edge of aabb)")
486 28 : {
487 1 : ro << 3.0, 3.5;
488 1 : rd << 0.0, -1.0;
489 1 : RealRay_t r(ro, rd);
490 :
491 1 : TraverseAABB traverse(aabb, r);
492 :
493 1 : THEN("the the aabb is not hit") { REQUIRE_UNARY_FALSE(traverse.isInBoundingBox()); }
494 1 : }
495 28 : }
496 28 : }
497 :
498 : TEST_CASE("TraverseAABB: Construction of a 3D traversal object")
499 1 : {
500 : // setup
501 1 : size_t dim = 3;
502 1 : IndexVector_t volumeDims(dim);
503 1 : volumeDims << 3, 3, 3;
504 :
505 1 : RealVector_t spacing(dim);
506 :
507 1 : RealVector_t ro(dim);
508 1 : RealVector_t rd(dim);
509 :
510 1 : GIVEN("a 3x3x3 aabb with standard spacing")
511 1 : {
512 1 : BoundingBox aabb(volumeDims);
513 :
514 1 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (0.5, "
515 1 : "-0.5, 0.5) and direction = (0, 1, 0)")
516 1 : {
517 1 : ro << 0.5, -0.5, 0.5;
518 1 : rd << 0.0, 1.0, 0.0;
519 1 : RealRay_t r(ro, rd);
520 :
521 1 : TraverseAABB traverse(aabb, r);
522 1 : CHECK_UNARY(traverse.isInBoundingBox());
523 :
524 1 : THEN("The ray intersects the aabb at the voxel (0, 0, 0)")
525 1 : {
526 1 : REQUIRE_UNARY(traverse.isInBoundingBox());
527 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
528 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
529 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(2), 0);
530 1 : }
531 1 : }
532 1 : }
533 1 : }
534 :
535 : TEST_CASE("TraverseAABB: Traverse a minimal 3D volume of size 1x1x1")
536 1 : {
537 : // setup
538 1 : size_t dim = 3;
539 1 : index_t x = 1;
540 1 : index_t y = 1;
541 1 : index_t z = 1;
542 1 : IndexVector_t volumeDims(dim);
543 1 : volumeDims << x, y, z;
544 :
545 1 : RealVector_t spacing(dim);
546 1 : RealVector_t ro(dim);
547 1 : RealVector_t rd(dim);
548 :
549 1 : GIVEN("A 1x1x1 volume with uniform scaling")
550 1 : {
551 1 : BoundingBox aabb(volumeDims);
552 1 : spacing << 1.0, 1.0, 1.0;
553 :
554 1 : WHEN("The volume is traversed with a ray with origin = (-0.5, 0.5, 0.5) and a direction = "
555 1 : "(0, 1, 0)")
556 1 : {
557 1 : ro << 0.5, -0.5, 0.5;
558 1 : rd << 0.0, 1.0, 0.0;
559 :
560 1 : RealRay_t r(ro, rd);
561 1 : TraverseAABB traverse(aabb, r);
562 1 : CHECK_UNARY(traverse.isInBoundingBox());
563 :
564 1 : traverse.updateTraverse();
565 :
566 1 : THEN("The algorithms left the volume and the voxel it left the box is (0, 1, 0)")
567 1 : {
568 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
569 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
570 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
571 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(2), 0);
572 1 : }
573 1 : }
574 1 : }
575 1 : }
576 :
577 : TEST_CASE("TraverseAABB: Traverse a 2D volume and only check that the endpoint is correct")
578 1 : {
579 : // setup
580 1 : size_t dim = 2;
581 1 : index_t x = 10;
582 1 : index_t y = 10;
583 1 : IndexVector_t volumeDims(dim);
584 1 : volumeDims << x, y;
585 :
586 1 : RealVector_t spacing(dim);
587 1 : RealVector_t ro(dim);
588 1 : RealVector_t rd(dim);
589 :
590 1 : GIVEN("A 10x10 volume with uniform scaling")
591 1 : {
592 1 : BoundingBox aabb(volumeDims);
593 :
594 1 : WHEN("The volume is traversed with a ray with origin = (-0.5, 0.5, 0.5) and a direction = "
595 1 : "(0, 1, 0)")
596 1 : {
597 1 : ro << -1, 4.5;
598 1 : rd << 1.0, 0;
599 :
600 1 : RealRay_t r(ro, rd);
601 1 : TraverseAABB traverse(aabb, r);
602 1 : CHECK_UNARY(traverse.isInBoundingBox());
603 :
604 11 : while (traverse.isInBoundingBox())
605 10 : traverse.updateTraverse();
606 :
607 1 : THEN("The endpoint should be (10,4)")
608 1 : {
609 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
610 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 10);
611 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 4);
612 1 : }
613 1 : }
614 1 : }
615 1 : }
616 :
617 : TEST_CASE("TraverseAABB: Traverse a 3D Volume diagonally")
618 2 : {
619 : // TODO: run through all 4 diagonals
620 : // TODO: make a non cube volume and run through all 4 diagonals
621 : // TODO: make non uniform scaling and run through all 4 diagonals
622 :
623 2 : size_t dim = 3;
624 2 : IndexVector_t volumeDims(dim);
625 2 : volumeDims << 10, 10, 10;
626 :
627 2 : RealVector_t spacing(dim);
628 2 : RealVector_t ro(dim);
629 2 : RealVector_t rd(dim);
630 :
631 2 : GIVEN("A 10x10 volume with uniform scaling")
632 2 : {
633 2 : BoundingBox aabb(volumeDims);
634 2 : WHEN("Start at (-1, -1, -1) (so bottom left front) and run to (10, 10, 10) (so top right "
635 2 : "back)")
636 2 : {
637 2 : ro << -1.0, -1.0, -1.0;
638 2 : rd << 1.0, 1.0, 1.0;
639 2 : rd.normalize();
640 :
641 2 : RealRay_t r(ro, rd);
642 :
643 2 : TraverseAABB traverse(aabb, r);
644 2 : CHECK_UNARY(traverse.isInBoundingBox());
645 :
646 2 : THEN("You entered at (0, 0, 0)")
647 2 : {
648 1 : CHECK_EQ(traverse.getCurrentVoxel()(0), 0);
649 1 : CHECK_EQ(traverse.getCurrentVoxel()(1), 0);
650 1 : CHECK_EQ(traverse.getCurrentVoxel()(2), 0);
651 1 : }
652 58 : while (traverse.isInBoundingBox())
653 56 : traverse.updateTraverse();
654 :
655 2 : THEN("You leave the volume at (10, 9, 9)")
656 2 : {
657 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
658 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 10);
659 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 9);
660 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(2), 9);
661 1 : }
662 2 : }
663 2 : }
664 2 : }
665 :
666 : TEST_CASE("TraverseAABB: Check that the first step into the 2D Volume is correct")
667 4 : {
668 4 : size_t dim = 2;
669 4 : index_t x = 5;
670 4 : index_t y = 5;
671 4 : IndexVector_t volumeDims(dim);
672 4 : volumeDims << x, y;
673 :
674 4 : RealVector_t ro(dim);
675 4 : RealVector_t rd(dim);
676 :
677 4 : GIVEN("A 5x5 volume with uniform scaling")
678 4 : {
679 4 : BoundingBox aabb(volumeDims);
680 :
681 4 : WHEN("The ray direction has the biggest value on the y axis")
682 4 : {
683 2 : ro << 0, 0;
684 2 : rd << 0.5f, 0.7f;
685 2 : rd.normalize();
686 :
687 2 : RealRay_t r(ro, rd);
688 2 : TraverseAABB traverse(aabb, r);
689 2 : CHECK_UNARY(traverse.isInBoundingBox());
690 :
691 2 : THEN("The traversal is initially at (0, 0)")
692 2 : {
693 1 : auto voxel = traverse.getCurrentVoxel();
694 1 : CHECK_EQ(voxel(0), 0);
695 1 : CHECK_EQ(voxel(1), 0);
696 1 : }
697 :
698 2 : traverse.updateTraverse();
699 :
700 2 : THEN("The first step is in y direction")
701 2 : {
702 1 : REQUIRE_UNARY(traverse.isInBoundingBox());
703 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
704 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
705 1 : }
706 2 : }
707 :
708 4 : WHEN("The ray direction has the biggest value on the x axis")
709 4 : {
710 2 : ro << 0, 0;
711 2 : rd << 0.7f, 0.5f;
712 2 : rd.normalize();
713 :
714 2 : RealRay_t r(ro, rd);
715 2 : TraverseAABB traverse(aabb, r);
716 2 : CHECK_UNARY(traverse.isInBoundingBox());
717 :
718 2 : THEN("The traversal is initially at (0, 0)")
719 2 : {
720 1 : auto voxel = traverse.getCurrentVoxel();
721 1 : CHECK_EQ(voxel(0), 0);
722 1 : CHECK_EQ(voxel(1), 0);
723 1 : }
724 :
725 2 : traverse.updateTraverse();
726 :
727 2 : THEN("The first step is in y direction")
728 2 : {
729 1 : REQUIRE_UNARY(traverse.isInBoundingBox());
730 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 1);
731 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
732 1 : }
733 2 : }
734 4 : }
735 4 : }
736 :
737 : TEST_CASE("TraverseAABB: Traverse_Volume_2D_EachPointIsTested")
738 1 : {
739 : // setup
740 1 : size_t dim = 2;
741 1 : index_t x = 128;
742 1 : index_t y = 128;
743 1 : IndexVector_t volumeDims(dim);
744 1 : volumeDims << x, y;
745 1 : BoundingBox aabb(volumeDims);
746 :
747 1 : RealVector_t ro(dim);
748 1 : ro << -168.274f, -143.397f;
749 1 : RealVector_t rd(dim);
750 1 : rd << 0.761124909f, 0.648605406f;
751 1 : rd.normalize();
752 1 : RealRay_t r(ro, rd);
753 :
754 1 : TraverseAABB traverse(aabb, r);
755 1 : CHECK_UNARY(traverse.isInBoundingBox());
756 :
757 1 : size_t iter = 0;
758 238 : while (traverse.isInBoundingBox()) {
759 237 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
760 237 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
761 :
762 237 : REQUIRE_UNARY(intersect(voxel, r));
763 237 : traverse.updateTraverse();
764 237 : iter++;
765 237 : }
766 1 : }
767 :
768 : TEST_CASE("TraverseAABB: Traversal through 2D volume should be equal to a ray voxel intersection "
769 : "for every voxel along the way")
770 8 : {
771 : // TODO make this a stronger test, for first some "easy" direction (parallel ones)
772 : // TODO Then make some harder ones
773 : // setup
774 8 : size_t dim = 2;
775 8 : index_t x = 128;
776 8 : index_t y = 128;
777 8 : IndexVector_t volumeDims(dim);
778 8 : volumeDims << x, y;
779 8 : BoundingBox aabb(volumeDims);
780 :
781 8 : RealVector_t ro(dim);
782 8 : RealVector_t rd(dim);
783 :
784 8 : GIVEN("a point at the bottom left of the volume and a ray with leading dimension x")
785 8 : {
786 1 : ro << -168.274f, -143.397f;
787 :
788 1 : rd << 0.761124909f, 0.648605406f;
789 1 : rd.normalize();
790 :
791 1 : RealRay_t r(ro, rd);
792 :
793 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
794 1 : {
795 1 : TraverseAABB traverse(aabb, r);
796 1 : CHECK_UNARY(traverse.isInBoundingBox());
797 :
798 1 : size_t iter = 0;
799 238 : while (traverse.isInBoundingBox()) {
800 237 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
801 237 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
802 :
803 237 : REQUIRE_UNARY(intersect(voxel, r));
804 237 : traverse.updateTraverse();
805 237 : iter++;
806 237 : }
807 1 : }
808 1 : }
809 :
810 8 : GIVEN("a point at the bottom left of the volume and a ray with leading dimension y")
811 8 : {
812 1 : ro << 0, 0;
813 :
814 1 : rd << 0.648605406f, 0.761124909f;
815 1 : rd.normalize();
816 :
817 1 : RealRay_t r(ro, rd);
818 :
819 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
820 1 : {
821 1 : TraverseAABB traverse(aabb, r);
822 1 : CHECK_UNARY(traverse.isInBoundingBox());
823 :
824 1 : size_t iter = 0;
825 238 : while (traverse.isInBoundingBox()) {
826 237 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
827 237 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
828 :
829 237 : REQUIRE_UNARY(intersect(voxel, r));
830 237 : traverse.updateTraverse();
831 237 : iter++;
832 237 : }
833 1 : }
834 1 : }
835 :
836 8 : GIVEN("a ray going through the border of voxel column 0 and 1")
837 8 : {
838 1 : ro << 1, -0.5f;
839 :
840 1 : rd << 0, 1;
841 1 : rd.normalize();
842 :
843 1 : RealRay_t r(ro, rd);
844 :
845 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
846 1 : {
847 1 : TraverseAABB traverse(aabb, r);
848 1 : CHECK_UNARY(traverse.isInBoundingBox());
849 :
850 1 : size_t iter = 0;
851 129 : while (traverse.isInBoundingBox()) {
852 128 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
853 128 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
854 :
855 128 : REQUIRE_UNARY(intersect(voxel, r));
856 128 : traverse.updateTraverse();
857 128 : iter++;
858 128 : }
859 1 : }
860 1 : }
861 :
862 8 : GIVEN("a ray going through the border of voxel row 0 and 1")
863 8 : {
864 1 : ro << -0.5f, 1;
865 :
866 1 : rd << 1, 0;
867 1 : rd.normalize();
868 :
869 1 : RealRay_t r(ro, rd);
870 :
871 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
872 1 : {
873 1 : TraverseAABB traverse(aabb, r);
874 1 : CHECK_UNARY(traverse.isInBoundingBox());
875 :
876 1 : size_t iter = 0;
877 129 : while (traverse.isInBoundingBox()) {
878 128 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
879 128 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
880 :
881 128 : REQUIRE_UNARY(intersect(voxel, r));
882 128 : traverse.updateTraverse();
883 128 : iter++;
884 128 : }
885 1 : }
886 1 : }
887 :
888 8 : GIVEN("A ray going diagonally through the volume")
889 8 : {
890 1 : ro << -0.5f, -0.5f;
891 :
892 1 : rd << 1, 1;
893 1 : rd.normalize();
894 :
895 1 : RealRay_t r(ro, rd);
896 :
897 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
898 1 : {
899 1 : TraverseAABB traverse(aabb, r);
900 1 : CHECK_UNARY(traverse.isInBoundingBox());
901 :
902 1 : size_t iter = 0;
903 256 : while (traverse.isInBoundingBox()) {
904 255 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
905 255 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
906 :
907 255 : REQUIRE_UNARY(intersect(voxel, r));
908 255 : traverse.updateTraverse();
909 255 : iter++;
910 255 : }
911 1 : }
912 1 : }
913 :
914 8 : GIVEN("A ray going diagonally through the volume")
915 8 : {
916 1 : ro << -0.5f, 32;
917 :
918 1 : rd << 1, 1;
919 1 : rd.normalize();
920 :
921 1 : RealRay_t r(ro, rd);
922 :
923 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
924 1 : {
925 1 : TraverseAABB traverse(aabb, r);
926 1 : CHECK_UNARY(traverse.isInBoundingBox());
927 :
928 1 : size_t iter = 0;
929 192 : while (traverse.isInBoundingBox()) {
930 191 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
931 191 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
932 :
933 191 : REQUIRE_UNARY(intersect(voxel, r));
934 191 : traverse.updateTraverse();
935 191 : iter++;
936 191 : }
937 1 : }
938 1 : }
939 :
940 8 : GIVEN("A ray going diagonally through the volume")
941 8 : {
942 1 : ro << -0.5f, -0.5f;
943 :
944 1 : rd << 0.699428f, 0.472203f;
945 1 : rd.normalize();
946 :
947 1 : RealRay_t r(ro, rd);
948 :
949 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
950 1 : {
951 1 : TraverseAABB traverse(aabb, r);
952 1 : CHECK_UNARY(traverse.isInBoundingBox());
953 :
954 1 : size_t iter = 0;
955 215 : while (traverse.isInBoundingBox()) {
956 214 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
957 214 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
958 :
959 214 : REQUIRE_UNARY(intersect(voxel, r));
960 214 : traverse.updateTraverse();
961 214 : iter++;
962 214 : }
963 1 : }
964 1 : }
965 :
966 8 : GIVEN("A ray going diagonally through the volume")
967 8 : {
968 1 : volumeDims << 64, 64;
969 1 : BoundingBox aabb(volumeDims);
970 :
971 1 : ro << 32.0002823f, 3232;
972 :
973 1 : rd << -0.000723466626f, -0.999999762f;
974 1 : rd.normalize();
975 :
976 1 : RealRay_t r(ro, rd);
977 :
978 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
979 1 : {
980 1 : TraverseAABB traverse(aabb, r);
981 1 : traverse.isInBoundingBox();
982 :
983 1 : size_t iter = 0;
984 65 : while (traverse.isInBoundingBox()) {
985 64 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
986 64 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
987 :
988 64 : REQUIRE_UNARY(intersect(voxel, r));
989 64 : traverse.updateTraverse();
990 64 : iter++;
991 64 : }
992 1 : }
993 1 : }
994 8 : }
|