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 3255 : {
21 : // pre-check parallel rays
22 8997 : for (index_t i = 0; i < r.dim(); ++i) {
23 6254 : real_t tmp = std::abs(r.origin()(i) - voxel(i));
24 :
25 6254 : if (std::abs(r.direction()(i)) < 0.0000001 && tmp >= 0.0 && tmp < 1.0)
26 512 : return true;
27 6254 : }
28 :
29 : // check if ray intersects pixel
30 3255 : IndexVector_t ones(voxel.size());
31 2743 : ones.setOnes();
32 2743 : BoundingBox bb(ones);
33 2743 : bb.min() += voxel;
34 2743 : bb.max() += voxel;
35 :
36 2743 : return intersectRay(bb, r).operator bool();
37 3255 : }
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")
431 1 : {
432 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
433 1 : }
434 1 : }
435 :
436 28 : WHEN("A ray with origin = (3.5, 3.0) and direction (-1, 0) hits the top edge of aabb")
437 28 : {
438 1 : ro << 3.5, 3.0;
439 1 : rd << -1.0, 0.0;
440 1 : RealRay_t r(ro, rd);
441 :
442 1 : TraverseAABB traverse(aabb, r);
443 :
444 1 : THEN("the the aabb is not hit")
445 1 : {
446 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
447 1 : }
448 1 : }
449 :
450 28 : WHEN("A ray with origin = (0.0, -0.5) and direction (0, 1) hits the bottom edge of aabb)")
451 28 : {
452 1 : ro << 0.0, -0.5;
453 1 : rd << 0.0, 1.0;
454 1 : RealRay_t r(ro, rd);
455 :
456 1 : TraverseAABB traverse(aabb, r);
457 1 : CHECK_UNARY(traverse.isInBoundingBox());
458 1 : THEN("The ray intersects the aabb at the bottom left pixel")
459 1 : {
460 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
461 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
462 1 : }
463 1 : }
464 :
465 28 : WHEN("A ray with origin = (0.0, 3.5) and direction (0, -1) hits the top edge of aabb)")
466 28 : {
467 1 : ro << 0.0, 3.5;
468 1 : rd << 0.0, -1.0;
469 1 : RealRay_t r(ro, rd);
470 :
471 1 : TraverseAABB traverse(aabb, r);
472 1 : CHECK_UNARY(traverse.isInBoundingBox());
473 1 : THEN("The ray intersects the aabb at the top left pixel")
474 1 : {
475 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
476 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 2);
477 1 : }
478 1 : }
479 :
480 28 : WHEN("A ray with origin = (3.0, -0.5) and direction (0, 1) hits the right edge of aabb)")
481 28 : {
482 1 : ro << 3.0, -0.5;
483 1 : rd << 0.0, 1.0;
484 1 : RealRay_t r(ro, rd);
485 :
486 1 : TraverseAABB traverse(aabb, r);
487 :
488 1 : THEN("the the aabb is not hit")
489 1 : {
490 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
491 1 : }
492 1 : }
493 :
494 28 : WHEN("A ray with origin = (3.0, 3.5) and direction (0, -1) hits the top edge of aabb)")
495 28 : {
496 1 : ro << 3.0, 3.5;
497 1 : rd << 0.0, -1.0;
498 1 : RealRay_t r(ro, rd);
499 :
500 1 : TraverseAABB traverse(aabb, r);
501 :
502 1 : THEN("the the aabb is not hit")
503 1 : {
504 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
505 1 : }
506 1 : }
507 28 : }
508 28 : }
509 :
510 : TEST_CASE("TraverseAABB: Construction of a 3D traversal object")
511 1 : {
512 : // setup
513 1 : size_t dim = 3;
514 1 : IndexVector_t volumeDims(dim);
515 1 : volumeDims << 3, 3, 3;
516 :
517 1 : RealVector_t spacing(dim);
518 :
519 1 : RealVector_t ro(dim);
520 1 : RealVector_t rd(dim);
521 :
522 1 : GIVEN("a 3x3x3 aabb with standard spacing")
523 1 : {
524 1 : BoundingBox aabb(volumeDims);
525 :
526 1 : WHEN("A traversal algorithms is initialised with the aabb and a ray with origin = (0.5, "
527 1 : "-0.5, 0.5) and direction = (0, 1, 0)")
528 1 : {
529 1 : ro << 0.5, -0.5, 0.5;
530 1 : rd << 0.0, 1.0, 0.0;
531 1 : RealRay_t r(ro, rd);
532 :
533 1 : TraverseAABB traverse(aabb, r);
534 1 : CHECK_UNARY(traverse.isInBoundingBox());
535 :
536 1 : THEN("The ray intersects the aabb at the voxel (0, 0, 0)")
537 1 : {
538 1 : REQUIRE_UNARY(traverse.isInBoundingBox());
539 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
540 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
541 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(2), 0);
542 1 : }
543 1 : }
544 1 : }
545 1 : }
546 :
547 : TEST_CASE("TraverseAABB: Traverse a minimal 3D volume of size 1x1x1")
548 1 : {
549 : // setup
550 1 : size_t dim = 3;
551 1 : index_t x = 1;
552 1 : index_t y = 1;
553 1 : index_t z = 1;
554 1 : IndexVector_t volumeDims(dim);
555 1 : volumeDims << x, y, z;
556 :
557 1 : RealVector_t spacing(dim);
558 1 : RealVector_t ro(dim);
559 1 : RealVector_t rd(dim);
560 :
561 1 : GIVEN("A 1x1x1 volume with uniform scaling")
562 1 : {
563 1 : BoundingBox aabb(volumeDims);
564 1 : spacing << 1.0, 1.0, 1.0;
565 :
566 1 : WHEN("The volume is traversed with a ray with origin = (-0.5, 0.5, 0.5) and a direction = "
567 1 : "(0, 1, 0)")
568 1 : {
569 1 : ro << 0.5, -0.5, 0.5;
570 1 : rd << 0.0, 1.0, 0.0;
571 :
572 1 : RealRay_t r(ro, rd);
573 1 : TraverseAABB traverse(aabb, r);
574 1 : CHECK_UNARY(traverse.isInBoundingBox());
575 :
576 1 : traverse.updateTraverse();
577 :
578 1 : THEN("The algorithms left the volume and the voxel it left the box is (0, 1, 0)")
579 1 : {
580 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
581 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
582 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
583 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(2), 0);
584 1 : }
585 1 : }
586 1 : }
587 1 : }
588 :
589 : TEST_CASE("TraverseAABB: Traverse a 2D volume and only check that the endpoint is correct")
590 1 : {
591 : // setup
592 1 : size_t dim = 2;
593 1 : index_t x = 10;
594 1 : index_t y = 10;
595 1 : IndexVector_t volumeDims(dim);
596 1 : volumeDims << x, y;
597 :
598 1 : RealVector_t spacing(dim);
599 1 : RealVector_t ro(dim);
600 1 : RealVector_t rd(dim);
601 :
602 1 : GIVEN("A 10x10 volume with uniform scaling")
603 1 : {
604 1 : BoundingBox aabb(volumeDims);
605 :
606 1 : WHEN("The volume is traversed with a ray with origin = (-0.5, 0.5, 0.5) and a direction = "
607 1 : "(0, 1, 0)")
608 1 : {
609 1 : ro << -1, 4.5;
610 1 : rd << 1.0, 0;
611 :
612 1 : RealRay_t r(ro, rd);
613 1 : TraverseAABB traverse(aabb, r);
614 1 : CHECK_UNARY(traverse.isInBoundingBox());
615 :
616 11 : while (traverse.isInBoundingBox())
617 10 : traverse.updateTraverse();
618 :
619 1 : THEN("The endpoint should be (10,4)")
620 1 : {
621 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
622 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 10);
623 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 4);
624 1 : }
625 1 : }
626 1 : }
627 1 : }
628 :
629 : TEST_CASE("TraverseAABB: Traverse a 3D Volume diagonally")
630 2 : {
631 : // TODO: run through all 4 diagonals
632 : // TODO: make a non cube volume and run through all 4 diagonals
633 : // TODO: make non uniform scaling and run through all 4 diagonals
634 :
635 2 : size_t dim = 3;
636 2 : IndexVector_t volumeDims(dim);
637 2 : volumeDims << 10, 10, 10;
638 :
639 2 : RealVector_t spacing(dim);
640 2 : RealVector_t ro(dim);
641 2 : RealVector_t rd(dim);
642 :
643 2 : GIVEN("A 10x10 volume with uniform scaling")
644 2 : {
645 2 : BoundingBox aabb(volumeDims);
646 2 : WHEN("Start at (-1, -1, -1) (so bottom left front) and run to (10, 10, 10) (so top right "
647 2 : "back)")
648 2 : {
649 2 : ro << -1.0, -1.0, -1.0;
650 2 : rd << 1.0, 1.0, 1.0;
651 2 : rd.normalize();
652 :
653 2 : RealRay_t r(ro, rd);
654 :
655 2 : TraverseAABB traverse(aabb, r);
656 2 : CHECK_UNARY(traverse.isInBoundingBox());
657 :
658 2 : THEN("You entered at (0, 0, 0)")
659 2 : {
660 1 : CHECK_EQ(traverse.getCurrentVoxel()(0), 0);
661 1 : CHECK_EQ(traverse.getCurrentVoxel()(1), 0);
662 1 : CHECK_EQ(traverse.getCurrentVoxel()(2), 0);
663 1 : }
664 58 : while (traverse.isInBoundingBox())
665 56 : traverse.updateTraverse();
666 :
667 2 : THEN("You leave the volume at (10, 9, 9)")
668 2 : {
669 1 : REQUIRE_UNARY_FALSE(traverse.isInBoundingBox());
670 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 10);
671 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 9);
672 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(2), 9);
673 1 : }
674 2 : }
675 2 : }
676 2 : }
677 :
678 : TEST_CASE("TraverseAABB: Check that the first step into the 2D Volume is correct")
679 4 : {
680 4 : size_t dim = 2;
681 4 : index_t x = 5;
682 4 : index_t y = 5;
683 4 : IndexVector_t volumeDims(dim);
684 4 : volumeDims << x, y;
685 :
686 4 : RealVector_t ro(dim);
687 4 : RealVector_t rd(dim);
688 :
689 4 : GIVEN("A 5x5 volume with uniform scaling")
690 4 : {
691 4 : BoundingBox aabb(volumeDims);
692 :
693 4 : WHEN("The ray direction has the biggest value on the y axis")
694 4 : {
695 2 : ro << 0, 0;
696 2 : rd << 0.5f, 0.7f;
697 2 : rd.normalize();
698 :
699 2 : RealRay_t r(ro, rd);
700 2 : TraverseAABB traverse(aabb, r);
701 2 : CHECK_UNARY(traverse.isInBoundingBox());
702 :
703 2 : THEN("The traversal is initially at (0, 0)")
704 2 : {
705 1 : auto voxel = traverse.getCurrentVoxel();
706 1 : CHECK_EQ(voxel(0), 0);
707 1 : CHECK_EQ(voxel(1), 0);
708 1 : }
709 :
710 2 : traverse.updateTraverse();
711 :
712 2 : THEN("The first step is in y direction")
713 2 : {
714 1 : REQUIRE_UNARY(traverse.isInBoundingBox());
715 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 0);
716 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 1);
717 1 : }
718 2 : }
719 :
720 4 : WHEN("The ray direction has the biggest value on the x axis")
721 4 : {
722 2 : ro << 0, 0;
723 2 : rd << 0.7f, 0.5f;
724 2 : rd.normalize();
725 :
726 2 : RealRay_t r(ro, rd);
727 2 : TraverseAABB traverse(aabb, r);
728 2 : CHECK_UNARY(traverse.isInBoundingBox());
729 :
730 2 : THEN("The traversal is initially at (0, 0)")
731 2 : {
732 1 : auto voxel = traverse.getCurrentVoxel();
733 1 : CHECK_EQ(voxel(0), 0);
734 1 : CHECK_EQ(voxel(1), 0);
735 1 : }
736 :
737 2 : traverse.updateTraverse();
738 :
739 2 : THEN("The first step is in y direction")
740 2 : {
741 1 : REQUIRE_UNARY(traverse.isInBoundingBox());
742 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(0), 1);
743 1 : REQUIRE_EQ(traverse.getCurrentVoxel()(1), 0);
744 1 : }
745 2 : }
746 4 : }
747 4 : }
748 :
749 : TEST_CASE("TraverseAABB: Traverse_Volume_2D_EachPointIsTested")
750 1 : {
751 : // setup
752 1 : size_t dim = 2;
753 1 : index_t x = 128;
754 1 : index_t y = 128;
755 1 : IndexVector_t volumeDims(dim);
756 1 : volumeDims << x, y;
757 1 : BoundingBox aabb(volumeDims);
758 :
759 1 : RealVector_t ro(dim);
760 1 : ro << -168.274f, -143.397f;
761 1 : RealVector_t rd(dim);
762 1 : rd << 0.761124909f, 0.648605406f;
763 1 : rd.normalize();
764 1 : RealRay_t r(ro, rd);
765 :
766 1 : TraverseAABB traverse(aabb, r);
767 1 : CHECK_UNARY(traverse.isInBoundingBox());
768 :
769 1 : size_t iter = 0;
770 238 : while (traverse.isInBoundingBox()) {
771 237 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
772 237 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
773 :
774 237 : REQUIRE_UNARY(intersect(voxel, r));
775 237 : traverse.updateTraverse();
776 237 : iter++;
777 237 : }
778 1 : }
779 :
780 : TEST_CASE("TraverseAABB: Traversal through 2D volume should be equal to a ray voxel intersection "
781 : "for every voxel along the way")
782 8 : {
783 : // TODO make this a stronger test, for first some "easy" direction (parallel ones)
784 : // TODO Then make some harder ones
785 : // setup
786 8 : size_t dim = 2;
787 8 : index_t x = 128;
788 8 : index_t y = 128;
789 8 : IndexVector_t volumeDims(dim);
790 8 : volumeDims << x, y;
791 8 : BoundingBox aabb(volumeDims);
792 :
793 8 : RealVector_t ro(dim);
794 8 : RealVector_t rd(dim);
795 :
796 8 : GIVEN("a point at the bottom left of the volume and a ray with leading dimension x")
797 8 : {
798 1 : ro << -168.274f, -143.397f;
799 :
800 1 : rd << 0.761124909f, 0.648605406f;
801 1 : rd.normalize();
802 :
803 1 : RealRay_t r(ro, rd);
804 :
805 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
806 1 : {
807 1 : TraverseAABB traverse(aabb, r);
808 1 : CHECK_UNARY(traverse.isInBoundingBox());
809 :
810 1 : size_t iter = 0;
811 238 : while (traverse.isInBoundingBox()) {
812 237 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
813 237 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
814 :
815 237 : REQUIRE_UNARY(intersect(voxel, r));
816 237 : traverse.updateTraverse();
817 237 : iter++;
818 237 : }
819 1 : }
820 1 : }
821 :
822 8 : GIVEN("a point at the bottom left of the volume and a ray with leading dimension y")
823 8 : {
824 1 : ro << 0, 0;
825 :
826 1 : rd << 0.648605406f, 0.761124909f;
827 1 : rd.normalize();
828 :
829 1 : RealRay_t r(ro, rd);
830 :
831 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
832 1 : {
833 1 : TraverseAABB traverse(aabb, r);
834 1 : CHECK_UNARY(traverse.isInBoundingBox());
835 :
836 1 : size_t iter = 0;
837 238 : while (traverse.isInBoundingBox()) {
838 237 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
839 237 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
840 :
841 237 : REQUIRE_UNARY(intersect(voxel, r));
842 237 : traverse.updateTraverse();
843 237 : iter++;
844 237 : }
845 1 : }
846 1 : }
847 :
848 8 : GIVEN("a ray going through the border of voxel column 0 and 1")
849 8 : {
850 1 : ro << 1, -0.5f;
851 :
852 1 : rd << 0, 1;
853 1 : rd.normalize();
854 :
855 1 : RealRay_t r(ro, rd);
856 :
857 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
858 1 : {
859 1 : TraverseAABB traverse(aabb, r);
860 1 : CHECK_UNARY(traverse.isInBoundingBox());
861 :
862 1 : size_t iter = 0;
863 129 : while (traverse.isInBoundingBox()) {
864 128 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
865 128 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
866 :
867 128 : REQUIRE_UNARY(intersect(voxel, r));
868 128 : traverse.updateTraverse();
869 128 : iter++;
870 128 : }
871 1 : }
872 1 : }
873 :
874 8 : GIVEN("a ray going through the border of voxel row 0 and 1")
875 8 : {
876 1 : ro << -0.5f, 1;
877 :
878 1 : rd << 1, 0;
879 1 : rd.normalize();
880 :
881 1 : RealRay_t r(ro, rd);
882 :
883 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
884 1 : {
885 1 : TraverseAABB traverse(aabb, r);
886 1 : CHECK_UNARY(traverse.isInBoundingBox());
887 :
888 1 : size_t iter = 0;
889 129 : while (traverse.isInBoundingBox()) {
890 128 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
891 128 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
892 :
893 128 : REQUIRE_UNARY(intersect(voxel, r));
894 128 : traverse.updateTraverse();
895 128 : iter++;
896 128 : }
897 1 : }
898 1 : }
899 :
900 8 : GIVEN("A ray going diagonally through the volume")
901 8 : {
902 1 : ro << -0.5f, -0.5f;
903 :
904 1 : rd << 1, 1;
905 1 : rd.normalize();
906 :
907 1 : RealRay_t r(ro, rd);
908 :
909 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
910 1 : {
911 1 : TraverseAABB traverse(aabb, r);
912 1 : CHECK_UNARY(traverse.isInBoundingBox());
913 :
914 1 : size_t iter = 0;
915 256 : while (traverse.isInBoundingBox()) {
916 255 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
917 255 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
918 :
919 255 : REQUIRE_UNARY(intersect(voxel, r));
920 255 : traverse.updateTraverse();
921 255 : iter++;
922 255 : }
923 1 : }
924 1 : }
925 :
926 8 : GIVEN("A ray going diagonally through the volume")
927 8 : {
928 1 : ro << -0.5f, 32;
929 :
930 1 : rd << 1, 1;
931 1 : rd.normalize();
932 :
933 1 : RealRay_t r(ro, rd);
934 :
935 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
936 1 : {
937 1 : TraverseAABB traverse(aabb, r);
938 1 : CHECK_UNARY(traverse.isInBoundingBox());
939 :
940 1 : size_t iter = 0;
941 192 : while (traverse.isInBoundingBox()) {
942 191 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
943 191 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
944 :
945 191 : REQUIRE_UNARY(intersect(voxel, r));
946 191 : traverse.updateTraverse();
947 191 : iter++;
948 191 : }
949 1 : }
950 1 : }
951 :
952 8 : GIVEN("A ray going diagonally through the volume")
953 8 : {
954 1 : ro << -0.5f, -0.5f;
955 :
956 1 : rd << 0.699428f, 0.472203f;
957 1 : rd.normalize();
958 :
959 1 : RealRay_t r(ro, rd);
960 :
961 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
962 1 : {
963 1 : TraverseAABB traverse(aabb, r);
964 1 : CHECK_UNARY(traverse.isInBoundingBox());
965 :
966 1 : size_t iter = 0;
967 215 : while (traverse.isInBoundingBox()) {
968 214 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
969 214 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
970 :
971 214 : REQUIRE_UNARY(intersect(voxel, r));
972 214 : traverse.updateTraverse();
973 214 : iter++;
974 214 : }
975 1 : }
976 1 : }
977 :
978 8 : GIVEN("A ray going diagonally through the volume")
979 8 : {
980 1 : volumeDims << 64, 64;
981 1 : BoundingBox aabb(volumeDims);
982 :
983 1 : ro << 32.0002823f, 3232;
984 :
985 1 : rd << -0.000723466626f, -0.999999762f;
986 1 : rd.normalize();
987 :
988 1 : RealRay_t r(ro, rd);
989 :
990 1 : THEN("Then all points the traversal visits are also hit by the intersection algorithm")
991 1 : {
992 1 : TraverseAABB traverse(aabb, r);
993 1 : traverse.isInBoundingBox();
994 :
995 1 : size_t iter = 0;
996 65 : while (traverse.isInBoundingBox()) {
997 64 : RealVector_t voxel = traverse.getCurrentVoxel().template cast<real_t>();
998 64 : INFO("Current Voxel: (" << voxel(0) << ", " << voxel(1) << ") in iter: " << iter);
999 :
1000 64 : REQUIRE_UNARY(intersect(voxel, r));
1001 64 : traverse.updateTraverse();
1002 64 : iter++;
1003 64 : }
1004 1 : }
1005 1 : }
1006 8 : }
|