39 #include <visp3/core/vpConfig.h>
41 #ifdef VISP_HAVE_CATCH2
43 #include <visp3/core/vpThetaUVector.h>
44 #include <visp3/core/vpUniRand.h>
46 #define CATCH_CONFIG_RUNNER
49 #ifdef ENABLE_VISP_NAMESPACE
65 const double ctheta = std::cos(angle);
66 const double stheta = std::sin(angle);
67 const double ax = rng.
uniform(-1.0, 1.0);
68 const double ay = rng.
uniform(-1.0, 1.0);
69 const double az = rng.
uniform(-1.0, 1.0);
75 bool test(
const std::string &s,
const vpArray2D<double> &v,
const std::vector<double> &bench)
77 std::cout << s <<
"(" << v.
getRows() <<
"," << v.
getCols() <<
") = [" << v <<
"]" << std::endl;
78 if (bench.size() != v.
size()) {
79 std::cout <<
"Test fails: bad size wrt bench" << std::endl;
82 for (
unsigned int i = 0; i < v.
size(); i++) {
83 if (std::fabs(v.
data[i] - bench[i]) > std::fabs(v.
data[i]) * std::numeric_limits<double>::epsilon()) {
84 std::cout <<
"Test fails: bad content" << std::endl;
94 std::cout << s <<
"(" << v.
getRows() <<
"," << v.
getCols() <<
") = [" << v <<
"]" << std::endl;
96 std::cout <<
"Test fails: bad size wrt bench" << std::endl;
99 for (
unsigned int i = 0; i < v.
size(); i++) {
100 if (std::fabs(v.
data[i] - bench[i]) > std::fabs(v.
data[i]) * std::numeric_limits<double>::epsilon()) {
101 std::cout <<
"Test fails: bad content" << std::endl;
109 bool test(
const std::string &s,
const vpRotationVector &v,
const double &bench)
111 std::cout << s <<
"(" << v.
getRows() <<
"," << v.
getCols() <<
") = [" << v <<
"]" << std::endl;
112 for (
unsigned int i = 0; i < v.
size(); i++) {
113 if (std::fabs(v[i] - bench) > std::fabs(v[i]) * std::numeric_limits<double>::epsilon()) {
114 std::cout <<
"Test fails: bad content" << std::endl;
124 for (
unsigned int i = 0; i < 4; i++) {
125 for (
unsigned int j = 0; j < 4; j++) {
134 TEST_CASE(
"Common rotation operations",
"[rotation]")
136 SECTION(
"Theta u initialization")
141 CHECK(test(
"r1", r1, bench1));
144 bench1 = r1.toStdVector();
145 CHECK(test(
"r1", r1, bench1));
148 CHECK(test(
"r1", r1, bench3));
151 CHECK(test(
"r2", r2, bench1));
152 CHECK(r2.
data != r1.data);
158 CHECK(test(
"r3", r3, bench1));
160 for (
unsigned int i = 0; i < r3.
size(); i++) {
161 CHECK(std::fabs(r3[i] - bench1[i]) < std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
166 CHECK(test(
"r4", r4, bench2));
169 CHECK(test(
"r5", r5, bench1));
171 SECTION(
"Rxyz initialization")
176 CHECK(test(
"r1", r1, bench1));
179 bench1 = r1.toStdVector();
180 CHECK(test(
"r1", r1, bench1));
183 CHECK(test(
"r1", r1, bench3));
186 CHECK(test(
"r2", r2, bench1));
192 CHECK(test(
"r3", r3, bench1));
194 for (
unsigned int i = 0; i < r3.
size(); i++) {
195 CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
200 CHECK(test(
"r4", r4, bench2));
203 CHECK(test(
"r5", r5, bench1));
205 SECTION(
"rzyx initialization")
210 CHECK(test(
"r1", r1, bench1));
213 bench1 = r1.toStdVector();
214 CHECK(test(
"r1", r1, bench1));
217 CHECK(test(
"r1", r1, bench3));
220 CHECK(test(
"r2", r2, bench1));
226 CHECK(test(
"r3", r3, bench1));
228 for (
unsigned int i = 0; i < r3.
size(); i++) {
229 CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
234 CHECK(test(
"r4", r4, bench2));
237 CHECK(test(
"r5", r5, bench1));
239 SECTION(
"rzyz initialiation")
244 CHECK(test(
"r1", r1, bench1));
247 bench1 = r1.toStdVector();
248 CHECK(test(
"r1", r1, bench1));
251 CHECK(test(
"r1", r1, bench3));
254 CHECK(test(
"r2", r2, bench1));
260 CHECK(test(
"r3", r3, bench1));
262 for (
unsigned int i = 0; i < r3.
size(); i++) {
263 CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
268 CHECK(test(
"r4", r4, bench2));
271 CHECK(test(
"r5", r5, bench1));
273 SECTION(
"Test quaternion initialization",
"[quaternion]")
278 CHECK(test(
"r1", r1, bench1));
281 bench1 = r1.toStdVector();
282 CHECK(test(
"r1", r1, bench1));
285 CHECK(test(
"r1", r1, bench3));
288 CHECK(test(
"r2", r2, bench1));
294 CHECK(test(
"r3", r3, bench1));
296 for (
unsigned int i = 0; i < r3.
size(); i++) {
297 CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
302 CHECK(test(
"r4", r4, bench2));
305 CHECK(test(
"r5", r5, bench1));
307 SECTION(
"Conversions")
310 for (
int i = -10; i < 10; i++) {
311 for (
int j = -10; j < 10; j++) {
315 std::cout <<
"Initialization " << std::endl;
321 std::cout <<
"theta=" <<
vpMath::deg(theta) << std::endl;
322 std::cout <<
"u=" << u << std::endl;
324 std::cout <<
"From vpThetaUVector to vpRotationMatrix " << std::endl;
327 std::cout <<
"Matrix R";
330 std::cout << R << std::endl;
332 std::cout <<
"From vpRotationMatrix to vpQuaternionVector " << std::endl;
334 CHECK(q.magnitude() == Approx(1.0).margin(1e-4));
335 std::cout << q << std::endl;
339 std::cout <<
"From vpQuaternionVector to vpRotationMatrix " << std::endl;
341 std::cout <<
"From vpRotationMatrix to vpRxyzVector " << std::endl;
343 std::cout << RxyzbuildR << std::endl;
345 std::cout <<
"From vpRxyzVector to vpThetaUVector " << std::endl;
346 std::cout <<
" use From vpRxyzVector to vpRotationMatrix " << std::endl;
347 std::cout <<
" use From vpRotationMatrix to vpThetaUVector " << std::endl;
352 std::cout << std::endl;
353 std::cout <<
"result : should equivalent to the first one " << std::endl;
359 std::cout <<
"theta=" <<
vpMath::deg(theta2) << std::endl;
360 std::cout <<
"u=" << u2 << std::endl;
362 CHECK(
vpMath::abs(theta2 - theta) < std::numeric_limits<double>::epsilon() * 1e10);
363 CHECK(
vpMath::abs(u[0] - u2[0]) < std::numeric_limits<double>::epsilon() * 1e10);
364 CHECK(
vpMath::abs(u[1] - u2[1]) < std::numeric_limits<double>::epsilon() * 1e10);
365 CHECK(
vpMath::abs(u[2] - u2[2]) < std::numeric_limits<double>::epsilon() * 1e10);
368 SECTION(
"Conversion from and to rzyz vector")
371 std::cout <<
"Initialization vpRzyzVector " << std::endl;
372 std::cout << rzyz << std::endl;
373 std::cout <<
"From vpRzyzVector to vpRotationMatrix " << std::endl;
376 std::cout <<
"From vpRotationMatrix to vpRzyzVector " << std::endl;
379 CHECK(test(
"rzyz", rzyz_final,
vpColVector(rzyz)));
380 std::cout << rzyz_final << std::endl;
382 SECTION(
"Conversion from and to rzyx vector")
385 std::cout <<
"Initialization vpRzyxVector " << std::endl;
386 std::cout << rzyx << std::endl;
387 std::cout <<
"From vpRzyxVector to vpRotationMatrix " << std::endl;
390 std::cout << R << std::endl;
391 std::cout <<
"From vpRotationMatrix to vpRzyxVector " << std::endl;
394 bool ret = test(
"rzyx", rzyx_final,
vpColVector(rzyx));
397 std::cout <<
"Rzyx vector differ. Test rotation matrix..." << std::endl;
400 std::cout <<
"Rzyx vector differ but rotation matrix is valid" << std::endl;
405 std::cout << rzyx_final << std::endl;
408 SECTION(
"Rotation matrix extraction from homogeneous matrix and multiplication")
412 _1_M_2_truth[0][0] = 0.9835;
413 _1_M_2_truth[0][1] = -0.0581;
414 _1_M_2_truth[0][2] = 0.1716;
415 _1_M_2_truth[0][3] = 0;
416 _1_M_2_truth[1][0] = -0.0489;
417 _1_M_2_truth[1][1] = -0.9972;
418 _1_M_2_truth[1][2] = -0.0571;
419 _1_M_2_truth[1][3] = 0;
420 _1_M_2_truth[2][0] = 0.1744;
421 _1_M_2_truth[2][1] = 0.0478;
422 _1_M_2_truth[2][2] = -0.9835;
423 _1_M_2_truth[2][3] = 0;
425 _2_M_3_[0][0] = 0.9835;
426 _2_M_3_[0][1] = -0.0581;
427 _2_M_3_[0][2] = 0.1716;
428 _2_M_3_[0][3] = 0.0072;
429 _2_M_3_[1][0] = -0.0489;
430 _2_M_3_[1][1] = -0.9972;
431 _2_M_3_[1][2] = -0.0571;
432 _2_M_3_[1][3] = 0.0352;
433 _2_M_3_[2][0] = 0.1744;
434 _2_M_3_[2][1] = 0.0478;
435 _2_M_3_[2][2] = -0.9835;
436 _2_M_3_[2][3] = 0.9470;
441 CHECK(test_matrix_equal(_1_M_3_, _1_M_3_truth));
445 TEST_CASE(
"Theta u multiplication",
"[theta.u]")
447 const int nTrials = 100;
448 const uint64_t seed = 0x123456789;
450 for (
int iter = 0; iter < nTrials; iter++) {
462 const double tolerance = 1e-9;
463 for (
unsigned int i = 0; i < 3; i++) {
464 for (
unsigned int j = 0; j < 3; j++) {
465 CHECK(c1Rc3_ref[i][j] == Approx(c1Rc3[i][j]).epsilon(0).margin(tolerance));
471 TEST_CASE(
"Quaternion multiplication",
"[quaternion]")
473 const int nTrials = 100;
474 const uint64_t seed = 0x123456789;
476 for (
int iter = 0; iter < nTrials; iter++) {
489 const double tolerance = 1e-9;
490 for (
unsigned int i = 0; i < 3; i++) {
491 for (
unsigned int j = 0; j < 3; j++) {
492 CHECK(c1Rc3_ref[i][j] == Approx(c1Rc3[i][j]).epsilon(0).margin(tolerance));
498 int main(
int argc,
char *argv[])
500 Catch::Session session;
503 session.applyCommandLine(argc, argv);
505 int numFailed = session.run();
515 int main() {
return EXIT_SUCCESS; }
unsigned int getCols() const
Type * data
Address of the first element of the data array.
unsigned int size() const
Return the number of elements of the 2D array.
unsigned int getRows() const
Implementation of column vector and the associated operations.
vpColVector extract(unsigned int r, unsigned int colsize) const
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
static double rad(double deg)
static Type abs(const Type &x)
static bool equal(double x, double y, double threshold=0.001)
static double deg(double rad)
Implementation of a rotation vector as quaternion angle minimal representation.
void set(double x, double y, double z, double w)
Implementation of a rotation matrix and operations on such kind of matrices.
vpRotationMatrix & build(const vpHomogeneousMatrix &M)
bool isARotationMatrix(double threshold=1e-6) const
Implementation of a generic rotation vector.
Implementation of a rotation vector as Euler angle minimal representation.
Implementation of a rotation vector as Euler angle minimal representation.
vpRzyxVector & build(const vpRotationMatrix &R)
Implementation of a rotation vector as Euler angle minimal representation.
vpRzyzVector & build(const vpRotationMatrix &R)
Implementation of a rotation vector as axis-angle minimal representation.
vpThetaUVector & build(const vpHomogeneousMatrix &M)
void extract(double &theta, vpColVector &u) const
Class for generating random numbers with uniform probability density.
int uniform(int a, int b)