1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5
6 #include "axom/config.hpp"
7 #include "axom/primal/operators/detail/intersect_ray_impl.hpp"
8
9 #include "axom/core/numerics/Matrix.hpp" // for numerics::Matrix
10 #include "axom/core/numerics/matvecops.hpp" // for matrix-vector operators
11
12 #include "gtest/gtest.h"
13
14 // C/C++ includes
15 #include <cmath>
16
17 // namespace aliases
18 namespace primal = axom::primal;
19 namespace numerics = axom::numerics;
20
21 //------------------------------------------------------------------------------
22 // UNIT TESTS
23 //------------------------------------------------------------------------------
TEST(primal_ray_intersect,ray_aabb_intersection_2D)24 TEST(primal_ray_intersect, ray_aabb_intersection_2D)
25 {
26 constexpr int N = 3;
27 constexpr double LO = 0.0f;
28 constexpr double HI = 1.0f;
29
30 using namespace primal::detail;
31
32 // Defines the test box:
33 #define TEST_BOX2D LO, HI, LO, HI
34
35 double x[N];
36 numerics::linspace(LO, HI, x, N);
37
38 // test BOTTOM (-y)
39 {
40 const double n0[] = {0.0, 1.0};
41 const double y0 = -1.0f;
42 for(int i = 0; i < N; ++i)
43 {
44 double tmin = 0.0;
45 double tmax = 0.0;
46
47 const double sx = x[i];
48 const double sy = y0;
49 const double nx = n0[0];
50 const double ny = n0[1];
51 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, TEST_BOX2D, tmin, tmax));
52 EXPECT_FALSE(intersect_ray(sx, -nx, sy, -ny, TEST_BOX2D, tmin, tmax));
53 }
54 }
55
56 // test RIGHT (+x)
57 {
58 const double n0[] = {-1.0, 0.0};
59 const double x0 = 2.0f;
60 for(int i = 0; i < N; ++i)
61 {
62 double tmin = 0.0;
63 double tmax = 0.0;
64
65 const double sx = x0;
66 const double sy = x[i];
67 const double nx = n0[0];
68 const double ny = n0[1];
69 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, TEST_BOX2D, tmin, tmax));
70 EXPECT_FALSE(intersect_ray(sx, -nx, sy, -ny, TEST_BOX2D, tmin, tmax));
71 }
72 }
73
74 // test TOP (+y)
75 {
76 const double n0[] = {0.0, -1.0};
77 const double y0 = 2.0f;
78 for(int i = 0; i < N; ++i)
79 {
80 double tmin = 0.0;
81 double tmax = 0.0;
82
83 const double sx = x[i];
84 const double sy = y0;
85 const double nx = n0[0];
86 const double ny = n0[1];
87 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, TEST_BOX2D, tmin, tmax));
88 EXPECT_FALSE(intersect_ray(sx, -nx, sy, -ny, TEST_BOX2D, tmin, tmax));
89 }
90 }
91
92 // test LEFT (-x)
93 {
94 const double n0[] = {1.0, 0.0};
95 const double x0 = -1.0f;
96 for(int i = 0; i < N; ++i)
97 {
98 double tmin = 0.0;
99 double tmax = 0.0;
100
101 const double sx = x0;
102 const double sy = x[i];
103 const double nx = n0[0];
104 const double ny = n0[1];
105 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, TEST_BOX2D, tmin, tmax));
106 EXPECT_FALSE(intersect_ray(sx, -nx, sy, -ny, TEST_BOX2D, tmin, tmax));
107 }
108 }
109
110 // Test a bunch of rays emitted from the box center
111 constexpr int NUM_ANGLES = 20;
112 double angles[NUM_ANGLES];
113 numerics::linspace(0.0, 360.0, angles, NUM_ANGLES);
114
115 numerics::Matrix<double> rotation_matrix(2, 2);
116
117 constexpr double PI_OVER_180 = M_PI / 180.0;
118 const double xc[] = {0.5, 0.5};
119 const double e1[] = {1.0, 0.0};
120 for(int i = 0; i < NUM_ANGLES; ++i)
121 {
122 const double t = angles[i] * PI_OVER_180;
123 const double cost = cos(t);
124 const double sint = sin(t);
125
126 rotation_matrix(0, 0) = cost;
127 rotation_matrix(0, 1) = -sint;
128 rotation_matrix(1, 0) = sint;
129 rotation_matrix(1, 1) = cost;
130
131 double n[2];
132 numerics::matrix_vector_multiply(rotation_matrix, e1, n);
133
134 double tmin = 0.0;
135 double tmax = 0.0;
136 const double x0 = xc[0];
137 const double y0 = xc[1];
138 const double nx = n[0];
139 const double ny = n[1];
140 EXPECT_TRUE(intersect_ray(x0, nx, y0, ny, TEST_BOX2D, tmin, tmax));
141 EXPECT_TRUE(intersect_ray(x0, -nx, y0, -ny, TEST_BOX2D, tmin, tmax));
142 }
143
144 #undef TEST_BOX2D
145 }
146
147 //------------------------------------------------------------------------------
TEST(primal_ray_intersect,ray_aabb_intersection_3D)148 TEST(primal_ray_intersect, ray_aabb_intersection_3D)
149 {
150 constexpr int N = 3;
151 constexpr double LO = 0.0f;
152 constexpr double HI = 1.0f;
153
154 using namespace primal::detail;
155
156 // Defines the test box:
157 #define TEST_BOX3D LO, HI, LO, HI, LO, HI
158
159 double x[N];
160 numerics::linspace(LO, HI, x, N);
161
162 // test BOTTOM (-z)
163 {
164 const double n0[] = {0.0, 0.0, 1.0};
165 const double z0 = -1.0f;
166
167 for(int i = 0; i < N; ++i)
168 {
169 for(int j = 0; j < N; ++j)
170 {
171 double tmin = 0.0;
172 double tmax = 0.0;
173
174 const double sx = x[i];
175 const double sy = x[j];
176 const double sz = z0;
177 const double nx = n0[0];
178 const double ny = n0[1];
179 const double nz = n0[2];
180 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, sz, nz, TEST_BOX3D, tmin, tmax));
181 EXPECT_FALSE(
182 intersect_ray(sx, -nx, sy, -ny, sz, -nz, TEST_BOX3D, tmin, tmax));
183 } // END for all j
184 } // END for all i
185 }
186
187 // test TOP (+z)
188 {
189 const double n0[] = {0.0, 0.0, -1.0};
190 const double z0 = 2.0f;
191
192 for(int i = 0; i < N; ++i)
193 {
194 for(int j = 0; j < N; ++j)
195 {
196 double tmin = 0.0;
197 double tmax = 0.0;
198
199 const double sx = x[i];
200 const double sy = x[j];
201 const double sz = z0;
202 const double nx = n0[0];
203 const double ny = n0[1];
204 const double nz = n0[2];
205 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, sz, nz, TEST_BOX3D, tmin, tmax));
206 EXPECT_FALSE(
207 intersect_ray(sx, -nx, sy, -ny, sz, -nz, TEST_BOX3D, tmin, tmax));
208 } // END for all j
209 } // END for all i
210 }
211
212 // test LEFT (-y)
213 {
214 const double n0[] = {0.0, 1.0, 0.0};
215 const double y0 = -1.0f;
216
217 for(int i = 0; i < N; ++i)
218 {
219 for(int j = 0; j < N; ++j)
220 {
221 double tmin = 0.0;
222 double tmax = 0.0;
223
224 const double sx = x[i];
225 const double sy = y0;
226 const double sz = x[j];
227 const double nx = n0[0];
228 const double ny = n0[1];
229 const double nz = n0[2];
230 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, sz, nz, TEST_BOX3D, tmin, tmax));
231 EXPECT_FALSE(
232 intersect_ray(sx, -nx, sy, -ny, sz, -nz, TEST_BOX3D, tmin, tmax));
233 } // END for all j
234 } // END for all i
235 }
236
237 // test RIGHT (+y)
238 {
239 const double n0[] = {0.0, -1.0, 0.0};
240 const double y0 = 2.0f;
241
242 for(int i = 0; i < N; ++i)
243 {
244 for(int j = 0; j < N; ++j)
245 {
246 double tmin = 0.0;
247 double tmax = 0.0;
248
249 const double sx = x[i];
250 const double sy = y0;
251 const double sz = x[j];
252 const double nx = n0[0];
253 const double ny = n0[1];
254 const double nz = n0[2];
255 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, sz, nz, TEST_BOX3D, tmin, tmax));
256 EXPECT_FALSE(
257 intersect_ray(sx, -nx, sy, -ny, sz, -nz, TEST_BOX3D, tmin, tmax));
258 } // END for all j
259 } // END for all i
260 }
261
262 // test BACK (-x)
263 {
264 const double n0[] = {1.0, 0.0, 0.0};
265 const double x0 = -1.0f;
266
267 for(int i = 0; i < N; ++i)
268 {
269 for(int j = 0; j < N; ++j)
270 {
271 double tmin = 0.0;
272 double tmax = 0.0;
273
274 const double sx = x0;
275 const double sy = x[i];
276 const double sz = x[j];
277 const double nx = n0[0];
278 const double ny = n0[1];
279 const double nz = n0[2];
280 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, sz, nz, TEST_BOX3D, tmin, tmax));
281 EXPECT_FALSE(
282 intersect_ray(sx, -nx, sy, -ny, sz, -nz, TEST_BOX3D, tmin, tmax));
283 } // END for all j
284 } // END for all i
285 }
286
287 // test FRONT (+x)
288 {
289 const double n0[] = {-1.0, 0.0, 0.0};
290 const double x0 = 2.0f;
291
292 for(int i = 0; i < N; ++i)
293 {
294 for(int j = 0; j < N; ++j)
295 {
296 double tmin = 0.0;
297 double tmax = 0.0;
298
299 const double sx = x0;
300 const double sy = x[i];
301 const double sz = x[j];
302 const double nx = n0[0];
303 const double ny = n0[1];
304 const double nz = n0[2];
305 EXPECT_TRUE(intersect_ray(sx, nx, sy, ny, sz, nz, TEST_BOX3D, tmin, tmax));
306 EXPECT_FALSE(
307 intersect_ray(sx, -nx, sy, -ny, sz, -nz, TEST_BOX3D, tmin, tmax));
308 } // END for all j
309 } // END for all i
310 }
311
312 // Test a bunch of rays emitted from the box center
313 constexpr int NUM_ANGLES = 20;
314 double angles[NUM_ANGLES];
315 numerics::linspace(0.0, 360.0, angles, NUM_ANGLES);
316
317 numerics::Matrix<double> Rx(3, 3);
318 Rx(0, 0) = 1.0;
319 numerics::Matrix<double> Ry(3, 3);
320 Ry(1, 1) = 1.0;
321 numerics::Matrix<double> Rz(3, 3);
322 Rz(2, 2) = 1.0;
323
324 constexpr double PI_OVER_180 = M_PI / 180.0;
325 const double xc[] = {0.5, 0.5, 0.5};
326 const double e1[] = {1.0, 0.0, 0.0};
327 const double e2[] = {0.0, 1.0, 0.0};
328 const double e3[] = {0.0, 0.0, 1.0};
329 double n[3];
330 for(int i = 0; i < NUM_ANGLES; ++i)
331 {
332 const double t = angles[i] * PI_OVER_180;
333 const double cost = cos(t);
334 const double sint = sin(t);
335
336 double tmin = 0.0;
337 double tmax = 0.0;
338
339 double nx = 0.0;
340 double ny = 0.0;
341 double nz = 0.0;
342
343 const double x0 = xc[0];
344 const double y0 = xc[1];
345 const double z0 = xc[2];
346
347 // Update Rx
348 Rx(1, 1) = cost;
349 Rx(1, 2) = -sint;
350 Rx(2, 1) = sint;
351 Rx(2, 2) = cost;
352
353 numerics::matrix_vector_multiply(Rx, e1, n);
354 nx = n[0];
355 ny = n[1];
356 nz = n[2];
357 EXPECT_TRUE(intersect_ray(x0, nx, y0, ny, z0, nz, TEST_BOX3D, tmin, tmax));
358
359 // Update Ry
360 Ry(0, 0) = cost;
361 Ry(0, 2) = sint;
362 Ry(2, 0) = -sint;
363 Ry(2, 2) = cost;
364
365 numerics::matrix_vector_multiply(Ry, e2, n);
366 nx = n[0];
367 ny = n[1];
368 nz = n[2];
369 EXPECT_TRUE(intersect_ray(x0, nx, y0, ny, z0, nz, TEST_BOX3D, tmin, tmax));
370
371 // Update Rz
372 Rz(0, 0) = cost;
373 Rz(0, 1) = -sint;
374 Rz(1, 0) = sint;
375 Rz(1, 1) = cost;
376
377 numerics::matrix_vector_multiply(Rz, e3, n);
378 nx = n[0];
379 ny = n[1];
380 nz = n[2];
381 EXPECT_TRUE(intersect_ray(x0, nx, y0, ny, z0, nz, TEST_BOX3D, tmin, tmax));
382 }
383
384 #undef TEST_BOX3D
385 }
386
387 //------------------------------------------------------------------------------
388 #include "axom/slic/core/SimpleLogger.hpp"
389 using axom::slic::SimpleLogger;
390
main(int argc,char * argv[])391 int main(int argc, char* argv[])
392 {
393 int result = 0;
394
395 ::testing::InitGoogleTest(&argc, argv);
396
397 SimpleLogger logger; // create & initialize test logger,
398
399 // finalized when exiting main scope
400
401 result = RUN_ALL_TESTS();
402
403 return result;
404 }
405