use crate::{List, Vector, Vectors, VectorsGeneric};
use itertools::multizip;
use na::{storage::Storage, Dynamic, RealField, U3};
use num_traits::{cast, NumCast};
pub fn magnitudes<T, S>(vectors: &VectorsGeneric<T, S>) -> List<T>
where
T: RealField,
S: Storage<T, U3, Dynamic>,
{
let size = crate::number_vectors(vectors);
let mut magnitudes = List::<T>::zeros(size);
for (res, vector) in multizip((magnitudes.iter_mut(), vectors.column_iter())) {
*res = vector.norm();
}
magnitudes
}
pub fn distances<T>(vectors_1: &Vectors<T>, vectors_2: &Vectors<T>) -> List<T>
where
T: RealField,
{
magnitudes(&(vectors_2 - vectors_1))
}
pub fn distance<T>(vector_1: &Vector<T>, vector_2: &Vector<T>) -> T
where
T: RealField,
{
(vector_2 - vector_1).norm()
}
pub fn units<T>(vectors: &Vectors<T>) -> Vectors<T>
where
T: RealField,
{
let size = crate::number_vectors(vectors);
let mut directions = Vectors::zeros(size);
for (mut direction, vector) in multizip((directions.column_iter_mut(), vectors.column_iter())) {
direction.copy_from(&vector.normalize());
}
directions
}
pub fn directions<T>(vectors_1: &Vectors<T>, vectors_2: &Vectors<T>) -> Vectors<T>
where
T: RealField,
{
units(&(vectors_2 - vectors_1))
}
pub fn direction<T>(vector_1: &Vector<T>, vector_2: &Vector<T>) -> Vector<T>
where
T: RealField,
{
(vector_2 - vector_1).normalize()
}
pub fn cart_to_sph<T, S>(vectors: &VectorsGeneric<T, S>) -> Vectors<T>
where
T: RealField + NumCast,
S: Storage<T, U3, Dynamic>,
{
let size = vectors.ncols();
let mut sphericals = Vectors::zeros(size);
for (mut spherical, cartesian) in
multizip((sphericals.column_iter_mut(), vectors.column_iter()))
{
if relative_eq!(cast::<T, f64>(cartesian.norm()).unwrap(), 0.0) {
spherical.copy_from(&Vector::<T>::zeros());
} else {
spherical.copy_from_slice(&[
cartesian[1].atan2(cartesian[0]),
(cartesian[2] / cartesian.norm()).asin(),
cartesian.norm(),
]);
}
}
sphericals
}
pub fn dot_products<T>(vectors_1: &Vectors<T>, vectors_2: &Vectors<T>) -> List<T>
where
T: RealField,
{
let size = crate::number_vectors(vectors_1);
let mut dot_products = List::<T>::zeros(size);
for (res, vector_1, vector_2) in multizip((
dot_products.iter_mut(),
vectors_1.column_iter(),
vectors_2.column_iter(),
)) {
*res = vector_1.dot(&vector_2);
}
dot_products
}
pub fn projection_vector<T>(vector_1: &Vector<T>, vector_2: &Vector<T>) -> Vector<T>
where
T: RealField,
{
vector_2 * vector_1.dot(vector_2) / vector_2.norm().powi(2)
}
pub fn projection_plane<T>(vector_1: &Vector<T>, vector_2: &Vector<T>) -> Vector<T>
where
T: RealField,
{
vector_1 - projection_vector(vector_1, vector_2)
}
pub fn direct_angle<T>(v1: &Vector<T>, v2: &Vector<T>, up: &Vector<T>) -> T
where
T: RealField,
{
let mut ang = v1.angle(v2);
let normal = v1.cross(v2);
let test = up.dotc(&normal);
if test < T::zero() {
ang = T::two_pi() - ang;
}
ang
}