test_quat.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2017, the mcl_3dl authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #define _USE_MATH_DEFINES
31 #include <cmath>
32 #include <cstddef>
33 
34 #include <mcl_3dl/quat.h>
35 
36 #include <gtest/gtest.h>
37 
38 TEST(Quat, Constractors)
39 {
40  // Test quaternion elements style constructor and copy constructor
41  const mcl_3dl::Quat a(1.0, 2.0, 3.0, 4.0);
42  const mcl_3dl::Quat b(a);
43 
44  ASSERT_TRUE(a.x_ == 1.0);
45  ASSERT_TRUE(a.y_ == 2.0);
46  ASSERT_TRUE(a.z_ == 3.0);
47  ASSERT_TRUE(a.w_ == 4.0);
48  ASSERT_TRUE(b.x_ == 1.0);
49  ASSERT_TRUE(b.y_ == 2.0);
50  ASSERT_TRUE(b.z_ == 3.0);
51  ASSERT_TRUE(b.w_ == 4.0);
52 
53  // Test RPY and angle-axis style constructor
54  for (int i = 0; i < 3; ++i)
55  {
56  const float ang = M_PI / 2.0;
57  const float r = (i == 0) ? 1.0 : 0.0;
58  const float p = (i == 1) ? 1.0 : 0.0;
59  const float y = (i == 2) ? 1.0 : 0.0;
60 
61  // Check consistency between styles
62  const mcl_3dl::Quat c(mcl_3dl::Vec3(r * ang, p * ang, y * ang));
64  d.setRPY(mcl_3dl::Vec3(r * ang, p * ang, y * ang));
65  ASSERT_TRUE(c == d);
66 
67  const mcl_3dl::Quat e(mcl_3dl::Vec3(r, p, y), ang);
68  ASSERT_LT(fabs(c.x_ - e.x_), 1e-6);
69  ASSERT_LT(fabs(c.y_ - e.y_), 1e-6);
70  ASSERT_LT(fabs(c.z_ - e.z_), 1e-6);
71  ASSERT_LT(fabs(c.w_ - e.w_), 1e-6);
72 
73  // Check elements
74  ASSERT_LT(fabs(c.x_ - r * std::sqrt(2.0) / 2.0), 1e-6);
75  ASSERT_LT(fabs(c.y_ - p * std::sqrt(2.0) / 2.0), 1e-6);
76  ASSERT_LT(fabs(c.z_ - y * std::sqrt(2.0) / 2.0), 1e-6);
77  ASSERT_LT(fabs(c.w_ - std::sqrt(2.0) / 2.0), 1e-6);
78 
79  // Check reverse conversions
80  mcl_3dl::Vec3 crpy(c.getRPY());
81  ASSERT_LT(fabs(r * ang - crpy.x_), 1e-3);
82  ASSERT_LT(fabs(p * ang - crpy.y_), 1e-3);
83  ASSERT_LT(fabs(y * ang - crpy.z_), 1e-3);
84 
85  mcl_3dl::Vec3 axis;
86  float angle;
87  c.getAxisAng(axis, angle);
88  ASSERT_LT(fabs(r - axis.x_), 1e-6);
89  ASSERT_LT(fabs(p - axis.y_), 1e-6);
90  ASSERT_LT(fabs(y - axis.z_), 1e-6);
91  ASSERT_LT(fabs(ang - angle), 1e-6);
92  }
93 
94  // Test forward up style constructor
95  for (int i = 0; i < 3; ++i)
96  {
97  const mcl_3dl::Vec3 fw((i == 0) ? 1.0 : 0.0, (i == 1) ? 1.0 : 0.0, (i == 2) ? 1.0 : 0.0);
98  for (int j = 0; j < 3; ++j)
99  {
100  const mcl_3dl::Vec3 up((j == 0) ? 1.0 : 0.0, (j == 1) ? 1.0 : 0.0, (j == 2) ? 1.0 : 0.0);
101 
102  if (fw == up)
103  continue;
104 
105  const mcl_3dl::Quat q(fw, up);
106 
107  // Rotate forward and up vectors and validate
108  const mcl_3dl::Vec3 f = q * mcl_3dl::Vec3(1.0, 0.0, 0.0);
109  const mcl_3dl::Vec3 u = q * mcl_3dl::Vec3(0.0, 0.0, 1.0);
110 
111  ASSERT_LT(fabs(f.x_ - fw.x_), 1e-6);
112  ASSERT_LT(fabs(f.y_ - fw.y_), 1e-6);
113  ASSERT_LT(fabs(f.z_ - fw.z_), 1e-6);
114  ASSERT_LT(fabs(u.x_ - up.x_), 1e-6);
115  ASSERT_LT(fabs(u.y_ - up.y_), 1e-6);
116  ASSERT_LT(fabs(u.z_ - up.z_), 1e-6);
117  }
118  }
119 }
120 
121 TEST(Quat, Operators)
122 {
123  const mcl_3dl::Quat a(1.0, 2.0, 3.0, 4.0);
124 
125  // Test ==,!= operators
126  ASSERT_TRUE(mcl_3dl::Quat(1.0, 2.0, 3.0, 4.0) == a);
127  ASSERT_FALSE(mcl_3dl::Quat(1.0, 2.0, 3.0, 4.0) != a);
128 
129  for (uint32_t i = 1; i < (1 << 4); ++i)
130  {
131  const float xp = (i & (1 << 0)) ? 0.1 : 0.0;
132  const float yp = (i & (1 << 1)) ? 0.1 : 0.0;
133  const float zp = (i & (1 << 2)) ? 0.1 : 0.0;
134  const float wp = (i & (1 << 3)) ? 0.1 : 0.0;
135  ASSERT_TRUE(mcl_3dl::Quat(1.0 + xp, 2.0 + yp, 3.0 + zp, 4.0 + wp) != a);
136  ASSERT_FALSE(mcl_3dl::Quat(1.0 + xp, 2.0 + yp, 3.0 + zp, 4.0 + wp) == a);
137  }
138 
139  // Test +, -, +=, -= operators
140  const mcl_3dl::Quat adding(0.5, -0.5, 1.0, -1.0);
141  mcl_3dl::Quat a_plus = a;
142  mcl_3dl::Quat a_minus = a;
143  a_plus += adding;
144  a_minus -= adding;
145  ASSERT_TRUE(a + adding == mcl_3dl::Quat(1.5, 1.5, 4.0, 3.0));
146  ASSERT_TRUE(a + adding == a_plus);
147  ASSERT_TRUE(a - adding == mcl_3dl::Quat(0.5, 2.5, 2.0, 5.0));
148  ASSERT_TRUE(a - adding == a_minus);
149 
150  // Test -() operator
151  ASSERT_TRUE(-a == mcl_3dl::Quat(-1.0, -2.0, -3.0, -4.0));
152 
153  // Test scalar *, / operators
154  mcl_3dl::Quat a_mul = a;
155  mcl_3dl::Quat a_div = a;
156  a_mul *= 0.5;
157  a_div /= 2.0;
158  ASSERT_TRUE(a * 0.5 == mcl_3dl::Quat(0.5, 1.0, 1.5, 2.0));
159  ASSERT_TRUE(a / 2.0 == a * 0.5);
160  ASSERT_TRUE(a * 0.5 == a_mul);
161  ASSERT_TRUE(a / 2.0 == a_div);
162 }
163 
164 TEST(Quat, Norm)
165 {
166  // Check norm operations
167  const mcl_3dl::Quat a(1.0, 2.0, 3.0, 4.0);
168  const mcl_3dl::Quat b(-4.0, 5.0, 6.0, -7.0);
169  ASSERT_LT(fabs(a.norm() - 5.477226), 1e-6);
170  ASSERT_LT(fabs(b.norm() - 11.224972), 1e-6);
171  ASSERT_LT(fabs(a.normalized().norm() - 1.0), 1e-6);
172  ASSERT_LT(fabs(b.normalized().norm() - 1.0), 1e-6);
173 }
174 
175 TEST(Quat, Products)
176 {
177  // Check cross and dot products
178  const int num_samples = 8;
179  const mcl_3dl::Quat samples[num_samples] =
180  {
181  mcl_3dl::Quat(mcl_3dl::Vec3(1.5, 2.5, 3.5), 0.5),
182  mcl_3dl::Quat(mcl_3dl::Vec3(-0.5, 1.0, 1.0), 1.0),
183  mcl_3dl::Quat(mcl_3dl::Vec3(0.5, -1.0, 2.0), 1.5),
184  mcl_3dl::Quat(mcl_3dl::Vec3(0.5, 1.0, -2.0), 2.0),
185  mcl_3dl::Quat(mcl_3dl::Vec3(-2.0, -5.0, 4.0), 2.5),
186  mcl_3dl::Quat(mcl_3dl::Vec3(2.0, -5.0, -4.0), -1.0),
187  mcl_3dl::Quat(mcl_3dl::Vec3(-2.0, 5.0, -4.0), -1.5),
188  mcl_3dl::Quat(mcl_3dl::Vec3(-3.0, -1.0, -2.0), -2.0)
189  };
190 
191  // Check inverse
192  for (int i = 0; i < num_samples; ++i)
193  {
194  const mcl_3dl::Quat inv = samples[i].inv();
195  const mcl_3dl::Quat ident0 = inv * samples[i];
196  const mcl_3dl::Quat ident1 = samples[i] * inv;
197 
198  ASSERT_LT(fabs(ident0.x_), 1e-6);
199  ASSERT_LT(fabs(ident0.y_), 1e-6);
200  ASSERT_LT(fabs(ident0.z_), 1e-6);
201  ASSERT_LT(fabs(ident0.w_ - 1.0), 1e-6);
202  ASSERT_LT(fabs(ident1.x_), 1e-6);
203  ASSERT_LT(fabs(ident1.y_), 1e-6);
204  ASSERT_LT(fabs(ident1.z_), 1e-6);
205  ASSERT_LT(fabs(ident1.w_ - 1.0), 1e-6);
206  }
207 
208  // Check rotate axis
209  for (int i = 0; i < num_samples; ++i)
210  {
211  for (int j = 0; j < num_samples; ++j)
212  {
213  mcl_3dl::Vec3 a_axis;
214  float a_ang;
215  samples[i].getAxisAng(a_axis, a_ang);
216 
217  mcl_3dl::Quat a(a_axis, a_ang);
218  const mcl_3dl::Quat& b = samples[j];
219 
220  const mcl_3dl::Vec3 rotated_axis = b * a_axis;
221  a.rotateAxis(b);
222 
223  mcl_3dl::Vec3 a_axis2;
224  float a_ang2;
225  a.getAxisAng(a_axis2, a_ang2);
226 
227  ASSERT_LT(fabs(a_axis2.x_ - rotated_axis.x_), 1e-6);
228  ASSERT_LT(fabs(a_axis2.y_ - rotated_axis.y_), 1e-6);
229  ASSERT_LT(fabs(a_axis2.z_ - rotated_axis.z_), 1e-6);
230  ASSERT_LT(fabs(a_ang - a_ang2), 1e-6);
231  }
232  }
233 
234  // Check vector rotation
235  const int num_vecs = 3;
236  const mcl_3dl::Vec3 v[num_vecs] =
237  {
238  mcl_3dl::Vec3(1.0, 0.0, 0.0),
239  mcl_3dl::Vec3(0.0, 1.0, 0.0),
240  mcl_3dl::Vec3(0.0, 0.0, 1.0)
241  };
242  const int num_rots = 3;
243  const mcl_3dl::Quat r[num_rots] =
244  {
245  mcl_3dl::Quat(mcl_3dl::Vec3(1.0, 0.0, 0.0), M_PI / 2.0),
246  mcl_3dl::Quat(mcl_3dl::Vec3(0.0, 1.0, 0.0), -M_PI / 2.0),
247  mcl_3dl::Quat(mcl_3dl::Vec3(0.0, 0.0, 1.0), -M_PI / 2.0)
248  };
249  const mcl_3dl::Vec3 v_ans[3][3] =
250  {
251  mcl_3dl::Vec3(1.0, 0.0, 0.0),
252  mcl_3dl::Vec3(0.0, 0.0, 1.0),
253  mcl_3dl::Vec3(0.0, -1.0, 0.0),
254  mcl_3dl::Vec3(0.0, 0.0, 1.0),
255  mcl_3dl::Vec3(0.0, 1.0, 0.0),
256  mcl_3dl::Vec3(-1.0, 0.0, 0.0),
257  mcl_3dl::Vec3(0.0, -1.0, 0.0),
258  mcl_3dl::Vec3(1.0, 0.0, 0.0),
259  mcl_3dl::Vec3(0.0, 0.0, 1.0)
260  };
261  for (int i = 0; i < num_vecs; ++i)
262  {
263  for (int j = 0; j < num_rots; ++j)
264  {
265  const mcl_3dl::Vec3 result = r[j] * v[i];
266  ASSERT_LT(fabs(result.x_ - v_ans[j][i].x_), 1e-6);
267  ASSERT_LT(fabs(result.y_ - v_ans[j][i].y_), 1e-6);
268  ASSERT_LT(fabs(result.z_ - v_ans[j][i].z_), 1e-6);
269  }
270  }
271 
272  for (int i = 0; i < num_samples; ++i)
273  {
274  for (int j = 0; j < num_samples; ++j)
275  {
276  const mcl_3dl::Quat& a = samples[i];
277  const mcl_3dl::Quat& b = samples[j];
278 
279  // Check dot products based on the distributive property
280  ASSERT_LT((a - b).dot(a - b) - a.dot(a) - b.dot(b) + 2.0 * a.dot(b), 1e-6);
281 
282  // Check mcl_3dl::Quat by mcl_3dl::Quat products
283  const mcl_3dl::Vec3 v(1.0, 2.0, 3.0);
284  const mcl_3dl::Vec3 v1 = (a * b) * v;
285  const mcl_3dl::Vec3 v2 = a * (b * v);
286  ASSERT_LT(fabs(v1.x_ - v2.x_), 1e-6);
287  ASSERT_LT(fabs(v1.y_ - v2.y_), 1e-6);
288  ASSERT_LT(fabs(v1.z_ - v2.z_), 1e-6);
289  }
290  }
291 }
292 
293 int main(int argc, char** argv)
294 {
295  testing::InitGoogleTest(&argc, argv);
296 
297  return RUN_ALL_TESTS();
298 }
float z_
Definition: vec3.h:42
d
f
float y_
Definition: quat.h:44
int main(int argc, char **argv)
Definition: test_quat.cpp:293
TFSIMD_FORCE_INLINE const tfScalar & y() const
doubleAcc dot(const VectorAcc &lhs, const VectorAcc &rhs)
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
constexpr Vec3 getRPY() const
Definition: quat.h:191
float w_
Definition: quat.h:46
float y_
Definition: vec3.h:41
constexpr Quat inv() const
Definition: quat.h:187
void getAxisAng(Vec3 &axis, float &ang) const
Definition: quat.h:226
TEST(Quat, Constractors)
Definition: test_quat.cpp:38
Quat normalized() const
Definition: quat.h:175
float x_
Definition: vec3.h:40
void setRPY(const Vec3 &rpy)
Definition: quat.h:202
constexpr float dot(const Quat &q) const
Definition: quat.h:87
float norm() const
Definition: quat.h:91
float z_
Definition: quat.h:45
float x_
Definition: quat.h:43
void rotateAxis(const Quat &r)
Definition: quat.h:240


mcl_3dl
Author(s): Atsushi Watanabe
autogenerated on Wed May 12 2021 02:16:29