Main MRPT website > C++ reference for MRPT 1.9.9
CQuaternion_unittest.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include <mrpt/math/CQuaternion.h>
11 #include <mrpt/poses/CPose3D.h>
12 #include <mrpt/poses/CPose3DQuat.h>
13 #include <gtest/gtest.h>
14 #include <mrpt/utils/CTraitsTest.h>
15 
16 using namespace mrpt;
17 using namespace mrpt::poses;
18 using namespace mrpt::utils;
19 using namespace mrpt::math;
20 using namespace std;
21 
25 
26 class QuaternionTests : public ::testing::Test
27 {
28  protected:
29  virtual void SetUp() {}
30  virtual void TearDown() {}
31  void test_gimbalLock(double YAW, double PITCH, double ROLL)
32  {
33  CQuaternionDouble q1, q1r;
34  CPose3D p1(0, 0, 0, YAW, PITCH, ROLL);
35  p1.getAsQuaternion(q1);
36  CPose3D(q1, 0, 0, 0).getAsQuaternion(q1r);
37 
38  TPose3D t1(CPose3D(q1, 0, 0, 0));
39  TPose3D t2(CPose3D(q1r, 0, 0, 0));
40 
41  EXPECT_NEAR(
42  0, std::abs(
43  (CPose3D(q1, 0, 0, 0).getAsVectorVal() -
44  CPose3D(q1r, 0, 0, 0).getAsVectorVal())
45  .sum()),
46  1e-6);
47  }
48 
49  void test_toYPRAndBack(double YAW, double PITCH, double ROLL)
50  {
51  CPose3D p1(0, 0, 0, YAW, PITCH, ROLL);
52  CPose3DQuat q1(p1);
53  CPose3D p2 = CPose3D(q1);
54 
55  EXPECT_NEAR(
56  0, (p1.getRotationMatrix() - p2.getRotationMatrix())
57  .array()
58  .abs()
59  .sum(),
60  1e-4)
61  << "ypr->quat->ypr failed with:" << endl
62  << " p1:" << p1 << endl
63  << " q1:" << q1 << endl
64  << " p2:" << p2 << endl;
65 
66  CPose3D p3(q1.quat(), q1[0], q1[1], q1[2]);
67  EXPECT_NEAR(
68  0, (p1.getRotationMatrix() - p3.getRotationMatrix())
69  .array()
70  .abs()
71  .sum(),
72  1e-4)
73  << "pose constructor from quat failed with:" << endl
74  << " p1:" << p1 << endl
75  << " q1:" << q1 << endl
76  << " p3:" << p3 << endl;
77  }
78 
79  void test_lnAndExpMatches(double yaw1, double pitch1, double roll1)
80  {
81  const CPose3D pp(0, 0, 0, yaw1, pitch1, roll1);
83  pp.getAsQuaternion(q1);
84 
86  const CQuaternionDouble q2 = CQuaternionDouble::exp(q1_ln);
87 
88  // q2 should be == q1
89  EXPECT_NEAR(0, (q1 - q2).array().abs().sum(), 1e-10) << "q1:\n"
90  << q1 << endl
91  << "q2:\n"
92  << q2 << endl
93  << "Error:\n"
94  << (q1 - q2)
95  << endl;
96  }
97 
98  void test_ExpAndLnMatches(double v0, double v1, double v2)
99  {
101  v[0] = v0;
102  v[1] = v1;
103  v[2] = v2;
104 
105  const CQuaternionDouble q1 = CQuaternionDouble::exp(v);
106  CArrayDouble<3> q1_ln = q1.ln<CArrayDouble<3>>();
107 
108  // q1_ln should be == v
109  EXPECT_NEAR(0, (q1_ln - v).array().abs().sum(), 1e-10) << "v:\n"
110  << v << endl
111  << "q1_ln:\n"
112  << q1_ln << endl
113  << "Error:\n"
114  << (q1_ln - v)
115  << endl;
116  }
117 };
118 
119 TEST_F(QuaternionTests, crossProduct)
120 {
121  CQuaternionDouble q1, q2, q3;
122 
123  // q1 = CQuaternionDouble(1,2,3,4); q1.normalize();
124  CPose3D p1(0, 0, 0, DEG2RAD(10), DEG2RAD(30), DEG2RAD(-20));
125  p1.getAsQuaternion(q1);
126 
127  CPose3D p2(0, 0, 0, DEG2RAD(30), DEG2RAD(-20), DEG2RAD(10));
128  p2.getAsQuaternion(q2);
129 
130  // q3 = q1 x q2
131  q3.crossProduct(q1, q2);
132 
133  const CPose3D p3 = p1 + p2;
134 
135  EXPECT_NEAR(
136  0, std::abs(
137  (p3.getAsVectorVal() - CPose3D(q3, 0, 0, 0).getAsVectorVal())
138  .sum()),
139  1e-6)
140  << "q1 = " << q1 << endl
141  << "q1 as CPose3D = " << CPose3D(q1, 0, 0, 0) << endl
142  << "q2 = " << q2 << endl
143  << "q2 as CPose3D = " << CPose3D(q2, 0, 0, 0) << endl
144  << "q3 = q1 * q2 = " << q3 << endl
145  << "q3 as CPose3D = " << CPose3D(q3, 0, 0, 0) << endl
146  << "Should be equal to p3 = p1 (+) p2 = " << p3 << endl;
147 }
148 
149 // Use special cases: gimbal lock:
151 {
152  test_gimbalLock(DEG2RAD(20), DEG2RAD(90), DEG2RAD(0));
153  test_gimbalLock(DEG2RAD(20), DEG2RAD(-90), DEG2RAD(0));
154 }
155 
156 TEST_F(QuaternionTests, ToYPRAndBack)
157 {
158  test_toYPRAndBack(DEG2RAD(20), DEG2RAD(30), DEG2RAD(40));
159  test_toYPRAndBack(DEG2RAD(20), DEG2RAD(30), DEG2RAD(40));
160  test_toYPRAndBack(DEG2RAD(30), DEG2RAD(90), DEG2RAD(0));
161  test_toYPRAndBack(DEG2RAD(-30), DEG2RAD(90), DEG2RAD(0));
162  test_toYPRAndBack(DEG2RAD(-30), DEG2RAD(88), DEG2RAD(60));
163  test_toYPRAndBack(DEG2RAD(-30), DEG2RAD(10), DEG2RAD(60));
164 }
165 
166 TEST_F(QuaternionTests, LnAndExpMatches)
167 {
168  const double list_test_YPR_angles_degrees[][3] = {
169  {0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0},
170  {0, 1, 0}, {0, 0, -1}, {0, 0, 1}, {40, 0, 0},
171  {0, 40, 0}, {0, 0, 40}, {-40, 0, 0}, {0, -40, 0},
172  {0, 0, -40}, {-30, 20, 50}, {-30, 20, -50}, {30, -20, -50}};
173 
174  const size_t N = sizeof(list_test_YPR_angles_degrees) /
175  sizeof(list_test_YPR_angles_degrees[0]);
176  for (size_t i = 0; i < N; i++)
177  test_lnAndExpMatches(
178  DEG2RAD(list_test_YPR_angles_degrees[i][0]),
179  DEG2RAD(list_test_YPR_angles_degrees[i][1]),
180  DEG2RAD(list_test_YPR_angles_degrees[i][2]));
181 }
182 
183 TEST_F(QuaternionTests, ExpAndLnMatches)
184 {
185  const double list_test_XYZ[][3] = {
186  {0, 0, 0}, {-1, 0, 0}, {1, 0, 0},
187  {0, -1, 0}, {0, 1, 0}, {0, 0, -1},
188  {0, 0, 1}, {1e-3, 0, 0}, {0, 1e-3, 0},
189  {0, 0, 1e-3}, {-1e-3, 0, 0}, {0, -1e-3, 0},
190  {0, 0, -1e-3}, {-0.1, 0.2, 0.3}, {-0.1, -0.2, 0.3},
191  {-0.1, -0.2, -0.3}, {-0.1, 0.2, -0.3}, {0.1, 0.2, -0.3},
192  {0.1, 0.2, 0.3}};
193 
194  const size_t N = sizeof(list_test_XYZ) / sizeof(list_test_XYZ[0]);
195  for (size_t i = 0; i < N; i++)
196  test_ExpAndLnMatches(
197  list_test_XYZ[i][0], list_test_XYZ[i][1], list_test_XYZ[i][2]);
198 }
TEST_F(QuaternionTests, crossProduct)
#define DEG2RAD
Definition: bits.h:112
void test_toYPRAndBack(double YAW, double PITCH, double ROLL)
void test_gimbalLock(double YAW, double PITCH, double ROLL)
virtual void TearDown()
void test_lnAndExpMatches(double yaw1, double pitch1, double roll1)
void test_ExpAndLnMatches(double v0, double v1, double v2)
A quaternion, which can represent a 3D rotation as pair , with a real part "r" and a 3D vector ,...
Definition: CQuaternion.h:47
void crossProduct(const CQuaternion &q1, const CQuaternion &q2)
Calculate the "cross" product (or "composed rotation") of two quaternion: this = q1 x q2 After the op...
Definition: CQuaternion.h:203
void ln(ARRAYLIKE3 &out_ln) const
Logarithm of the 3x3 matrix defined by this pose, generating the corresponding vector in the SO(3) Li...
Definition: CQuaternion.h:155
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction.
Definition: types_math.h:70
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:89
void getRotationMatrix(mrpt::math::CMatrixDouble33 &ROT) const
Get the 3x3 rotation matrix.
Definition: CPose3D.h:237
void getAsQuaternion(mrpt::math::CQuaternionDouble &q, mrpt::math::CMatrixFixedNumeric< double, 4, 3 > *out_dq_dr=nullptr) const
Returns the quaternion associated to the rotation of this object (NOTE: XYZ translation is ignored)
Definition: CPose3D.cpp:584
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,...
Definition: CPose3DQuat.h:49
mrpt::math::CQuaternionDouble & quat()
Read/Write access to the quaternion representing the 3D rotation.
Definition: CPose3DQuat.h:60
mrpt::math::CVectorDouble getAsVectorVal() const
Return the pose or point as a 1xN vector with all the components (see derived classes for each implem...
Definition: CPoseOrPoint.h:265
GLfloat GLfloat v1
Definition: glext.h:4105
const GLdouble * v
Definition: glext.h:3678
GLfloat v0
Definition: glext.h:4103
GLfloat GLfloat GLfloat v2
Definition: glext.h:4107
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:20
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:18
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 63ea9d1f1 Thu Nov 23 00:06:53 2017 +0100 at mar 26 may 2026 12:19:29 CEST