use nalgebra::{Isometry3, Unit, Vector3};
use serde::{Serialize, Deserialize};
use crate::utils::utils_errors::OptimaError;
use crate::utils::utils_se3::homogeneous_matrix::HomogeneousMatrix;
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};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RotationAndTranslation {
rotation: OptimaRotation,
translation: Vector3<f64>
}
impl RotationAndTranslation {
pub fn new(rotation: OptimaRotation, translation: Vector3<f64>) -> Self {
Self {
rotation,
translation
}
}
pub fn new_from_euler_angles(rx: f64, ry: f64, rz: f64, x: f64, y: f64, z: f64, rotation_type: &OptimaRotationType) -> Self {
let rotation = match rotation_type {
OptimaRotationType::RotationMatrix => { OptimaRotation::new_rotation_matrix_from_euler_angles(rx, ry, rz) }
OptimaRotationType::UnitQuaternion => { OptimaRotation::new_unit_quaternion_from_euler_angles(rx, ry, rz) }
};
return Self::new(rotation, Vector3::new(x, y, z));
}
pub fn new_from_axis_angle(axis: &Unit<Vector3<f64>>, angle: f64, x: f64, y: f64, z: f64, rotation_type: &OptimaRotationType) -> Self {
let rotation = match rotation_type {
OptimaRotationType::RotationMatrix => { OptimaRotation::new_rotation_matrix_from_axis_angle(axis, angle) }
OptimaRotationType::UnitQuaternion => { OptimaRotation::new_unit_quaternion_from_axis_angle(axis, angle) }
};
return Self::new(rotation, Vector3::new(x, y, z));
}
pub fn rotation(&self) -> &OptimaRotation {
&self.rotation
}
pub fn translation(&self) -> &Vector3<f64> {
&self.translation
}
pub fn multiply(&self, other: &RotationAndTranslation, conversion_if_necessary: bool) -> Result<RotationAndTranslation, OptimaError> {
let rotation = self.rotation.multiply(&other.rotation, conversion_if_necessary)?;
let translation = self.rotation.multiply_by_point(&other.translation) + &self.translation;
return Ok(Self::new(rotation, translation));
}
pub fn multiply_by_point(&self, point: &Vector3<f64>) -> Vector3<f64> {
return self.rotation().multiply_by_point(point) + self.translation();
}
pub fn inverse_multiply_by_point(&self, point: &Vector3<f64>) -> Vector3<f64> {
return self.rotation.inverse().multiply_by_point(&(point - &self.translation));
}
pub fn inverse(&self) -> RotationAndTranslation {
let rotation = self.rotation.inverse();
let translation = rotation.multiply_by_point(&-self.translation);
return Self::new(rotation, translation);
}
pub fn displacement(&self, other: &RotationAndTranslation, conversion_if_necessary: bool) -> Result<RotationAndTranslation, OptimaError> {
return self.inverse().multiply(&other, conversion_if_necessary);
}
pub fn displacement_separate_rotation_and_translation(&self, other: &RotationAndTranslation) -> (OptimaRotation, Vector3<f64>) {
let disp_rotation = self.rotation.displacement(other.rotation(), true).expect("error");
let disp_translation = other.translation - self.translation;
return (disp_rotation, disp_translation);
}
pub fn slerp(&self, other: &RotationAndTranslation, t: f64, conversion_if_necessary: bool) -> Result<RotationAndTranslation, OptimaError> {
let new_rot = self.rotation.slerp(&other.rotation, t, conversion_if_necessary)?;
let new_translation = (1.0 - t) * self.translation + t * other.translation;
return Ok(Self::new(new_rot, new_translation));
}
pub fn approximate_distance(&self, other: &RotationAndTranslation, conversion_if_necessary: bool) -> Result<f64, OptimaError> {
let angle_between = self.rotation().angle_between(other.rotation(), conversion_if_necessary)?;
let translation_between = (self.translation() - other.translation()).norm();
return Ok(angle_between + translation_between);
}
pub fn to_euler_angles_and_translation(&self) -> (Vector3<f64>, Vector3<f64>) {
let rotation = self.rotation();
let euler_angles = rotation.to_euler_angles();
return (euler_angles, self.translation.clone());
}
pub fn to_axis_angle_and_translation(&self) -> (Vector3<f64>, f64, Vector3<f64>) {
let axis_angle = match &self.rotation {
OptimaRotation::RotationMatrix { data, .. } => { data.axis_angle() }
OptimaRotation::UnitQuaternion { data, .. } => { data.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 = match &self.rotation {
OptimaRotation::RotationMatrix { data, .. } => { data.scaled_axis() }
OptimaRotation::UnitQuaternion { data, .. } => { data.scaled_axis() }
};
return Isometry3::new(self.translation.clone(), axis);
}
pub fn convert_rotation_type(&mut self, target_type: &OptimaRotationType) {
self.rotation = self.rotation.convert(target_type);
}
pub fn convert(&self, target_type: &OptimaSE3PoseType) -> OptimaSE3Pose {
return match target_type {
OptimaSE3PoseType::ImplicitDualQuaternion => {
let unit_quaternion = self.rotation().convert(&OptimaRotationType::UnitQuaternion).unwrap_unit_quaternion().expect("error").clone();
let data = ImplicitDualQuaternion::new(unit_quaternion, self.translation().clone());
OptimaSE3Pose::new_implicit_dual_quaternion(data)
}
OptimaSE3PoseType::HomogeneousMatrix => {
let matrix = HomogeneousMatrix::rotation_and_translation_to_homogeneous_matrix(self.rotation(), self.translation());
let data = HomogeneousMatrix::new(matrix);
OptimaSE3Pose::new_homogeneous_matrix(data)
}
OptimaSE3PoseType::UnitQuaternionAndTranslation => {
return match self.rotation() {
OptimaRotation::RotationMatrix { .. } => {
let mut out_rt = self.clone();
out_rt.convert_rotation_type(&OptimaRotationType::UnitQuaternion);
OptimaSE3Pose::new_rotation_and_translation(out_rt)
}
OptimaRotation::UnitQuaternion { .. } => {
OptimaSE3Pose::new_rotation_and_translation(self.clone())
}
}
}
OptimaSE3PoseType::RotationMatrixAndTranslation => {
return match self.rotation() {
OptimaRotation::RotationMatrix { .. } => {
OptimaSE3Pose::new_rotation_and_translation(self.clone())
}
OptimaRotation::UnitQuaternion { .. } => {
let mut out_rt = self.clone();
out_rt.convert_rotation_type(&OptimaRotationType::RotationMatrix);
OptimaSE3Pose::new_rotation_and_translation(out_rt)
}
}
}
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 rotation = self.rotation();
let mut out_vec = rotation.to_vec_representation();
let t = self.translation();
out_vec.push(vec![t[0], t[1], t[2]]);
out_vec
}
}