Mercurial > hg > orthanc-stone
comparison UnitTestsSources/UnitTestsMain.cpp @ 1679:5b8b88e5bfd6
successfully running unit tests in WebAssembly
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 24 Nov 2020 12:59:10 +0100 |
parents | f62f685e0eb2 |
children | 03afa09cfcf1 |
comparison
equal
deleted
inserted
replaced
1678:1393e3393a0b | 1679:5b8b88e5bfd6 |
---|---|
19 **/ | 19 **/ |
20 | 20 |
21 | 21 |
22 #include <gtest/gtest.h> | 22 #include <gtest/gtest.h> |
23 | 23 |
24 #include "../OrthancStone/Sources/StoneEnumerations.h" | |
24 #include "../OrthancStone/Sources/StoneInitialization.h" | 25 #include "../OrthancStone/Sources/StoneInitialization.h" |
25 #include "../OrthancStone/Sources/Toolbox/FiniteProjectiveCamera.h" | |
26 #include "../OrthancStone/Sources/Toolbox/GenericToolbox.h" | |
27 #include "../OrthancStone/Sources/Toolbox/GeometryToolbox.h" | |
28 #include "../OrthancStone/Sources/Volumes/ImageBuffer3D.h" | |
29 | 26 |
30 #include <Images/ImageProcessing.h> | |
31 #include <Logging.h> | 27 #include <Logging.h> |
32 #include <MultiThreading/SharedMessageQueue.h> | |
33 #include <OrthancException.h> | |
34 | 28 |
35 #include <boost/lexical_cast.hpp> | 29 #if defined(__EMSCRIPTEN__) |
36 #include <boost/date_time/posix_time/posix_time.hpp> | 30 # include <emscripten.h> |
37 #include <boost/thread/thread.hpp> | 31 #endif |
38 #include <boost/math/special_functions/round.hpp> | |
39 | 32 |
40 | |
41 TEST(GeometryToolbox, Interpolation) | |
42 { | |
43 using namespace OrthancStone::GeometryToolbox; | |
44 | |
45 // https://en.wikipedia.org/wiki/Bilinear_interpolation#Application_in_image_processing | |
46 ASSERT_DOUBLE_EQ(146.1f, ComputeBilinearInterpolationUnitSquare(0.5f, 0.2f, 91, 210, 162, 95)); | |
47 | |
48 ASSERT_DOUBLE_EQ(91, ComputeBilinearInterpolationUnitSquare(0, 0, 91, 210, 162, 95)); | |
49 ASSERT_DOUBLE_EQ(210, ComputeBilinearInterpolationUnitSquare(1, 0, 91, 210, 162, 95)); | |
50 ASSERT_DOUBLE_EQ(162, ComputeBilinearInterpolationUnitSquare(0, 1, 91, 210, 162, 95)); | |
51 ASSERT_DOUBLE_EQ(95, ComputeBilinearInterpolationUnitSquare(1, 1, 91, 210, 162, 95)); | |
52 | |
53 ASSERT_DOUBLE_EQ(123.35f, ComputeTrilinearInterpolationUnitSquare | |
54 (0.5f, 0.2f, 0.7f, | |
55 91, 210, 162, 95, | |
56 51, 190, 80, 92)); | |
57 | |
58 ASSERT_DOUBLE_EQ(ComputeBilinearInterpolationUnitSquare(0.5f, 0.2f, 91, 210, 162, 95), | |
59 ComputeTrilinearInterpolationUnitSquare(0.5f, 0.2f, 0, | |
60 91, 210, 162, 95, | |
61 51, 190, 80, 92)); | |
62 | |
63 ASSERT_DOUBLE_EQ(ComputeBilinearInterpolationUnitSquare(0.5f, 0.2f, 51, 190, 80, 92), | |
64 ComputeTrilinearInterpolationUnitSquare(0.5f, 0.2f, 1, | |
65 91, 210, 162, 95, | |
66 51, 190, 80, 92)); | |
67 } | |
68 | |
69 | |
70 static bool CompareMatrix(const OrthancStone::Matrix& a, | |
71 const OrthancStone::Matrix& b, | |
72 double threshold = 0.00000001) | |
73 { | |
74 if (a.size1() != b.size1() || | |
75 a.size2() != b.size2()) | |
76 { | |
77 return false; | |
78 } | |
79 | |
80 for (size_t i = 0; i < a.size1(); i++) | |
81 { | |
82 for (size_t j = 0; j < a.size2(); j++) | |
83 { | |
84 if (fabs(a(i, j) - b(i, j)) > threshold) | |
85 { | |
86 LOG(ERROR) << "Too large difference in component (" | |
87 << i << "," << j << "): " << a(i,j) << " != " << b(i,j); | |
88 return false; | |
89 } | |
90 } | |
91 } | |
92 | |
93 return true; | |
94 } | |
95 | |
96 | |
97 static bool CompareVector(const OrthancStone::Vector& a, | |
98 const OrthancStone::Vector& b, | |
99 double threshold = 0.00000001) | |
100 { | |
101 if (a.size() != b.size()) | |
102 { | |
103 return false; | |
104 } | |
105 | |
106 for (size_t i = 0; i < a.size(); i++) | |
107 { | |
108 if (fabs(a(i) - b(i)) > threshold) | |
109 { | |
110 LOG(ERROR) << "Too large difference in component " | |
111 << i << ": " << a(i) << " != " << b(i); | |
112 return false; | |
113 } | |
114 } | |
115 | |
116 return true; | |
117 } | |
118 | |
119 | |
120 | |
121 TEST(FiniteProjectiveCamera, Decomposition1) | |
122 { | |
123 // Example 6.2 of "Multiple View Geometry in Computer Vision - 2nd | |
124 // edition" (page 163) | |
125 const double p[12] = { | |
126 3.53553e+2, 3.39645e+2, 2.77744e+2, -1.44946e+6, | |
127 -1.03528e+2, 2.33212e+1, 4.59607e+2, -6.32525e+5, | |
128 7.07107e-1, -3.53553e-1, 6.12372e-1, -9.18559e+2 | |
129 }; | |
130 | |
131 OrthancStone::FiniteProjectiveCamera camera(p); | |
132 ASSERT_EQ(3u, camera.GetMatrix().size1()); | |
133 ASSERT_EQ(4u, camera.GetMatrix().size2()); | |
134 ASSERT_EQ(3u, camera.GetIntrinsicParameters().size1()); | |
135 ASSERT_EQ(3u, camera.GetIntrinsicParameters().size2()); | |
136 ASSERT_EQ(3u, camera.GetRotation().size1()); | |
137 ASSERT_EQ(3u, camera.GetRotation().size2()); | |
138 ASSERT_EQ(3u, camera.GetCenter().size()); | |
139 | |
140 ASSERT_NEAR(1000.0, camera.GetCenter()[0], 0.01); | |
141 ASSERT_NEAR(2000.0, camera.GetCenter()[1], 0.01); | |
142 ASSERT_NEAR(1500.0, camera.GetCenter()[2], 0.01); | |
143 | |
144 ASSERT_NEAR(468.2, camera.GetIntrinsicParameters() (0, 0), 0.1); | |
145 ASSERT_NEAR(91.2, camera.GetIntrinsicParameters() (0, 1), 0.1); | |
146 ASSERT_NEAR(300.0, camera.GetIntrinsicParameters() (0, 2), 0.1); | |
147 ASSERT_NEAR(427.2, camera.GetIntrinsicParameters() (1, 1), 0.1); | |
148 ASSERT_NEAR(200.0, camera.GetIntrinsicParameters() (1, 2), 0.1); | |
149 ASSERT_NEAR(1.0, camera.GetIntrinsicParameters() (2, 2), 0.1); | |
150 | |
151 ASSERT_NEAR(0, camera.GetIntrinsicParameters() (1, 0), 0.0000001); | |
152 ASSERT_NEAR(0, camera.GetIntrinsicParameters() (2, 0), 0.0000001); | |
153 ASSERT_NEAR(0, camera.GetIntrinsicParameters() (2, 1), 0.0000001); | |
154 | |
155 ASSERT_NEAR(0.41380, camera.GetRotation() (0, 0), 0.00001); | |
156 ASSERT_NEAR(0.90915, camera.GetRotation() (0, 1), 0.00001); | |
157 ASSERT_NEAR(0.04708, camera.GetRotation() (0, 2), 0.00001); | |
158 ASSERT_NEAR(-0.57338, camera.GetRotation() (1, 0), 0.00001); | |
159 ASSERT_NEAR(0.22011, camera.GetRotation() (1, 1), 0.00001); | |
160 ASSERT_NEAR(0.78917, camera.GetRotation() (1, 2), 0.00001); | |
161 ASSERT_NEAR(0.70711, camera.GetRotation() (2, 0), 0.00001); | |
162 ASSERT_NEAR(-0.35355, camera.GetRotation() (2, 1), 0.00001); | |
163 ASSERT_NEAR(0.61237, camera.GetRotation() (2, 2), 0.00001); | |
164 | |
165 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(camera.GetRotation())); | |
166 | |
167 OrthancStone::FiniteProjectiveCamera camera2(camera.GetIntrinsicParameters(), | |
168 camera.GetRotation(), | |
169 camera.GetCenter()); | |
170 | |
171 ASSERT_TRUE(CompareMatrix(camera.GetMatrix(), camera2.GetMatrix())); | |
172 ASSERT_TRUE(CompareMatrix(camera.GetIntrinsicParameters(), camera2.GetIntrinsicParameters())); | |
173 ASSERT_TRUE(CompareMatrix(camera.GetRotation(), camera2.GetRotation())); | |
174 ASSERT_TRUE(CompareVector(camera.GetCenter(), camera2.GetCenter())); | |
175 } | |
176 | |
177 | |
178 TEST(FiniteProjectiveCamera, Decomposition2) | |
179 { | |
180 const double p[] = { 1188.111986, 580.205341, -808.445330, 128000.000000, -366.466264, 1446.510501, 418.499736, 128000.000000, -0.487118, 0.291726, -0.823172, 500.000000 }; | |
181 const double k[] = { -1528.494743, 0.000000, 256.000000, 0.000000, 1528.494743, 256.000000, 0.000000, 0.000000, 1.000000 }; | |
182 const double r[] = { -0.858893, -0.330733, 0.391047, -0.158171, 0.897503, 0.411668, -0.487118, 0.291726, -0.823172 }; | |
183 const double c[] = { 243.558936, -145.863085, 411.585964 }; | |
184 | |
185 OrthancStone::FiniteProjectiveCamera camera(p); | |
186 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(camera.GetRotation())); | |
187 | |
188 OrthancStone::FiniteProjectiveCamera camera2(k, r, c); | |
189 ASSERT_TRUE(CompareMatrix(camera.GetMatrix(), camera2.GetMatrix(), 1)); | |
190 ASSERT_TRUE(CompareMatrix(camera.GetIntrinsicParameters(), camera2.GetIntrinsicParameters(), 0.001)); | |
191 ASSERT_TRUE(CompareMatrix(camera.GetRotation(), camera2.GetRotation(), 0.000001)); | |
192 ASSERT_TRUE(CompareVector(camera.GetCenter(), camera2.GetCenter(), 0.0001)); | |
193 } | |
194 | |
195 | |
196 TEST(FiniteProjectiveCamera, Decomposition3) | |
197 { | |
198 const double p[] = { 10, 0, 0, 0, | |
199 0, 20, 0, 0, | |
200 0, 0, 30, 0 }; | |
201 | |
202 OrthancStone::FiniteProjectiveCamera camera(p); | |
203 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(camera.GetRotation())); | |
204 ASSERT_DOUBLE_EQ(10, camera.GetIntrinsicParameters() (0, 0)); | |
205 ASSERT_DOUBLE_EQ(20, camera.GetIntrinsicParameters() (1, 1)); | |
206 ASSERT_DOUBLE_EQ(30, camera.GetIntrinsicParameters() (2, 2)); | |
207 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (0, 0)); | |
208 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (1, 1)); | |
209 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (2, 2)); | |
210 ASSERT_DOUBLE_EQ(0, camera.GetCenter() (0)); | |
211 ASSERT_DOUBLE_EQ(0, camera.GetCenter() (1)); | |
212 ASSERT_DOUBLE_EQ(0, camera.GetCenter() (2)); | |
213 } | |
214 | |
215 | |
216 TEST(FiniteProjectiveCamera, Decomposition4) | |
217 { | |
218 const double p[] = { 1, 0, 0, 10, | |
219 0, 1, 0, 20, | |
220 0, 0, 1, 30 }; | |
221 | |
222 OrthancStone::FiniteProjectiveCamera camera(p); | |
223 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(camera.GetRotation())); | |
224 ASSERT_DOUBLE_EQ(1, camera.GetIntrinsicParameters() (0, 0)); | |
225 ASSERT_DOUBLE_EQ(1, camera.GetIntrinsicParameters() (1, 1)); | |
226 ASSERT_DOUBLE_EQ(1, camera.GetIntrinsicParameters() (2, 2)); | |
227 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (0, 0)); | |
228 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (1, 1)); | |
229 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (2, 2)); | |
230 ASSERT_DOUBLE_EQ(-10, camera.GetCenter() (0)); | |
231 ASSERT_DOUBLE_EQ(-20, camera.GetCenter() (1)); | |
232 ASSERT_DOUBLE_EQ(-30, camera.GetCenter() (2)); | |
233 } | |
234 | |
235 | |
236 TEST(FiniteProjectiveCamera, Decomposition5) | |
237 { | |
238 const double p[] = { 0, 0, 10, 0, | |
239 0, 20, 0, 0, | |
240 30, 0, 0, 0 }; | |
241 | |
242 OrthancStone::FiniteProjectiveCamera camera(p); | |
243 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(camera.GetRotation())); | |
244 ASSERT_DOUBLE_EQ(-10, camera.GetIntrinsicParameters() (0, 0)); | |
245 ASSERT_DOUBLE_EQ(20, camera.GetIntrinsicParameters() (1, 1)); | |
246 ASSERT_DOUBLE_EQ(30, camera.GetIntrinsicParameters() (2, 2)); | |
247 ASSERT_DOUBLE_EQ(-1, camera.GetRotation() (0, 2)); | |
248 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (1, 1)); | |
249 ASSERT_DOUBLE_EQ(1, camera.GetRotation() (2, 0)); | |
250 ASSERT_DOUBLE_EQ(0, camera.GetCenter() (0)); | |
251 ASSERT_DOUBLE_EQ(0, camera.GetCenter() (1)); | |
252 ASSERT_DOUBLE_EQ(0, camera.GetCenter() (2)); | |
253 | |
254 OrthancStone::FiniteProjectiveCamera camera2(camera.GetIntrinsicParameters(), | |
255 camera.GetRotation(), | |
256 camera.GetCenter()); | |
257 ASSERT_TRUE(CompareMatrix(camera.GetMatrix(), camera2.GetMatrix())); | |
258 ASSERT_TRUE(CompareMatrix(camera.GetIntrinsicParameters(), camera2.GetIntrinsicParameters())); | |
259 ASSERT_TRUE(CompareMatrix(camera.GetRotation(), camera2.GetRotation())); | |
260 ASSERT_TRUE(CompareVector(camera.GetCenter(), camera2.GetCenter())); | |
261 } | |
262 | |
263 | |
264 static double GetCosAngle(const OrthancStone::Vector& a, | |
265 const OrthancStone::Vector& b) | |
266 { | |
267 // Returns the cosine of the angle between two vectors | |
268 // https://en.wikipedia.org/wiki/Dot_product#Geometric_definition | |
269 return boost::numeric::ublas::inner_prod(a, b) / | |
270 (boost::numeric::ublas::norm_2(a) * boost::numeric::ublas::norm_2(b)); | |
271 } | |
272 | |
273 | |
274 TEST(FiniteProjectiveCamera, Ray) | |
275 { | |
276 const double pp[] = { -1499.650894, 2954.618773, -259.737419, 637891.819097, | |
277 -2951.517707, -1501.019129, -285.785281, 637891.819097, | |
278 0.008528, 0.003067, -0.999959, 2491.764918 }; | |
279 | |
280 const OrthancStone::FiniteProjectiveCamera camera(pp); | |
281 | |
282 ASSERT_NEAR(-21.2492, camera.GetCenter() (0), 0.0001); | |
283 ASSERT_NEAR(-7.64234, camera.GetCenter() (1), 0.00001); | |
284 ASSERT_NEAR(2491.66, camera.GetCenter() (2), 0.01); | |
285 | |
286 // Image plane that led to these parameters, with principal point at | |
287 // (256,256). The image has dimensions 512x512. | |
288 OrthancStone::Vector o = | |
289 OrthancStone::LinearAlgebra::CreateVector(7.009620, 2.521030, -821.942000); | |
290 OrthancStone::Vector ax = | |
291 OrthancStone::LinearAlgebra::CreateVector(-0.453219, 0.891399, -0.001131); | |
292 OrthancStone::Vector ay = | |
293 OrthancStone::LinearAlgebra::CreateVector(-0.891359, -0.453210, -0.008992); | |
294 | |
295 OrthancStone::CoordinateSystem3D imagePlane(o, ax, ay); | |
296 | |
297 // Back-projection of the principal point | |
298 { | |
299 OrthancStone::Vector ray = camera.GetRayDirection(256, 256); | |
300 | |
301 // The principal axis vector is orthogonal to the image plane | |
302 // (i.e. parallel to the plane normal), in the opposite direction | |
303 // ("-1" corresponds to "cos(pi)"). | |
304 ASSERT_NEAR(-1, GetCosAngle(ray, imagePlane.GetNormal()), 0.0000001); | |
305 | |
306 // Forward projection of principal axis, resulting in the principal point | |
307 double x, y; | |
308 camera.ApplyFinite(x, y, camera.GetCenter() - ray); | |
309 | |
310 ASSERT_NEAR(256, x, 0.00001); | |
311 ASSERT_NEAR(256, y, 0.00001); | |
312 } | |
313 | |
314 // Back-projection of the 4 corners of the image | |
315 std::vector<double> cx, cy; | |
316 cx.push_back(0); | |
317 cy.push_back(0); | |
318 cx.push_back(512); | |
319 cy.push_back(0); | |
320 cx.push_back(512); | |
321 cy.push_back(512); | |
322 cx.push_back(0); | |
323 cy.push_back(512); | |
324 | |
325 bool first = true; | |
326 double angle; | |
327 | |
328 for (size_t i = 0; i < cx.size(); i++) | |
329 { | |
330 OrthancStone::Vector ray = camera.GetRayDirection(cx[i], cy[i]); | |
331 | |
332 // Check that the angle wrt. principal axis is the same for all | |
333 // the 4 corners | |
334 double a = GetCosAngle(ray, imagePlane.GetNormal()); | |
335 if (first) | |
336 { | |
337 first = false; | |
338 angle = a; | |
339 } | |
340 else | |
341 { | |
342 ASSERT_NEAR(angle, a, 0.000001); | |
343 } | |
344 | |
345 // Forward projection of the ray, going back to the original point | |
346 double x, y; | |
347 camera.ApplyFinite(x, y, camera.GetCenter() - ray); | |
348 | |
349 ASSERT_NEAR(cx[i], x, 0.00001); | |
350 ASSERT_NEAR(cy[i], y, 0.00001); | |
351 | |
352 // Alternative construction, by computing the intersection of the | |
353 // ray with the image plane | |
354 OrthancStone::Vector p; | |
355 ASSERT_TRUE(imagePlane.IntersectLine(p, camera.GetCenter(), -ray)); | |
356 imagePlane.ProjectPoint(x, y, p); | |
357 ASSERT_NEAR(cx[i], x + 256, 0.01); | |
358 ASSERT_NEAR(cy[i], y + 256, 0.01); | |
359 } | |
360 } | |
361 | |
362 | |
363 TEST(Matrix, Inverse1) | |
364 { | |
365 OrthancStone::Matrix a, b; | |
366 | |
367 a.resize(0, 0); | |
368 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
369 ASSERT_EQ(0u, b.size1()); | |
370 ASSERT_EQ(0u, b.size2()); | |
371 | |
372 a.resize(2, 3); | |
373 ASSERT_THROW(OrthancStone::LinearAlgebra::InvertMatrix(b, a), Orthanc::OrthancException); | |
374 | |
375 a.resize(1, 1); | |
376 a(0, 0) = 45.0; | |
377 | |
378 ASSERT_DOUBLE_EQ(45, OrthancStone::LinearAlgebra::ComputeDeterminant(a)); | |
379 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
380 ASSERT_EQ(1u, b.size1()); | |
381 ASSERT_EQ(1u, b.size2()); | |
382 ASSERT_DOUBLE_EQ(1.0 / 45.0, b(0, 0)); | |
383 | |
384 a(0, 0) = 0; | |
385 ASSERT_DOUBLE_EQ(0, OrthancStone::LinearAlgebra::ComputeDeterminant(a)); | |
386 ASSERT_THROW(OrthancStone::LinearAlgebra::InvertMatrix(b, a), Orthanc::OrthancException); | |
387 } | |
388 | |
389 | |
390 TEST(Matrix, Inverse2) | |
391 { | |
392 OrthancStone::Matrix a, b; | |
393 a.resize(2, 2); | |
394 a(0, 0) = 4; | |
395 a(0, 1) = 3; | |
396 a(1, 0) = 3; | |
397 a(1, 1) = 2; | |
398 | |
399 ASSERT_DOUBLE_EQ(-1, OrthancStone::LinearAlgebra::ComputeDeterminant(a)); | |
400 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
401 ASSERT_EQ(2u, b.size1()); | |
402 ASSERT_EQ(2u, b.size2()); | |
403 | |
404 ASSERT_DOUBLE_EQ(-2, b(0, 0)); | |
405 ASSERT_DOUBLE_EQ(3, b(0, 1)); | |
406 ASSERT_DOUBLE_EQ(3, b(1, 0)); | |
407 ASSERT_DOUBLE_EQ(-4, b(1, 1)); | |
408 | |
409 a(0, 0) = 1; | |
410 a(0, 1) = 2; | |
411 a(1, 0) = 3; | |
412 a(1, 1) = 4; | |
413 | |
414 ASSERT_DOUBLE_EQ(-2, OrthancStone::LinearAlgebra::ComputeDeterminant(a)); | |
415 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
416 | |
417 ASSERT_DOUBLE_EQ(-2, b(0, 0)); | |
418 ASSERT_DOUBLE_EQ(1, b(0, 1)); | |
419 ASSERT_DOUBLE_EQ(1.5, b(1, 0)); | |
420 ASSERT_DOUBLE_EQ(-0.5, b(1, 1)); | |
421 } | |
422 | |
423 | |
424 TEST(Matrix, Inverse3) | |
425 { | |
426 OrthancStone::Matrix a, b; | |
427 a.resize(3, 3); | |
428 a(0, 0) = 7; | |
429 a(0, 1) = 2; | |
430 a(0, 2) = 1; | |
431 a(1, 0) = 0; | |
432 a(1, 1) = 3; | |
433 a(1, 2) = -1; | |
434 a(2, 0) = -3; | |
435 a(2, 1) = 4; | |
436 a(2, 2) = -2; | |
437 | |
438 ASSERT_DOUBLE_EQ(1, OrthancStone::LinearAlgebra::ComputeDeterminant(a)); | |
439 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
440 ASSERT_EQ(3u, b.size1()); | |
441 ASSERT_EQ(3u, b.size2()); | |
442 | |
443 ASSERT_DOUBLE_EQ(-2, b(0, 0)); | |
444 ASSERT_DOUBLE_EQ(8, b(0, 1)); | |
445 ASSERT_DOUBLE_EQ(-5, b(0, 2)); | |
446 ASSERT_DOUBLE_EQ(3, b(1, 0)); | |
447 ASSERT_DOUBLE_EQ(-11, b(1, 1)); | |
448 ASSERT_DOUBLE_EQ(7, b(1, 2)); | |
449 ASSERT_DOUBLE_EQ(9, b(2, 0)); | |
450 ASSERT_DOUBLE_EQ(-34, b(2, 1)); | |
451 ASSERT_DOUBLE_EQ(21, b(2, 2)); | |
452 | |
453 | |
454 a(0, 0) = 1; | |
455 a(0, 1) = 2; | |
456 a(0, 2) = 2; | |
457 a(1, 0) = 1; | |
458 a(1, 1) = 0; | |
459 a(1, 2) = 1; | |
460 a(2, 0) = 1; | |
461 a(2, 1) = 2; | |
462 a(2, 2) = 1; | |
463 | |
464 ASSERT_DOUBLE_EQ(2, OrthancStone::LinearAlgebra::ComputeDeterminant(a)); | |
465 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
466 ASSERT_EQ(3u, b.size1()); | |
467 ASSERT_EQ(3u, b.size2()); | |
468 | |
469 ASSERT_DOUBLE_EQ(-1, b(0, 0)); | |
470 ASSERT_DOUBLE_EQ(1, b(0, 1)); | |
471 ASSERT_DOUBLE_EQ(1, b(0, 2)); | |
472 ASSERT_DOUBLE_EQ(0, b(1, 0)); | |
473 ASSERT_DOUBLE_EQ(-0.5, b(1, 1)); | |
474 ASSERT_DOUBLE_EQ(0.5, b(1, 2)); | |
475 ASSERT_DOUBLE_EQ(1, b(2, 0)); | |
476 ASSERT_DOUBLE_EQ(0, b(2, 1)); | |
477 ASSERT_DOUBLE_EQ(-1, b(2, 2)); | |
478 } | |
479 | |
480 | |
481 TEST(Matrix, Inverse4) | |
482 { | |
483 OrthancStone::Matrix a, b; | |
484 a.resize(4, 4); | |
485 a(0, 0) = 2; | |
486 a(0, 1) = 1; | |
487 a(0, 2) = 2; | |
488 a(0, 3) = -3; | |
489 a(1, 0) = -2; | |
490 a(1, 1) = 2; | |
491 a(1, 2) = -1; | |
492 a(1, 3) = -1; | |
493 a(2, 0) = 2; | |
494 a(2, 1) = 2; | |
495 a(2, 2) = -3; | |
496 a(2, 3) = -1; | |
497 a(3, 0) = 3; | |
498 a(3, 1) = -2; | |
499 a(3, 2) = -3; | |
500 a(3, 3) = -1; | |
501 | |
502 OrthancStone::LinearAlgebra::InvertMatrix(b, a); | |
503 ASSERT_EQ(4u, b.size1()); | |
504 ASSERT_EQ(4u, b.size2()); | |
505 | |
506 b *= 134.0; // This is the determinant | |
507 | |
508 ASSERT_DOUBLE_EQ(8, b(0, 0)); | |
509 ASSERT_DOUBLE_EQ(-44, b(0, 1)); | |
510 ASSERT_DOUBLE_EQ(30, b(0, 2)); | |
511 ASSERT_DOUBLE_EQ(-10, b(0, 3)); | |
512 ASSERT_DOUBLE_EQ(2, b(1, 0)); | |
513 ASSERT_DOUBLE_EQ(-11, b(1, 1)); | |
514 ASSERT_DOUBLE_EQ(41, b(1, 2)); | |
515 ASSERT_DOUBLE_EQ(-36, b(1, 3)); | |
516 ASSERT_DOUBLE_EQ(16, b(2, 0)); | |
517 ASSERT_DOUBLE_EQ(-21, b(2, 1)); | |
518 ASSERT_DOUBLE_EQ(-7, b(2, 2)); | |
519 ASSERT_DOUBLE_EQ(-20, b(2, 3)); | |
520 ASSERT_DOUBLE_EQ(-28, b(3, 0)); | |
521 ASSERT_DOUBLE_EQ(-47, b(3, 1)); | |
522 ASSERT_DOUBLE_EQ(29, b(3, 2)); | |
523 ASSERT_DOUBLE_EQ(-32, b(3, 3)); | |
524 } | |
525 | |
526 | |
527 TEST(FiniteProjectiveCamera, Calibration) | |
528 { | |
529 unsigned int volumeWidth = 512; | |
530 unsigned int volumeHeight = 512; | |
531 unsigned int volumeDepth = 110; | |
532 | |
533 OrthancStone::Vector camera = OrthancStone::LinearAlgebra::CreateVector | |
534 (-1000, -5000, -static_cast<double>(volumeDepth) * 32); | |
535 | |
536 OrthancStone::Vector principalPoint = OrthancStone::LinearAlgebra::CreateVector | |
537 (volumeWidth/2, volumeHeight/2, volumeDepth * 2); | |
538 | |
539 OrthancStone::FiniteProjectiveCamera c(camera, principalPoint, 0, 512, 512, 1, 1); | |
540 | |
541 double swapv[9] = { 1, 0, 0, | |
542 0, -1, 512, | |
543 0, 0, 1 }; | |
544 OrthancStone::Matrix swap; | |
545 OrthancStone::LinearAlgebra::FillMatrix(swap, 3, 3, swapv); | |
546 | |
547 OrthancStone::Matrix p = OrthancStone::LinearAlgebra::Product(swap, c.GetMatrix()); | |
548 p /= p(2,3); | |
549 | |
550 ASSERT_NEAR( 1.04437, p(0,0), 0.00001); | |
551 ASSERT_NEAR(-0.0703111, p(0,1), 0.00000001); | |
552 ASSERT_NEAR(-0.179283, p(0,2), 0.000001); | |
553 ASSERT_NEAR( 61.7431, p(0,3), 0.0001); | |
554 ASSERT_NEAR( 0.11127, p(1,0), 0.000001); | |
555 ASSERT_NEAR(-0.595541, p(1,1), 0.000001); | |
556 ASSERT_NEAR( 0.872211, p(1,2), 0.000001); | |
557 ASSERT_NEAR( 203.748, p(1,3), 0.001); | |
558 ASSERT_NEAR( 3.08593e-05, p(2,0), 0.0000000001); | |
559 ASSERT_NEAR( 0.000129138, p(2,1), 0.000000001); | |
560 ASSERT_NEAR( 9.18901e-05, p(2,2), 0.0000000001); | |
561 ASSERT_NEAR( 1, p(2,3), 0.0000001); | |
562 } | |
563 | |
564 | |
565 static bool IsEqualRotationVector(OrthancStone::Vector a, | |
566 OrthancStone::Vector b) | |
567 { | |
568 if (a.size() != b.size() || | |
569 a.size() != 3) | |
570 { | |
571 return false; | |
572 } | |
573 else | |
574 { | |
575 OrthancStone::LinearAlgebra::NormalizeVector(a); | |
576 OrthancStone::LinearAlgebra::NormalizeVector(b); | |
577 return OrthancStone::LinearAlgebra::IsCloseToZero(boost::numeric::ublas::norm_2(a - b)); | |
578 } | |
579 } | |
580 | |
581 | |
582 TEST(GeometryToolbox, AlignVectorsWithRotation) | |
583 { | |
584 OrthancStone::Vector a, b; | |
585 OrthancStone::Matrix r; | |
586 | |
587 OrthancStone::LinearAlgebra::AssignVector(a, -200, 200, -846.63); | |
588 OrthancStone::LinearAlgebra::AssignVector(b, 0, 0, 1); | |
589 | |
590 OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, a, b); | |
591 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(r)); | |
592 ASSERT_TRUE(IsEqualRotationVector(OrthancStone::LinearAlgebra::Product(r, a), b)); | |
593 | |
594 OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, b, a); | |
595 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(r)); | |
596 ASSERT_TRUE(IsEqualRotationVector(OrthancStone::LinearAlgebra::Product(r, b), a)); | |
597 | |
598 OrthancStone::LinearAlgebra::AssignVector(a, 1, 0, 0); | |
599 OrthancStone::LinearAlgebra::AssignVector(b, 0, 0, 1); | |
600 OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, a, b); | |
601 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(r)); | |
602 ASSERT_TRUE(IsEqualRotationVector(OrthancStone::LinearAlgebra::Product(r, a), b)); | |
603 | |
604 OrthancStone::LinearAlgebra::AssignVector(a, 0, 1, 0); | |
605 OrthancStone::LinearAlgebra::AssignVector(b, 0, 0, 1); | |
606 OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, a, b); | |
607 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(r)); | |
608 ASSERT_TRUE(IsEqualRotationVector(OrthancStone::LinearAlgebra::Product(r, a), b)); | |
609 | |
610 OrthancStone::LinearAlgebra::AssignVector(a, 0, 0, 1); | |
611 OrthancStone::LinearAlgebra::AssignVector(b, 0, 0, 1); | |
612 OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, a, b); | |
613 ASSERT_TRUE(OrthancStone::LinearAlgebra::IsRotationMatrix(r)); | |
614 ASSERT_TRUE(IsEqualRotationVector(OrthancStone::LinearAlgebra::Product(r, a), b)); | |
615 | |
616 OrthancStone::LinearAlgebra::AssignVector(a, 0, 0, 0); | |
617 OrthancStone::LinearAlgebra::AssignVector(b, 0, 0, 1); | |
618 ASSERT_THROW(OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, a, b), Orthanc::OrthancException); | |
619 | |
620 // TODO: Deal with opposite vectors | |
621 | |
622 /* | |
623 OrthancStone::LinearAlgebra::AssignVector(a, 0, 0, -1); | |
624 OrthancStone::LinearAlgebra::AssignVector(b, 0, 0, 1); | |
625 OrthancStone::GeometryToolbox::AlignVectorsWithRotation(r, a, b); | |
626 OrthancStone::LinearAlgebra::Print(r); | |
627 OrthancStone::LinearAlgebra::Print(boost::numeric::ublas::prod(r, a)); | |
628 */ | |
629 } | |
630 | |
631 | |
632 static bool IsEqualVectorL1(OrthancStone::Vector a, | |
633 OrthancStone::Vector b) | |
634 { | |
635 if (a.size() != b.size()) | |
636 { | |
637 return false; | |
638 } | |
639 else | |
640 { | |
641 for (size_t i = 0; i < a.size(); i++) | |
642 { | |
643 if (!OrthancStone::LinearAlgebra::IsNear(a[i], b[i], 0.0001)) | |
644 { | |
645 return false; | |
646 } | |
647 } | |
648 | |
649 return true; | |
650 } | |
651 } | |
652 | |
653 | |
654 TEST(VolumeImageGeometry, Basic) | |
655 { | |
656 using namespace OrthancStone; | |
657 | |
658 VolumeImageGeometry g; | |
659 g.SetSizeInVoxels(10, 20, 30); | |
660 g.SetVoxelDimensions(1, 2, 3); | |
661 | |
662 Vector p = g.GetCoordinates(0, 0, 0); | |
663 ASSERT_EQ(3u, p.size()); | |
664 ASSERT_DOUBLE_EQ(-1.0 / 2.0, p[0]); | |
665 ASSERT_DOUBLE_EQ(-2.0 / 2.0, p[1]); | |
666 ASSERT_DOUBLE_EQ(-3.0 / 2.0, p[2]); | |
667 | |
668 p = g.GetCoordinates(1, 1, 1); | |
669 ASSERT_DOUBLE_EQ(-1.0 / 2.0 + 10.0 * 1.0, p[0]); | |
670 ASSERT_DOUBLE_EQ(-2.0 / 2.0 + 20.0 * 2.0, p[1]); | |
671 ASSERT_DOUBLE_EQ(-3.0 / 2.0 + 30.0 * 3.0, p[2]); | |
672 | |
673 VolumeProjection proj; | |
674 ASSERT_TRUE(g.DetectProjection(proj, g.GetAxialGeometry().GetNormal())); | |
675 ASSERT_EQ(VolumeProjection_Axial, proj); | |
676 ASSERT_TRUE(g.DetectProjection(proj, g.GetCoronalGeometry().GetNormal())); | |
677 ASSERT_EQ(VolumeProjection_Coronal, proj); | |
678 ASSERT_TRUE(g.DetectProjection(proj, g.GetSagittalGeometry().GetNormal())); | |
679 ASSERT_EQ(VolumeProjection_Sagittal, proj); | |
680 | |
681 ASSERT_EQ(10u, g.GetProjectionWidth(VolumeProjection_Axial)); | |
682 ASSERT_EQ(20u, g.GetProjectionHeight(VolumeProjection_Axial)); | |
683 ASSERT_EQ(30u, g.GetProjectionDepth(VolumeProjection_Axial)); | |
684 ASSERT_EQ(10u, g.GetProjectionWidth(VolumeProjection_Coronal)); | |
685 ASSERT_EQ(30u, g.GetProjectionHeight(VolumeProjection_Coronal)); | |
686 ASSERT_EQ(20u, g.GetProjectionDepth(VolumeProjection_Coronal)); | |
687 ASSERT_EQ(20u, g.GetProjectionWidth(VolumeProjection_Sagittal)); | |
688 ASSERT_EQ(30u, g.GetProjectionHeight(VolumeProjection_Sagittal)); | |
689 ASSERT_EQ(10u, g.GetProjectionDepth(VolumeProjection_Sagittal)); | |
690 | |
691 p = g.GetVoxelDimensions(VolumeProjection_Axial); | |
692 ASSERT_EQ(3u, p.size()); | |
693 ASSERT_DOUBLE_EQ(1, p[0]); | |
694 ASSERT_DOUBLE_EQ(2, p[1]); | |
695 ASSERT_DOUBLE_EQ(3, p[2]); | |
696 p = g.GetVoxelDimensions(VolumeProjection_Coronal); | |
697 ASSERT_EQ(3u, p.size()); | |
698 ASSERT_DOUBLE_EQ(1, p[0]); | |
699 ASSERT_DOUBLE_EQ(3, p[1]); | |
700 ASSERT_DOUBLE_EQ(2, p[2]); | |
701 p = g.GetVoxelDimensions(VolumeProjection_Sagittal); | |
702 ASSERT_EQ(3u, p.size()); | |
703 ASSERT_DOUBLE_EQ(2, p[0]); | |
704 ASSERT_DOUBLE_EQ(3, p[1]); | |
705 ASSERT_DOUBLE_EQ(1, p[2]); | |
706 | |
707 // Loop over all the voxels of the volume | |
708 for (unsigned int z = 0; z < g.GetDepth(); z++) | |
709 { | |
710 const float zz = (0.5f + static_cast<float>(z)) / static_cast<float>(g.GetDepth()); // Z-center of the voxel | |
711 | |
712 for (unsigned int y = 0; y < g.GetHeight(); y++) | |
713 { | |
714 const float yy = (0.5f + static_cast<float>(y)) / static_cast<float>(g.GetHeight()); // Y-center of the voxel | |
715 | |
716 for (unsigned int x = 0; x < g.GetWidth(); x++) | |
717 { | |
718 const float xx = (0.5f + static_cast<float>(x)) / static_cast<float>(g.GetWidth()); // X-center of the voxel | |
719 | |
720 const float sx = 1.0f; | |
721 const float sy = 2.0f; | |
722 const float sz = 3.0f; | |
723 | |
724 Vector p = g.GetCoordinates(xx, yy, zz); | |
725 | |
726 Vector q = (g.GetAxialGeometry().MapSliceToWorldCoordinates( | |
727 static_cast<double>(x) * sx, | |
728 static_cast<double>(y) * sy) + | |
729 z * sz * g.GetAxialGeometry().GetNormal()); | |
730 ASSERT_TRUE(IsEqualVectorL1(p, q)); | |
731 | |
732 q = (g.GetCoronalGeometry().MapSliceToWorldCoordinates( | |
733 static_cast<double>(x) * sx, | |
734 static_cast<double>(g.GetDepth() - 1 - z) * sz) + | |
735 y * sy * g.GetCoronalGeometry().GetNormal()); | |
736 ASSERT_TRUE(IsEqualVectorL1(p, q)); | |
737 | |
738 /** | |
739 * WARNING: In sagittal geometry, the normal points to | |
740 * REDUCING X-axis in the 3D world. This is necessary to keep | |
741 * the right-hand coordinate system. Hence the "-". | |
742 **/ | |
743 q = (g.GetSagittalGeometry().MapSliceToWorldCoordinates( | |
744 static_cast<double>(y) * sy, | |
745 static_cast<double>(g.GetDepth() - 1 - z) * sz) + | |
746 x * sx * (-g.GetSagittalGeometry().GetNormal())); | |
747 ASSERT_TRUE(IsEqualVectorL1(p, q)); | |
748 } | |
749 } | |
750 } | |
751 | |
752 ASSERT_EQ(0, (int) VolumeProjection_Axial); | |
753 ASSERT_EQ(1, (int) VolumeProjection_Coronal); | |
754 ASSERT_EQ(2, (int) VolumeProjection_Sagittal); | |
755 | |
756 for (int p = 0; p < 3; p++) | |
757 { | |
758 VolumeProjection projection = (VolumeProjection) p; | |
759 const CoordinateSystem3D& s = g.GetProjectionGeometry(projection); | |
760 | |
761 ASSERT_THROW(g.GetProjectionSlice(projection, g.GetProjectionDepth(projection)), Orthanc::OrthancException); | |
762 | |
763 for (unsigned int i = 0; i < g.GetProjectionDepth(projection); i++) | |
764 { | |
765 CoordinateSystem3D plane = g.GetProjectionSlice(projection, i); | |
766 | |
767 if (projection == VolumeProjection_Sagittal) | |
768 { | |
769 ASSERT_TRUE(IsEqualVectorL1(plane.GetOrigin(), s.GetOrigin() + static_cast<double>(i) * | |
770 (-s.GetNormal()) * g.GetVoxelDimensions(projection)[2])); | |
771 } | |
772 else | |
773 { | |
774 ASSERT_TRUE(IsEqualVectorL1(plane.GetOrigin(), s.GetOrigin() + static_cast<double>(i) * | |
775 s.GetNormal() * g.GetVoxelDimensions(projection)[2])); | |
776 } | |
777 | |
778 ASSERT_TRUE(IsEqualVectorL1(plane.GetAxisX(), s.GetAxisX())); | |
779 ASSERT_TRUE(IsEqualVectorL1(plane.GetAxisY(), s.GetAxisY())); | |
780 | |
781 unsigned int slice; | |
782 VolumeProjection q; | |
783 ASSERT_TRUE(g.DetectSlice(q, slice, plane)); | |
784 ASSERT_EQ(projection, q); | |
785 ASSERT_EQ(i, slice); | |
786 } | |
787 } | |
788 } | |
789 | |
790 | |
791 TEST(LinearAlgebra, ParseVectorLocale) | |
792 { | |
793 OrthancStone::Vector v; | |
794 | |
795 ASSERT_TRUE(OrthancStone::LinearAlgebra::ParseVector(v, "1.2")); | |
796 ASSERT_EQ(1u, v.size()); | |
797 ASSERT_DOUBLE_EQ(1.2, v[0]); | |
798 | |
799 ASSERT_TRUE(OrthancStone::LinearAlgebra::ParseVector(v, "-1.2e+2")); | |
800 ASSERT_EQ(1u, v.size()); | |
801 ASSERT_DOUBLE_EQ(-120.0, v[0]); | |
802 | |
803 ASSERT_TRUE(OrthancStone::LinearAlgebra::ParseVector(v, "-1e-2\\2")); | |
804 ASSERT_EQ(2u, v.size()); | |
805 ASSERT_DOUBLE_EQ(-0.01, v[0]); | |
806 ASSERT_DOUBLE_EQ(2.0, v[1]); | |
807 | |
808 ASSERT_TRUE(OrthancStone::LinearAlgebra::ParseVector(v, "1.3671875\\1.3671875")); | |
809 ASSERT_EQ(2u, v.size()); | |
810 ASSERT_DOUBLE_EQ(1.3671875, v[0]); | |
811 ASSERT_DOUBLE_EQ(1.3671875, v[1]); | |
812 } | |
813 | |
814 TEST(GenericToolbox, NormalizeUuid) | |
815 { | |
816 std::string ref("44ca5051-14ef-4d2f-8bd7-db20bfb61fbb"); | |
817 | |
818 { | |
819 std::string u("44ca5051-14ef-4d2f-8bd7-db20bfb61fbb"); | |
820 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
821 ASSERT_EQ(ref, u); | |
822 } | |
823 | |
824 // space left | |
825 { | |
826 std::string u(" 44ca5051-14ef-4d2f-8bd7-db20bfb61fbb"); | |
827 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
828 ASSERT_EQ(ref, u); | |
829 } | |
830 | |
831 // space right | |
832 { | |
833 std::string u("44ca5051-14ef-4d2f-8bd7-db20bfb61fbb "); | |
834 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
835 ASSERT_EQ(ref, u); | |
836 } | |
837 | |
838 // space l & r | |
839 { | |
840 std::string u(" 44ca5051-14ef-4d2f-8bd7-db20bfb61fbb "); | |
841 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
842 ASSERT_EQ(ref, u); | |
843 } | |
844 | |
845 // space left + case | |
846 { | |
847 std::string u(" 44CA5051-14ef-4d2f-8bd7-dB20bfb61fbb"); | |
848 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
849 ASSERT_EQ(ref, u); | |
850 } | |
851 | |
852 // space right + case | |
853 { | |
854 std::string u("44ca5051-14EF-4D2f-8bd7-db20bfb61fbB "); | |
855 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
856 ASSERT_EQ(ref, u); | |
857 } | |
858 | |
859 // space l & r + case | |
860 { | |
861 std::string u(" 44cA5051-14Ef-4d2f-8bD7-db20bfb61fbb "); | |
862 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
863 ASSERT_EQ(ref, u); | |
864 } | |
865 | |
866 // no | |
867 { | |
868 std::string u(" 44ca5051-14ef-4d2f-8bd7- db20bfb61fbb"); | |
869 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
870 ASSERT_NE(ref, u); | |
871 } | |
872 | |
873 // no | |
874 { | |
875 std::string u("44ca5051-14ef-4d2f-8bd7-db20bfb61fb"); | |
876 OrthancStone::GenericToolbox::NormalizeUuid(u); | |
877 ASSERT_NE(ref, u); | |
878 } | |
879 } | |
880 | |
881 | |
882 TEST(CoordinateSystem3D, Basic) | |
883 { | |
884 using namespace OrthancStone; | |
885 | |
886 { | |
887 CoordinateSystem3D c; | |
888 ASSERT_FALSE(c.IsValid()); | |
889 ASSERT_DOUBLE_EQ(c.GetNormal()[0], 0); | |
890 ASSERT_DOUBLE_EQ(c.GetNormal()[1], 0); | |
891 ASSERT_DOUBLE_EQ(c.GetNormal()[2], 1); | |
892 | |
893 ASSERT_DOUBLE_EQ(0, c.ComputeDistance(LinearAlgebra::CreateVector(0, 0, 0))); | |
894 ASSERT_DOUBLE_EQ(0, c.ComputeDistance(LinearAlgebra::CreateVector(5, 0, 0))); | |
895 ASSERT_DOUBLE_EQ(0, c.ComputeDistance(LinearAlgebra::CreateVector(0, 5, 0))); | |
896 ASSERT_DOUBLE_EQ(5, c.ComputeDistance(LinearAlgebra::CreateVector(0, 0, 5))); | |
897 } | |
898 | |
899 { | |
900 CoordinateSystem3D c("nope1", "nope2"); | |
901 ASSERT_FALSE(c.IsValid()); | |
902 ASSERT_DOUBLE_EQ(c.GetNormal()[0], 0); | |
903 ASSERT_DOUBLE_EQ(c.GetNormal()[1], 0); | |
904 ASSERT_DOUBLE_EQ(c.GetNormal()[2], 1); | |
905 } | |
906 | |
907 { | |
908 // https://www.vedantu.com/maths/perpendicular-distance-of-a-point-from-a-plane | |
909 CoordinateSystem3D c = CoordinateSystem3D::CreateFromPlaneGeneralForm(2, 4, -4, -6); | |
910 ASSERT_DOUBLE_EQ(3, c.ComputeDistance(LinearAlgebra::CreateVector(0, 3, 6))); | |
911 } | |
912 | |
913 { | |
914 // https://mathinsight.org/distance_point_plane_examples | |
915 CoordinateSystem3D c = CoordinateSystem3D::CreateFromPlaneGeneralForm(2, -2, 5, 8); | |
916 ASSERT_DOUBLE_EQ(39.0 / sqrt(33.0), c.ComputeDistance(LinearAlgebra::CreateVector(4, -4, 3))); | |
917 } | |
918 | |
919 { | |
920 // https://www.ck12.org/calculus/distance-between-a-point-and-a-plane/lesson/Distance-Between-a-Point-and-a-Plane-MAT-ALY/ | |
921 const Vector a = LinearAlgebra::CreateVector(3, 6, 9); | |
922 const Vector b = LinearAlgebra::CreateVector(9, 6, 3); | |
923 const Vector c = LinearAlgebra::CreateVector(6, -9, 9); | |
924 CoordinateSystem3D d = CoordinateSystem3D::CreateFromThreePoints(a, b, c); | |
925 ASSERT_DOUBLE_EQ(0, d.ComputeDistance(a)); | |
926 ASSERT_DOUBLE_EQ(0, d.ComputeDistance(b)); | |
927 ASSERT_DOUBLE_EQ(0, d.ComputeDistance(c)); | |
928 } | |
929 | |
930 { | |
931 // https://tutorial.math.lamar.edu/classes/calcii/eqnsofplanes.aspx | |
932 const Vector a = LinearAlgebra::CreateVector(1, -2, 0); | |
933 const Vector b = LinearAlgebra::CreateVector(3, 1, 4); | |
934 const Vector c = LinearAlgebra::CreateVector(0, -1, 2); | |
935 CoordinateSystem3D d = CoordinateSystem3D::CreateFromThreePoints(a, b, c); | |
936 double r = d.GetNormal() [0] / 2.0; | |
937 ASSERT_DOUBLE_EQ(-8 * r, d.GetNormal() [1]); | |
938 ASSERT_DOUBLE_EQ(5 * r, d.GetNormal() [2]); | |
939 } | |
940 } | |
941 | 33 |
942 | 34 |
943 TEST(Enumerations, Basic) | 35 TEST(Enumerations, Basic) |
944 { | 36 { |
945 using namespace OrthancStone; | 37 using namespace OrthancStone; |
963 } | 55 } |
964 | 56 |
965 | 57 |
966 int main(int argc, char **argv) | 58 int main(int argc, char **argv) |
967 { | 59 { |
968 Orthanc::Logging::Initialize(); | 60 #if defined(__EMSCRIPTEN__) |
969 Orthanc::Logging::EnableInfoLevel(true); | 61 std::string output; |
62 #endif | |
63 | |
64 int result; | |
970 | 65 |
971 ::testing::InitGoogleTest(&argc, argv); | 66 { |
972 int result = RUN_ALL_TESTS(); | 67 Orthanc::Logging::Initialize(); |
68 Orthanc::Logging::EnableInfoLevel(true); | |
973 | 69 |
974 Orthanc::Logging::Finalize(); | 70 ::testing::InitGoogleTest(&argc, argv); |
71 | |
72 #if defined(__EMSCRIPTEN__) | |
73 ::testing::internal::CaptureStdout(); | |
74 #endif | |
75 | |
76 result = RUN_ALL_TESTS(); | |
77 | |
78 Orthanc::Logging::Finalize(); | |
79 | |
80 #if defined(__EMSCRIPTEN__) | |
81 output = testing::internal::GetCapturedStdout(); | |
82 #endif | |
83 } | |
84 | |
85 #if defined(__EMSCRIPTEN__) | |
86 EM_ASM({ | |
87 document.getElementById("output").innerHTML = UTF8ToString($0); | |
88 }, | |
89 output.c_str()); | |
90 #endif | |
975 | 91 |
976 return result; | 92 return result; |
977 } | 93 } |