use nalgebra::{Rotation3, UnitVector3, Vector3};
use std::ops::{Div, Mul};
pub fn get_unit(unit: char) -> UnitVector3<f32> {
match unit {
'i' => Vector3::x_axis(),
'j' => Vector3::y_axis(),
'k' => Vector3::z_axis(),
_ => {
panic!("{} unkown unit vector", unit)
}
}
}
pub fn angle_with_unit_vector(user: Vector3<f32>, unit: char) -> f32 {
let user_length = user.norm();
let unit_lengths = 1.0_f32;
let unit = &get_unit(unit);
user.dot(unit).div(user_length.mul(unit_lengths)).acos()
}
pub fn angle_with_other_vector(user: Vector3<f32>, user_other: Vector3<f32>) -> f32 {
let user_length = user.norm();
let user_o_length = user_other.norm();
user.dot(&user_other)
.div(user_length.mul(user_o_length))
.acos()
}
pub fn get_rotation_matrix(angle: f32, unit: UnitVector3<f32>) -> Rotation3<f32> {
Rotation3::from_axis_angle(&unit, angle)
}
#[cfg(test)]
mod unit_tests {
use super::*;
use std::f32::consts::{FRAC_PI_2, FRAC_PI_4};
#[test]
fn test_angle() {
let test_vector = Vector3::z_axis();
assert_eq!(1.0_f32, test_vector.norm());
assert_eq!(
0.0_f32,
test_vector.dot(&Vector3::new(1.0_f32, 0.0_f32, 0.0_f32))
);
assert_eq!(FRAC_PI_2, angle_with_unit_vector(*test_vector, 'i'));
}
#[test]
fn test_rotation() {
let test_vector = Vector3::z_axis();
let rot_matrix = get_rotation_matrix(FRAC_PI_2, Vector3::y_axis());
assert_relative_eq!(
rot_matrix * test_vector,
Vector3::x_axis(),
epsilon = f32::EPSILON
);
let rot_matrix = get_rotation_matrix(FRAC_PI_4, Vector3::x_axis());
let expected: Vector3<f32> =
Vector3::new(0.0_f32, -(1.0.div(2.0_f32.sqrt())), 1.0.div(2.0_f32.sqrt()));
assert_relative_eq!(
*(rot_matrix * test_vector),
expected,
epsilon = f32::EPSILON
);
}
#[test]
fn test_angle_wo() {
let test_1: Vector3<f32> =
Vector3::new(0.0_f32, -(1.0.div(2.0_f32.sqrt())), 1.0.div(2.0_f32.sqrt()));
let test_2: Vector3<f32> =
Vector3::new(0.0_f32, 1.0.div(2.0_f32.sqrt()), 1.0.div(2.0_f32.sqrt()));
assert_eq!(FRAC_PI_2, angle_with_other_vector(test_1, test_2));
}
}