orbita3d_kinematics/
conversion.rs1use nalgebra::{Quaternion, Rotation3, UnitQuaternion, Vector3};
2
3pub fn quaternion_to_rotation_matrix(qx: f64, qy: f64, qz: f64, qw: f64) -> Rotation3<f64> {
5 Rotation3::from(UnitQuaternion::from_quaternion(Quaternion::new(
6 qw, qx, qy, qz,
7 )))
8}
9
10pub fn rotation_matrix_to_quaternion(rot: Rotation3<f64>) -> [f64; 4] {
12 let q = UnitQuaternion::from_rotation_matrix(&rot);
13 [q.i, q.j, q.k, q.w]
14}
15
16pub fn intrinsic_roll_pitch_yaw_to_matrix(roll: f64, pitch: f64, yaw: f64) -> Rotation3<f64> {
18 let mx = Rotation3::from_axis_angle(&Vector3::x_axis(), roll);
19 let my = Rotation3::from_axis_angle(&Vector3::y_axis(), pitch);
20 let mz = Rotation3::from_axis_angle(&Vector3::z_axis(), yaw);
21
22 mx * my * mz
23}
24
25pub fn matrix_to_intrinsic_roll_pitch_yaw(rot: Rotation3<f64>) -> [f64; 3] {
27 let roll = -rot[(1, 2)].atan2(rot[(2, 2)]);
28 let pitch = rot[(0, 2)].atan2((1.0 - rot[(0, 2)].powf(2.0)).sqrt());
29 let yaw = -rot[(0, 1)].atan2(rot[(0, 0)]);
30
31 [roll, pitch, yaw]
32}
33
34pub fn quaternion_to_roll_pitch_yaw(quat: [f64; 4]) -> [f64; 3] {
41 let q = UnitQuaternion::from_quaternion(Quaternion::new(quat[3], quat[0], quat[1], quat[2]));
42 let mat = q.to_rotation_matrix();
43 matrix_to_intrinsic_roll_pitch_yaw(mat)
44}
45
46pub fn quaternion_to_intrinsic_roll_pitch_yaw(quat: [f64; 4]) -> [f64; 3] {
47 let q = UnitQuaternion::from_quaternion(Quaternion::new(quat[3], quat[0], quat[1], quat[2]));
48 let mat = q.to_rotation_matrix();
49 matrix_to_intrinsic_roll_pitch_yaw(mat)
50}
51
52pub fn vector3_to_array(v: Vector3<f64>) -> [f64; 3] {
54 [v.x, v.y, v.z]
55}
56pub fn array_to_vector3(a: [f64; 3]) -> Vector3<f64> {
58 Vector3::new(a[0], a[1], a[2])
59}
60
61#[cfg(test)]
62mod tests {
63 use rand::Rng;
64 use std::f64::consts::PI;
65
66 use super::*;
67
68 const EPSILON: f64 = 1e-6;
69
70 #[test]
71 fn rpy() {
72 let mut rng = rand::thread_rng();
73
74 let roll = rng.gen_range(-2.0 * PI..2.0 * PI).to_radians();
75 let pitch = rng.gen_range(-2.0 * PI..2.0 * PI).to_radians();
76 let yaw = rng.gen_range(-2.0 * PI..2.0 * PI).to_radians();
77
78 let rot = intrinsic_roll_pitch_yaw_to_matrix(roll, pitch, yaw);
87 let rpy = matrix_to_intrinsic_roll_pitch_yaw(rot);
88
89 assert!((roll - rpy[0]).abs() < EPSILON);
90 assert!((pitch - rpy[1]).abs() < EPSILON);
91 assert!((yaw - rpy[2]).abs() < EPSILON);
92 }
93
94 #[test]
95 fn quat() {
96 let mut rng = rand::thread_rng();
97
98 let roll = rng.gen_range(-2.0 * PI..2.0 * PI).to_radians();
100 let pitch = rng.gen_range(-2.0 * PI..2.0 * PI).to_radians();
101 let yaw = rng.gen_range(-2.0 * PI..2.0 * PI).to_radians();
102 let rot = intrinsic_roll_pitch_yaw_to_matrix(roll, pitch, yaw);
103
104 let quat = rotation_matrix_to_quaternion(rot);
106 let reconstructed = quaternion_to_rotation_matrix(quat[0], quat[1], quat[2], quat[3]);
107
108 for i in 0..3 {
110 for j in 0..3 {
111 assert!((rot[(i, j)] - reconstructed[(i, j)]).abs() < 0.0001);
112 }
113 }
114 }
115}