@@ -52,6 +52,48 @@ TEST(get_transformation_matrix_attitude, test_transformation_matrix_zeros) {
5252 EXPECT_NEAR (0.0 , matrix_norm_diff (expected, transformation_matrix), 0.01 );
5353}
5454
55+ TEST (get_transformation_matrix_attitude_quat,
56+ test_transformation_matrix_unit_quat) {
57+ Eigen::Quaterniond quat = Eigen::Quaterniond::Identity ();
58+ Eigen::Matrix<double , 4 , 3 > transformation_matrix{
59+ get_transformation_matrix_attitude_quat (quat)};
60+ Eigen::Matrix<double , 4 , 3 > expected = Eigen::Matrix<double , 4 , 3 >::Zero ();
61+ expected.bottomRightCorner <3 , 3 >() = 0.5 * Eigen::Matrix3d::Identity ();
62+ EXPECT_NEAR (0.0 , matrix_norm_diff (expected, transformation_matrix), 0.01 );
63+ }
64+
65+ TEST (eigen_vector3d_to_quaternion, zero_vector_returns_identity) {
66+ const Eigen::Vector3d v = Eigen::Vector3d::Zero ();
67+
68+ const Eigen::Quaterniond q = eigen_vector3d_to_quaternion (v);
69+
70+ EXPECT_NEAR (q.w (), 1.0 , 1e-15 );
71+ EXPECT_NEAR (q.x (), 0.0 , 1e-15 );
72+ EXPECT_NEAR (q.y (), 0.0 , 1e-15 );
73+ EXPECT_NEAR (q.z (), 0.0 , 1e-15 );
74+ EXPECT_NEAR (q.norm (), 1.0 , 1e-15 );
75+ }
76+
77+ TEST (eigen_vector3d_to_quaternion, general_vector_matches_axis_angle_formula) {
78+ const Eigen::Vector3d v (0.3 , -0.4 , 0.5 );
79+ const double angle = v.norm ();
80+ const Eigen::Vector3d axis = v / angle;
81+
82+ const double half = 0.5 * angle;
83+ const double c = cos (half);
84+ const double s = sin (half);
85+ const Eigen::Quaterniond expected (c, axis.x () * s, axis.y () * s,
86+ axis.z () * s);
87+
88+ const Eigen::Quaterniond q = eigen_vector3d_to_quaternion (v);
89+
90+ EXPECT_NEAR (q.w (), expected.w (), 1e-12 );
91+ EXPECT_NEAR (q.x (), expected.x (), 1e-12 );
92+ EXPECT_NEAR (q.y (), expected.y (), 1e-12 );
93+ EXPECT_NEAR (q.z (), expected.z (), 1e-12 );
94+ EXPECT_NEAR (q.norm (), 1.0 , 1e-12 );
95+ }
96+
5597// Test that the identity quaternion correctly maps to 0, 0, 0
5698TEST (quat_to_euler, test_quat_to_euler_1) {
5799 Eigen::Quaterniond q (1.0 , 0.0 , 0.0 , 0.0 );
@@ -168,4 +210,69 @@ TEST(euler_to_quat, test_euler_to_quat_5) {
168210 }
169211}
170212
213+ // Test that zero euler angles construct the correct quaternion
214+ TEST (euler_to_quat_vec3, zero_angles_identity_quaternion) {
215+ const Eigen::Vector3d euler (0.0 , 0.0 , 0.0 ); // roll, pitch, yaw
216+ const Eigen::Quaterniond q = euler_to_quat (euler);
217+
218+ const Eigen::Vector4d result{q.x (), q.y (), q.z (), q.w ()};
219+ const Eigen::Vector4d expected (0.0 , 0.0 , 0.0 , 1.0 );
220+
221+ for (int i = 0 ; i < 4 ; ++i) {
222+ EXPECT_NEAR (expected[i], result[i], 0.01 );
223+ }
224+ }
225+
226+ // Test that non-zero roll constructs the correct quaternion
227+ TEST (euler_to_quat_vec3, roll_only) {
228+ const Eigen::Vector3d euler (1.0 , 0.0 , 0.0 ); // roll, pitch, yaw
229+ const Eigen::Quaterniond q = euler_to_quat (euler);
230+
231+ const Eigen::Vector4d result{q.x (), q.y (), q.z (), q.w ()};
232+ const Eigen::Vector4d expected (0.479 , 0.0 , 0.0 , 0.877 );
233+
234+ for (int i = 0 ; i < 4 ; ++i) {
235+ EXPECT_NEAR (expected[i], result[i], 0.01 );
236+ }
237+ }
238+
239+ // Test that non-zero pitch constructs the correct quaternion
240+ TEST (euler_to_quat_vec3, pitch_only) {
241+ const Eigen::Vector3d euler (0.0 , 1.0 , 0.0 );
242+ const Eigen::Quaterniond q = euler_to_quat (euler);
243+
244+ const Eigen::Vector4d result{q.x (), q.y (), q.z (), q.w ()};
245+ const Eigen::Vector4d expected (0.0 , 0.479 , 0.0 , 0.877 );
246+
247+ for (int i = 0 ; i < 4 ; ++i) {
248+ EXPECT_NEAR (expected[i], result[i], 0.01 );
249+ }
250+ }
251+
252+ // Test that non-zero yaw constructs the correct quaternion
253+ TEST (euler_to_quat_vec3, yaw_only) {
254+ const Eigen::Vector3d euler (0.0 , 0.0 , 1.0 );
255+ const Eigen::Quaterniond q = euler_to_quat (euler);
256+
257+ const Eigen::Vector4d result{q.x (), q.y (), q.z (), q.w ()};
258+ const Eigen::Vector4d expected (0.0 , 0.0 , 0.479 , 0.877 );
259+
260+ for (int i = 0 ; i < 4 ; ++i) {
261+ EXPECT_NEAR (expected[i], result[i], 0.01 );
262+ }
263+ }
264+
265+ // Test that non-zero euler angles construct the correct quaternion
266+ TEST (euler_to_quat_vec3, roll_pitch_yaw_all_nonzero) {
267+ const Eigen::Vector3d euler (1.0 , 1.0 , 1.0 );
268+ const Eigen::Quaterniond q = euler_to_quat (euler);
269+
270+ const Eigen::Vector4d result{q.x (), q.y (), q.z (), q.w ()};
271+ const Eigen::Vector4d expected (0.1675 , 0.5709 , 0.1675 , 0.786 );
272+
273+ for (int i = 0 ; i < 4 ; ++i) {
274+ EXPECT_NEAR (expected[i], result[i], 0.01 );
275+ }
276+ }
277+
171278} // namespace vortex::utils::math
0 commit comments