MathLib
Loading...
Searching...
No Matches
TestDualQuaternion.cpp
Go to the documentation of this file.
4#include <cassert>
5#include <iostream>
6#include <cstdlib>
7
8#define _USE_MATH_DEFINES 1
9#include <math.h>
10
11
32{
33
34using namespace Math;
35using namespace Math::Literals;
36
38{
39 std::cout << __func__ << std::endl;
40
41 CHECK_IF_EQUAL( DualQuaternionf::make_rotation( Quaternionf::make_rotation(0.0_deg_f, 0.0f, 1.0f, 0.0f) ).dual(), Quaternionf::zero() );
42 CHECK_IF_EQUAL( DualQuaternionf::make_rotation( Quaternionf::make_rotation(45.0_deg_f, 0.0f, 0.0f, 1.0f) ).dual(), Quaternionf::zero() );
43 CHECK_IF_EQUAL( DualQuaternionf::make_rotation( Quaternionf::make_rotation(90.0_deg_f, 1.0f, 0.0f, 0.0f) ).dual(), Quaternionf::zero() );
44
45 // Same thing, but use a better named method.
46 // NOTE: They are not the same thing for the general case!
47 CHECK_IF_EQUAL( DualQuaternionf::make_rotation( Quaternionf::make_rotation(0.0_deg_f, 0.0f, 1.0f, 0.0f) ).translation(), Vector3Df::zero() );
48 CHECK_IF_EQUAL( DualQuaternionf::make_rotation( Quaternionf::make_rotation(45.0_deg_f, 0.0f, 0.0f, 1.0f) ).translation(), Vector3Df::zero() );
49 CHECK_IF_EQUAL( DualQuaternionf::make_rotation( Quaternionf::make_rotation(90.0_deg_f, 1.0f, 0.0f, 0.0f) ).translation(), Vector3Df::zero() );
50}
51
53{
54 std::cout << __func__ << std::endl;
55
56 CHECK_IF_EQUAL( DualQuaternionf::make_translation(1.0f, 2.0f, 3.0f).real(), Quaternionf::identity());
57 CHECK_IF_EQUAL( DualQuaternionf::make_translation(1.0f, 2.0f, 3.0f).rotation(), Quaternionf::identity());
58}
59
61{
62 std::cout << __func__ << std::endl;
63
64 DualQuaternionf a{ Quaternionf::make_rotation(45.0_deg_f, 0.0f, 0.0f, 1.0f), {-43.1113f, -6.0f, 0.0f} };
65
66 a = a * 3.3f;
67 DualQuaternionf normalized_a = a.normalized();
68
69 CHECK_IF_EQUAL( normalized_a.norm(), Dualf::identity() );
70 CHECK_IF_EQUAL( normalized_a.magnitude(), Dualf::identity() );
71 assert( !a.is_unit() );
72}
73
75{
76 std::cout << __func__ << std::endl;
77
78 DualQuaternionf a{ Quaternionf::make_rotation( 45.0_deg_f, 1.0f, 0.0f, 0.0f ),
79 10.0f, 10.0f, 10.0f
80 };
81 DualQuaternionf a_times_conjugate{ a * a.conjugate() };
82 Dualf mag_a = a.magnitude();
83 Dualf mag_a_times_conjugate = a_times_conjugate.magnitude();
84
85 CHECK_IF_EQUAL( mag_a, mag_a_times_conjugate );
86}
87
89{
90 std::cout << __func__ << std::endl;
91
92 Quaternionf q_rotation{ Quaternionf::make_rotation( 45.0_deg_f, 1.0f, 0.0f, 0.0f ) };
93 DualQuaternionf a{ DualQuaternionf::make_coordinate_system( q_rotation, 10.0f, 10.0f, 10.0f ) };
94 Quaternionf conjugate_real{ a.real().conjugate() * a.dual()};
95 Quaternionf conjugate_dual{ a.dual().conjugate() * a.real()};
96 Quaternionf sum = conjugate_real + conjugate_dual;
97
98
99 CHECK_IF_EQUAL( a.magnitude(), Dualf{ 1.0f } );
100 assert( a.is_unit() );
101 CHECK_IF_EQUAL( sum, Quaternionf::zero() );
102}
103
105{
106 Quaternionf q_rotation{ Quaternionf::make_rotation( 45.0_deg_f, 1.0f, 0.0f, 0.0f ) };
107 Vector3Df translation{ 10.0f, 0.0f, 0.0f };
108 DualQuaternionf pure_rotation{ DualQuaternionf::make_rotation( q_rotation ) };
109 DualQuaternionf pure_translation{ DualQuaternionf::make_translation( translation ) };
110 DualQuaternionf combination = pure_translation * pure_rotation;
111
112 CHECK_IF_EQUAL( combination.rotation(), q_rotation );
113 CHECK_IF_EQUAL( combination.translation(), translation );
114}
115
116void CreateRotationAndTestXAxis(float degrees_of_rotation)
117{
118 float half_angle = degrees_of_rotation / 2.0f;
119 DualQuaternionf rotation = DualQuaternionf::make_rotation( Quaternionf::make_rotation( Degreef(degrees_of_rotation), Vector3Df::unit_x() ) );
120
121 // Rotation is 45 deg angle in right-hand coordinate system
122 CHECK_IF_EQUAL( rotation.real().w(), std::cos( DegreesToRadians(half_angle) ) );
123 CHECK_IF_EQUAL( rotation.real().i(), std::sin( DegreesToRadians(half_angle) ) );
124 CHECK_IF_EQUAL( rotation.real().j(), 0.0f );
125 CHECK_IF_EQUAL( rotation.real().k(), 0.0f );
126
127 // Translation is 0
128 assert( rotation.dual().isZero() );
129}
130
131void CreateRotationAndTestYAxis(float degrees_of_rotation)
132{
133 float half_angle = degrees_of_rotation / 2.0f;
134 DualQuaternionf rotation = DualQuaternionf::make_rotation( Quaternionf::make_rotation( Degreef(degrees_of_rotation), Vector3Df::unit_y() ) );
135
136 // Rotation is 45 deg angle in right-hand coordinate system
137 CHECK_IF_EQUAL( rotation.real().w(), std::cos( DegreesToRadians(half_angle) ) );
138 CHECK_IF_EQUAL( rotation.real().i(), 0.0f );
139 CHECK_IF_EQUAL( rotation.real().j(), std::sin( DegreesToRadians(half_angle) ) );
140 CHECK_IF_EQUAL( rotation.real().k(), 0.0f );
141
142 // Translation is 0
143 assert( rotation.dual().isZero() );
144}
145
146void CreateRotationAndTestZAxis(float degrees_of_rotation)
147{
148 float half_angle = degrees_of_rotation / 2.0f;
149 DualQuaternionf rotation = DualQuaternionf::make_rotation( Quaternionf::make_rotation( Degreef(degrees_of_rotation), Vector3Df::unit_z() ) );
150
151 // Rotation is 45 deg angle in right-hand coordinate system
152 CHECK_IF_EQUAL( rotation.real().w(), std::cos( DegreesToRadians(half_angle) ) );
153 CHECK_IF_EQUAL( rotation.real().i(), 0.0f );
154 CHECK_IF_EQUAL( rotation.real().j(), 0.0f );
155 CHECK_IF_EQUAL( rotation.real().k(), std::sin( DegreesToRadians(half_angle) ) );
156
157 // Translation is 0
158 assert( rotation.dual().isZero() );
159}
160
162{
163 std::cout << __func__ << std::endl;
164
165 DualQuaternionf origin;
166
167 // Rotation part
168 CHECK_IF_EQUAL( origin.real().norm(), 1.0f );
169 CHECK_IF_EQUAL( origin.real().w(), 1.0f );
170 CHECK_IF_EQUAL( origin.real().i(), 0.0f );
171 CHECK_IF_EQUAL( origin.real().j(), 0.0f );
172 CHECK_IF_EQUAL( origin.real().k(), 0.0f );
173
174 // Translation Part
175 assert( origin.dual().isZero() );
176}
177
179{
180 std::cout << __func__ << std::endl;
181
182 // Rotate 0 around X axis
183 DualQuaternionf no_rotation = DualQuaternionf::make_rotation( Quaternionf::make_rotation(0.0_deg_f, Vector3Df::unit_x()) );
184
185 // Rotation part is a unit quaternion
186 CHECK_IF_EQUAL( no_rotation.real().norm(), 1.0f );
187 CHECK_IF_EQUAL( no_rotation.real().w(), 1.0f );
188 CHECK_IF_EQUAL( no_rotation.real().i(), 0.0f );
189 CHECK_IF_EQUAL( no_rotation.real().j(), 0.0f );
190 CHECK_IF_EQUAL( no_rotation.real().k(), 0.0f );
191
192 // Translation Part
193 assert( no_rotation.dual().isZero() );
194
195 // Rotate 0 around Y axis
196 no_rotation = DualQuaternionf::make_rotation( Quaternionf::make_rotation(0.0_deg_f, Vector3Df::unit_y()) );
197
198 // Rotation part is a unit quaternion
199 CHECK_IF_EQUAL( no_rotation.real().norm(), 1.0f );
200 CHECK_IF_EQUAL( no_rotation.real().w(), 1.0f );
201 CHECK_IF_EQUAL( no_rotation.real().i(), 0.0f );
202 CHECK_IF_EQUAL( no_rotation.real().j(), 0.0f );
203 CHECK_IF_EQUAL( no_rotation.real().k(), 0.0f );
204
205 // Translation Part
206 assert( no_rotation.dual().isZero() );
207
208 // Rotate 0 around Z axis
209 no_rotation = DualQuaternionf::make_rotation( Quaternionf::make_rotation(0.0_deg_f, Vector3Df::unit_z()) );
210
211 // Rotation part is a unit quaternion
212 CHECK_IF_EQUAL( no_rotation.real().norm(), 1.0f );
213 CHECK_IF_EQUAL( no_rotation.real().w(), 1.0f );
214 CHECK_IF_EQUAL( no_rotation.real().i(), 0.0f );
215 CHECK_IF_EQUAL( no_rotation.real().j(), 0.0f );
216 CHECK_IF_EQUAL( no_rotation.real().k(), 0.0f );
217
218 // Translation Part
219 assert( no_rotation.dual().isZero() );
220}
221
223{
224 std::cout << __func__ << std::endl;
225
226 Vector3Df x_translation{ 5.0f, 0.0f, 0.0f };
227 DualQuaternionf origin;
228 Quaternionf encoded_translation = 0.5f * Quaternionf{0.0f, x_translation.x, x_translation.y, x_translation.z} * Quaternionf::identity();
229
230 DualQuaternionf result = origin * DualQuaternionf::make_translation(x_translation);
231 Vector3Df output_translation = result.translation();
232
233 // Rotation part should be a "1" as a quaternion
234 assert( result.real().isUnit() );
235 CHECK_IF_EQUAL( result.real().w(), 1.0f );
236 CHECK_IF_EQUAL( result.real().i(), 0.0f );
237 CHECK_IF_EQUAL( result.real().j(), 0.0f );
238 CHECK_IF_EQUAL( result.real().k(), 0.0f );
239
240 // Translation part
241 CHECK_IF_EQUAL( result.dual().w(), 0.0f ); // This should always be 0
242 CHECK_IF_EQUAL( result.dual(), encoded_translation );
243
244 CHECK_IF_EQUAL( output_translation.x, x_translation.x );
245 CHECK_IF_EQUAL( output_translation.y, x_translation.y );
246 CHECK_IF_EQUAL( output_translation.z, x_translation.z );
247}
248
250{
251 std::cout << __func__ << std::endl;
252
253 Vector3Df y_translation{ 0.0f, 17.2f, 0.0f };
254 DualQuaternionf origin;
255 Quaternionf encoded_translation = 0.5f * Quaternionf{0.0f, y_translation.x, y_translation.y, y_translation.z} * Quaternionf::identity();
256
257 DualQuaternionf result = origin * DualQuaternionf::make_translation(y_translation);
258 Vector3Df output_translation = result.translation();
259
260 // Rotation part should be a "1" as a quaternion
261 assert( result.real().isUnit() );
262 CHECK_IF_EQUAL(result.real().w(), 1.0f );
263 CHECK_IF_EQUAL(result.real().i(), 0.0f );
264 CHECK_IF_EQUAL(result.real().j(), 0.0f );
265 CHECK_IF_EQUAL(result.real().k(), 0.0f );
266
267 // Translation part
268 CHECK_IF_EQUAL( result.dual().w(), 0.0f ); // This should always be 0
269 CHECK_IF_EQUAL( result.dual(), encoded_translation );
270
271 CHECK_IF_EQUAL(output_translation.x, y_translation.x );
272 CHECK_IF_EQUAL(output_translation.y, y_translation.y );
273 CHECK_IF_EQUAL(output_translation.z, y_translation.z );
274}
275
277{
278 std::cout << __func__ << std::endl;
279
280 Vector3Df z_translation{ 0.0f, 0.0f, -32.0f };
281 DualQuaternionf origin;
282 Quaternionf encoded_translation = 0.5f * Quaternionf{0.0f, z_translation.x, z_translation.y, z_translation.z} * Quaternionf::identity();
283
284 DualQuaternionf result = origin * DualQuaternionf::make_translation(z_translation);
285 Vector3Df output_translation = result.translation();
286
287 // Rotation part should be a "1" as a quaternion
288 assert( result.real().isUnit());
289 CHECK_IF_EQUAL(result.real().w(), 1.0f );
290 CHECK_IF_EQUAL(result.real().i(), 0.0f );
291 CHECK_IF_EQUAL(result.real().j(), 0.0f );
292 CHECK_IF_EQUAL(result.real().k(), 0.0f );
293
294 // Translation part
295 CHECK_IF_EQUAL(result.dual().w(), 0.0f ); // This should always be 0
296 CHECK_IF_EQUAL( result.dual(), encoded_translation );
297
298 CHECK_IF_EQUAL(output_translation.x, z_translation.x );
299 CHECK_IF_EQUAL(output_translation.y, z_translation.y );
300 CHECK_IF_EQUAL(output_translation.z, z_translation.z );
301}
302
304{
305 std::cout << __func__ << std::endl;
306
307 float input_rotations[] = { 90.0f, 60.0f, 45.0f, 30.0f, -90.0f, -60.0f, -45.0f, -30.0f };
308
309 // X axis
310 for (float degrees : input_rotations)
312
313 // Y axis
314 for (float degrees : input_rotations)
316
317 // Z axis
318 for (float degrees : input_rotations)
320}
321
323{
324 std::cout << __func__ << std::endl;
325
326 Vector3Df vector{ 42.0f, 3.14f, -723.0f };
327
328 assert( DualQuaternionf::make_translation(vector).translation() == vector);
329}
330
338
344
348void Run()
349{
350 std::cout << "Running Dual Quaternion Tests..." << std::endl;
351
361
362 std::cout << "PASSED!" << std::endl;
363}
364}
366
367int main(void)
368{
370 return EXIT_SUCCESS;
371}
int main(void)
void CHECK_IF_EQUAL(float input, float near_to, float tolerance=0.0002f)
Definition Checks.hpp:127
constexpr T DegreesToRadians(T degrees)
Convert degrees to radians.
void CreateRotationAndTestYAxis(float degrees_of_rotation)
void MagnitudeIsTheNumberMultipliedByItsConjugate()
void TranslationIsTheInverseOfMakeTranslation()
void HowToCombineASeparateRotationAndTranslation()
void CreateRotationAndTestZAxis(float degrees_of_rotation)
void MagnitudeOfNormalizedDualQuaternionIsOne()
void CreateRotationAndTestXAxis(float degrees_of_rotation)
Definition Angle.hpp:16