use nalgebra::{Isometry3, Matrix3, Matrix4, Rotation3, Unit, UnitQuaternion, Vector3, Vector4};
use serde::{Serialize, Deserialize};
use crate::utils::utils_se3::implicit_dual_quaternion::ImplicitDualQuaternion;
use crate::utils::utils_se3::optima_rotation::{OptimaRotation, OptimaRotationType};
use crate::utils::utils_se3::optima_se3_pose::{OptimaSE3Pose, OptimaSE3PoseType};
use crate::utils::utils_se3::rotation_and_translation::RotationAndTranslation;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HomogeneousMatrix {
matrix: Matrix4<f64>
}
impl HomogeneousMatrix {
pub fn new(matrix: Matrix4<f64>) -> Self {
Self {
matrix
}
}
pub fn new_from_euler_angles(rx: f64, ry: f64, rz: f64, x: f64, y: f64, z: f64) -> Self {
let rotation = OptimaRotation::new_rotation_matrix_from_euler_angles(rx, ry, rz);
let translation = Vector3::new(x, y, z);
let matrix = Self::rotation_and_translation_to_homogeneous_matrix(&rotation, &translation);
return Self::new(matrix);
}
pub fn new_from_axis_angle(axis: &Unit<Vector3<f64>>, angle: f64, x: f64, y: f64, z: f64) -> Self {
let rotation = OptimaRotation::new_rotation_matrix_from_axis_angle(axis, angle);
let translation = Vector3::new(x, y, z);
let matrix = Self::rotation_and_translation_to_homogeneous_matrix(&rotation, &translation);
return Self::new(matrix);
}
pub fn rotation(&self) -> Rotation3<f64> {
let mut mat3 = Matrix3::zeros();
mat3[(0,0)] = self.matrix[(0,0)];
mat3[(0,1)] = self.matrix[(0,1)];
mat3[(0,2)] = self.matrix[(0,2)];
mat3[(1,0)] = self.matrix[(1,0)];
mat3[(1,1)] = self.matrix[(1,1)];
mat3[(1,2)] = self.matrix[(1,2)];
mat3[(2,0)] = self.matrix[(2,0)];
mat3[(2,1)] = self.matrix[(2,1)];
mat3[(2,2)] = self.matrix[(2,2)];
return Rotation3::from_matrix(&mat3);
}
pub fn translation(&self) -> Vector3<f64> {
let out_vec = Vector3::new(self.matrix[(0,3)], self.matrix[(1,3)], self.matrix[(2,3)]);
return out_vec;
}
pub fn multiply(&self, other: &HomogeneousMatrix) -> HomogeneousMatrix {
let matrix = self.matrix * &other.matrix;
return Self::new(matrix);
}
pub fn multiply_by_point(&self, point: &Vector3<f64>) -> Vector3<f64> {
let four_point = Vector4::new(point[0], point[1], point[2], 1.0);
let result_point = self.matrix * &four_point;
return Vector3::new(result_point[0], result_point[1], result_point[2]);
}
pub fn inverse_multiply_by_point(&self, point: &Vector3<f64>) -> Vector3<f64> {
return self.inverse().multiply_by_point(&point);
}
pub fn inverse(&self) -> Self {
let mut matrix = Matrix4::zeros();
let rot_mat = self.rotation();
let rot_mat_transpose = rot_mat.transpose();
let translation = self.translation();
let new_translation = rot_mat_transpose * &translation;
matrix[(0,0)] = rot_mat_transpose[(0,0)];
matrix[(0,1)] = rot_mat_transpose[(0,1)];
matrix[(0,2)] = rot_mat_transpose[(0,2)];
matrix[(1,0)] = rot_mat_transpose[(1,0)];
matrix[(1,1)] = rot_mat_transpose[(1,1)];
matrix[(1,2)] = rot_mat_transpose[(1,2)];
matrix[(2,0)] = rot_mat_transpose[(2,0)];
matrix[(2,1)] = rot_mat_transpose[(2,1)];
matrix[(2,2)] = rot_mat_transpose[(2,2)];
matrix[(0,3)] = -new_translation[0];
matrix[(1,3)] = -new_translation[1];
matrix[(2,3)] = -new_translation[2];
matrix[(3,3)] = 1.0;
return Self::new(matrix);
}
pub fn displacement(&self, other: &HomogeneousMatrix) -> HomogeneousMatrix {
return self.inverse().multiply(&other);
}
pub fn displacement_separate_rotation_and_translation(&self, other: &HomogeneousMatrix) -> (OptimaRotation, Vector3<f64>) {
let disp_rotation = OptimaRotation::new_rotation_matrix(self.rotation().clone()).displacement(&OptimaRotation::new_rotation_matrix(other.rotation().clone()), false).expect("error");
let disp_translation = other.translation() - self.translation();
return (disp_rotation, disp_translation);
}
pub fn slerp(&self, other: &HomogeneousMatrix, t: f64) -> HomogeneousMatrix {
let new_rot = OptimaRotation::new_rotation_matrix(self.rotation().slerp(&other.rotation(), t));
let new_translation = (1.0 - t) * self.translation() + t * other.translation();
let matrix = Self::rotation_and_translation_to_homogeneous_matrix(&new_rot, &new_translation);
return Self::new(matrix);
}
pub fn approximate_distance(&self, other: &HomogeneousMatrix) -> f64 {
let angle_between = self.rotation().angle_to(&other.rotation());
let translation_between = (self.translation() - other.translation()).norm();
return angle_between + translation_between;
}
pub fn rotation_and_translation_to_homogeneous_matrix(rotation: &OptimaRotation, translation: &Vector3<f64>) -> Matrix4<f64> {
let rot_mat = rotation.convert(&OptimaRotationType::RotationMatrix)
.unwrap_rotation_matrix()
.expect("error")
.clone();
let mut out_mat = Matrix4::zeros();
out_mat[(0,0)] = rot_mat[(0,0)];
out_mat[(0,1)] = rot_mat[(0,1)];
out_mat[(0,2)] = rot_mat[(0,2)];
out_mat[(1,0)] = rot_mat[(1,0)];
out_mat[(1,1)] = rot_mat[(1,1)];
out_mat[(1,2)] = rot_mat[(1,2)];
out_mat[(2,0)] = rot_mat[(2,0)];
out_mat[(2,1)] = rot_mat[(2,1)];
out_mat[(2,2)] = rot_mat[(2,2)];
out_mat[(0,3)] = translation[0];
out_mat[(1,3)] = translation[1];
out_mat[(2,3)] = translation[2];
out_mat[(3,3)] = 1.0;
return out_mat;
}
pub fn homogeneous_matrix_to_rotation_and_translation(mat: &Matrix4<f64>) -> (OptimaRotation, Vector3<f64>) {
let mut mat3 = Matrix3::zeros();
mat3[(0,0)] = mat[(0,0)];
mat3[(0,1)] = mat[(0,1)];
mat3[(0,2)] = mat[(0,2)];
mat3[(1,0)] = mat[(1,0)];
mat3[(1,1)] = mat[(1,1)];
mat3[(1,2)] = mat[(1,2)];
mat3[(2,0)] = mat[(2,0)];
mat3[(2,1)] = mat[(2,1)];
mat3[(2,2)] = mat[(2,2)];
let rot3 = Rotation3::from_matrix(&mat3);
let quat = UnitQuaternion::from_rotation_matrix(&rot3);
let rotation = OptimaRotation::new_unit_quaternion(quat);
let translation = Vector3::new(mat[(0,3)], mat[(1,3)], mat[(2,3)]);
return (rotation, translation);
}
pub fn to_euler_angles_and_translation(&self) -> (Vector3<f64>, Vector3<f64>) {
let rotation = self.rotation();
let euler_angles = rotation.euler_angles();
let euler_angles_vec = Vector3::new(euler_angles.0, euler_angles.1, euler_angles.2);
return (euler_angles_vec, self.translation());
}
pub fn to_axis_angle_and_translation(&self) -> (Vector3<f64>, f64, Vector3<f64>) {
let axis_angle = self.rotation().axis_angle();
let (axis, angle) = match axis_angle {
None => { (Vector3::new(0.,0.,0.), 0.0) }
Some(axis_angle) => { (Vector3::new(axis_angle.0[0], axis_angle.0[1], axis_angle.0[2]), axis_angle.1) }
};
return (axis, angle, self.translation().clone());
}
pub fn to_nalgebra_isometry(&self) -> Isometry3<f64> {
let axis = self.rotation().scaled_axis();
return Isometry3::new(self.translation(), axis);
}
pub fn convert(&self, target_type: &OptimaSE3PoseType) -> OptimaSE3Pose {
return match target_type {
OptimaSE3PoseType::ImplicitDualQuaternion => {
let rotation = UnitQuaternion::from_rotation_matrix(&self.rotation());
let translation = self.translation();
let data = ImplicitDualQuaternion::new(rotation, translation);
OptimaSE3Pose::new_implicit_dual_quaternion(data)
}
OptimaSE3PoseType::HomogeneousMatrix => {
OptimaSE3Pose::new_homogeneous_matrix(self.clone())
}
OptimaSE3PoseType::UnitQuaternionAndTranslation => {
let rotation = OptimaRotation::new_unit_quaternion(UnitQuaternion::from_rotation_matrix(&self.rotation()));
let translation = self.translation();
let data = RotationAndTranslation::new(rotation, translation);
OptimaSE3Pose::new_rotation_and_translation(data)
}
OptimaSE3PoseType::RotationMatrixAndTranslation => {
let rotation_matrix = self.rotation();
let translation = self.translation();
let data = RotationAndTranslation::new(OptimaRotation::new_rotation_matrix(rotation_matrix), translation);
OptimaSE3Pose::new_rotation_and_translation(data)
}
OptimaSE3PoseType::EulerAnglesAndTranslation => {
let euler_angles_and_rotation = self.to_euler_angles_and_translation();
let e = &euler_angles_and_rotation.0;
let t = &euler_angles_and_rotation.1;
return OptimaSE3Pose::EulerAnglesAndTranslation {
euler_angles: e.clone(),
translation: t.clone(),
phantom_data: self.convert(&OptimaSE3PoseType::ImplicitDualQuaternion).unwrap_implicit_dual_quaternion().expect("error").clone(),
pose_type: OptimaSE3PoseType::EulerAnglesAndTranslation
}
}
}
}
pub fn to_vec_representation(&self) -> Vec<Vec<f64>> {
let mut out_vec = vec![];
for i in 0..4 {
let mut tmp_vec = vec![];
for j in 0..4 {
tmp_vec.push(self.matrix[(i,j)]);
}
out_vec.push(tmp_vec);
}
out_vec
}
}