use core::iter::Sum;
use core::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
use crate::Scalar;
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T: ::core::marker::Copy> ::core::marker::Copy for Vector3<T> {}
impl<T: ::core::clone::Clone> ::core::clone::Clone for Vector3<T> {
#[inline]
fn clone(&self) -> Self {
Self {
x: self.x.clone(),
y: self.y.clone(),
z: self.z.clone(),
}
}
}
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Vector3<T> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
f.debug_struct("Vector3")
.field("x", &self.x)
.field("y", &self.y)
.field("z", &self.z)
.finish()
}
}
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Vector3<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl<T> Vector3<T> {
#[inline]
pub const fn new(x: T, y: T, z: T) -> Self {
Self { x, y, z }
}
#[inline]
pub fn from_array(array: [T; 3]) -> Self {
let [x, y, z] = array;
Self { x, y, z }
}
#[inline]
pub fn to_array(self) -> [T; 3] {
[self.x, self.y, self.z]
}
#[inline]
pub fn with_x(self, x: T) -> Self {
Self {
x,
y: self.y,
z: self.z,
}
}
#[inline]
pub fn with_y(self, y: T) -> Self {
Self {
x: self.x,
y,
z: self.z,
}
}
#[inline]
pub fn with_z(self, z: T) -> Self {
Self {
x: self.x,
y: self.y,
z,
}
}
#[inline]
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Vector3<U> {
Vector3 {
x: f(self.x),
y: f(self.y),
z: f(self.z),
}
}
#[inline]
pub fn zip_map<U, R, F: FnMut(T, U) -> R>(self, rhs: Vector3<U>, mut f: F) -> Vector3<R> {
Vector3 {
x: f(self.x, rhs.x),
y: f(self.y, rhs.y),
z: f(self.z, rhs.z),
}
}
}
impl<T: Copy> Vector3<T> {
#[inline]
pub const fn splat(value: T) -> Self {
Self {
x: value,
y: value,
z: value,
}
}
#[inline]
pub fn from_slice(slice: &[T]) -> Self {
Self {
x: slice[0],
y: slice[1],
z: slice[2],
}
}
}
impl<T> Index<usize> for Vector3<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!("index out of bounds: Vector3 has 3 components but the index is {index}"),
}
}
}
impl<T> IndexMut<usize> for Vector3<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!("index out of bounds: Vector3 has 3 components but the index is {index}"),
}
}
}
impl<T: Default> Default for Vector3<T> {
#[inline]
fn default() -> Self {
Self {
x: T::default(),
y: T::default(),
z: T::default(),
}
}
}
impl<T: Neg<Output = T>> Neg for Vector3<T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::new(-self.x, -self.y, -self.z)
}
}
impl<T: Add<Output = T>> Add for Vector3<T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
}
}
impl<T: AddAssign> AddAssign for Vector3<T> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
self.z += rhs.z;
}
}
impl<T: Sub<Output = T>> Sub for Vector3<T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
}
}
impl<T: SubAssign> SubAssign for Vector3<T> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y;
self.z -= rhs.z;
}
}
impl<T, S: Scalar> Mul<S> for Vector3<T>
where
T: Mul<S, Output = T>,
{
type Output = Self;
#[inline]
fn mul(self, rhs: S) -> Self {
Self::new(self.x * rhs, self.y * rhs, self.z * rhs)
}
}
impl<T, S: Scalar> MulAssign<S> for Vector3<T>
where
T: MulAssign<S>,
{
#[inline]
fn mul_assign(&mut self, rhs: S) {
self.x *= rhs;
self.y *= rhs;
self.z *= rhs;
}
}
impl<T, S: Scalar> Div<S> for Vector3<T>
where
T: Div<S, Output = T>,
{
type Output = Self;
#[inline]
fn div(self, rhs: S) -> Self {
Self::new(self.x / rhs, self.y / rhs, self.z / rhs)
}
}
impl<T, S: Scalar> DivAssign<S> for Vector3<T>
where
T: DivAssign<S>,
{
#[inline]
fn div_assign(&mut self, rhs: S) {
self.x /= rhs;
self.y /= rhs;
self.z /= rhs;
}
}
impl<T: Add<Output = T> + Default + Copy> Sum for Vector3<T> {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::default(), |acc, v| acc + v)
}
}
impl<'a, T: Add<Output = T> + Default + Copy> Sum<&'a Vector3<T>> for Vector3<T> {
#[inline]
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
iter.copied().fold(Self::default(), |acc, v| acc + v)
}
}
impl<T: Add<Output = T>> Vector3<T> {
#[inline]
pub fn element_sum(self) -> T {
self.x + self.y + self.z
}
}
impl<T: Add<Output = T> + Sub<Output = T> + Copy> Vector3<T> {
#[inline]
pub fn lerp<S: Scalar>(self, rhs: Self, t: S) -> Self
where
T: Mul<S, Output = T>,
{
self + (rhs - self) * t
}
}
impl<V: Scalar> Vector3<V> {
pub const ZERO: Self = Self::new(V::ZERO, V::ZERO, V::ZERO);
pub const ONE: Self = Self::new(V::ONE, V::ONE, V::ONE);
pub const X: Self = Self::new(V::ONE, V::ZERO, V::ZERO);
pub const Y: Self = Self::new(V::ZERO, V::ONE, V::ZERO);
pub const Z: Self = Self::new(V::ZERO, V::ZERO, V::ONE);
#[inline]
pub fn dot(self, rhs: Self) -> V {
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
}
#[inline]
pub fn cross(self, rhs: Self) -> Self {
Self::new(
self.y * rhs.z - self.z * rhs.y,
self.z * rhs.x - self.x * rhs.z,
self.x * rhs.y - self.y * rhs.x,
)
}
#[inline]
pub fn norm_squared(self) -> V {
self.dot(self)
}
#[inline]
pub fn norm(self) -> V {
self.norm_squared().sqrt()
}
#[inline]
pub fn normalize(self) -> Self {
self / self.norm()
}
#[inline]
pub fn try_normalize(self) -> Option<Self> {
let norm = self.norm();
if norm.is_finite() && norm > V::ZERO {
Some(self / norm)
} else {
None
}
}
#[inline]
pub fn normalize_or_zero(self) -> Self {
self.try_normalize().unwrap_or(Self::ZERO)
}
#[inline]
pub fn is_normalized(self) -> bool {
(self.norm_squared() - V::ONE).abs() <= V::from_f64(2.0e-4)
}
#[inline]
pub fn angle_between(self, rhs: Self) -> V {
self.cross(rhs).norm().atan2(self.dot(rhs))
}
#[inline]
pub fn project_onto(self, onto: Self) -> Self {
onto * (self.dot(onto) / onto.norm_squared())
}
#[inline]
pub fn reject_from(self, from: Self) -> Self {
self - self.project_onto(from)
}
#[inline]
pub fn reflect(self, normal: Self) -> Self {
self - normal * (self.dot(normal) * (V::ONE + V::ONE))
}
#[inline]
pub fn recip(self) -> Self {
Self::new(self.x.recip(), self.y.recip(), self.z.recip())
}
#[inline]
pub fn element_product(self) -> V {
self.x * self.y * self.z
}
#[inline]
pub fn abs(self) -> Self {
Self::new(self.x.abs(), self.y.abs(), self.z.abs())
}
#[inline]
pub fn min(self, rhs: Self) -> Self {
Self::new(self.x.min(rhs.x), self.y.min(rhs.y), self.z.min(rhs.z))
}
#[inline]
pub fn max(self, rhs: Self) -> Self {
Self::new(self.x.max(rhs.x), self.y.max(rhs.y), self.z.max(rhs.z))
}
#[inline]
pub fn clamp(self, min: Self, max: Self) -> Self {
Self::new(
self.x.clamp(min.x, max.x),
self.y.clamp(min.y, max.y),
self.z.clamp(min.z, max.z),
)
}
#[inline]
pub fn min_element(self) -> V {
self.x.min(self.y).min(self.z)
}
#[inline]
pub fn max_element(self) -> V {
self.x.max(self.y).max(self.z)
}
#[inline]
pub fn floor(self) -> Self {
Self::new(self.x.floor(), self.y.floor(), self.z.floor())
}
#[inline]
pub fn ceil(self) -> Self {
Self::new(self.x.ceil(), self.y.ceil(), self.z.ceil())
}
#[inline]
pub fn round(self) -> Self {
Self::new(self.x.round(), self.y.round(), self.z.round())
}
#[inline]
pub fn round_ties_even(self) -> Self {
Self::new(
self.x.round_ties_even(),
self.y.round_ties_even(),
self.z.round_ties_even(),
)
}
#[inline]
pub fn trunc(self) -> Self {
Self::new(self.x.trunc(), self.y.trunc(), self.z.trunc())
}
#[inline]
pub fn fract(self) -> Self {
Self::new(self.x.fract(), self.y.fract(), self.z.fract())
}
#[inline]
pub fn copysign(self, sign: Self) -> Self {
Self::new(
self.x.copysign(sign.x),
self.y.copysign(sign.y),
self.z.copysign(sign.z),
)
}
#[inline]
pub fn signum(self) -> Self {
Self::new(self.x.signum(), self.y.signum(), self.z.signum())
}
#[inline]
pub fn rem_euclid(self, rhs: Self) -> Self {
Self::new(
self.x.rem_euclid(rhs.x),
self.y.rem_euclid(rhs.y),
self.z.rem_euclid(rhs.z),
)
}
#[inline]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
}
#[inline]
pub fn is_infinite(self) -> bool {
self.x.is_infinite() || self.y.is_infinite() || self.z.is_infinite()
}
#[inline]
pub fn is_nan(self) -> bool {
self.x.is_nan() || self.y.is_nan() || self.z.is_nan()
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::f64::consts::FRAC_PI_2;
use core::iter;
#[test]
fn new() {
let v = Vector3::new(1.0, 2.0, 3.0);
assert_eq!((v.x, v.y, v.z), (1.0, 2.0, 3.0));
}
#[test]
fn from_array() {
assert_eq!(
Vector3::from_array([1.0, 2.0, 3.0]),
Vector3::new(1.0, 2.0, 3.0)
);
}
#[test]
fn to_array() {
assert_eq!(Vector3::new(1.0, 2.0, 3.0).to_array(), [1.0, 2.0, 3.0]);
}
#[test]
fn splat() {
assert_eq!(Vector3::splat(5.0), Vector3::new(5.0, 5.0, 5.0));
}
#[test]
fn from_slice() {
assert_eq!(
Vector3::from_slice(&[1.0, 2.0, 3.0, 4.0]),
Vector3::new(1.0, 2.0, 3.0)
);
}
#[test]
#[should_panic]
fn from_slice_panics_when_too_short() {
Vector3::<f64>::from_slice(&[1.0, 2.0]);
}
#[test]
fn with_x() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).with_x(9.0),
Vector3::new(9.0, 2.0, 3.0)
);
}
#[test]
fn with_y() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).with_y(9.0),
Vector3::new(1.0, 9.0, 3.0)
);
}
#[test]
fn with_z() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).with_z(9.0),
Vector3::new(1.0, 2.0, 9.0)
);
}
#[test]
fn map() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).map(|c| c * 2.0),
Vector3::new(2.0, 4.0, 6.0)
);
}
#[test]
fn zip_map() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).zip_map(Vector3::new(4.0, 5.0, 6.0), |a, b| a + b),
Vector3::new(5.0, 7.0, 9.0)
);
}
#[test]
fn default_is_zero() {
assert_eq!(Vector3::<f64>::default(), Vector3::new(0.0, 0.0, 0.0));
}
#[test]
fn copy_and_clone() {
let a = Vector3::new(1.0, 2.0, 3.0);
let b = a;
let c = ::core::clone::Clone::clone(&a);
assert_eq!(a, b);
assert_eq!(a, c);
}
#[test]
fn eq() {
let a = Vector3::new(1.0, 2.0, 3.0);
assert_eq!(a, Vector3::new(1.0, 2.0, 3.0));
assert_ne!(a, Vector3::new(1.0, 2.0, 4.0));
}
#[test]
fn debug() {
assert_eq!(
format!("{:?}", Vector3::new(1.0, 2.0, 3.0)),
"Vector3 { x: 1.0, y: 2.0, z: 3.0 }"
);
}
#[test]
fn index() {
let v = Vector3::new(1.0, 2.0, 3.0);
assert_eq!((v[0], v[1], v[2]), (1.0, 2.0, 3.0));
}
#[test]
fn index_mut() {
let mut v = Vector3::new(1.0, 2.0, 3.0);
v[1] = 9.0;
assert_eq!(v.y, 9.0);
}
#[test]
#[should_panic]
fn index_panics_when_out_of_bounds() {
let _ = Vector3::new(1.0, 2.0, 3.0)[3];
}
#[test]
#[should_panic]
fn index_mut_panics_when_out_of_bounds() {
Vector3::new(1.0, 2.0, 3.0)[3] = 0.0;
}
#[test]
fn constants() {
assert_eq!(Vector3::<f64>::ZERO, Vector3::new(0.0, 0.0, 0.0));
assert_eq!(Vector3::<f64>::ONE, Vector3::new(1.0, 1.0, 1.0));
assert_eq!(Vector3::<f64>::X, Vector3::new(1.0, 0.0, 0.0));
assert_eq!(Vector3::<f64>::Y, Vector3::new(0.0, 1.0, 0.0));
assert_eq!(Vector3::<f64>::Z, Vector3::new(0.0, 0.0, 1.0));
}
#[test]
fn neg() {
assert_eq!(-Vector3::new(1.0, -2.0, 3.0), Vector3::new(-1.0, 2.0, -3.0));
}
#[test]
fn add() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0) + Vector3::new(4.0, 5.0, 6.0),
Vector3::new(5.0, 7.0, 9.0)
);
}
#[test]
fn add_assign() {
let mut v = Vector3::new(1.0, 2.0, 3.0);
v += Vector3::new(4.0, 5.0, 6.0);
assert_eq!(v, Vector3::new(5.0, 7.0, 9.0));
}
#[test]
fn sub() {
assert_eq!(
Vector3::new(4.0, 5.0, 6.0) - Vector3::new(1.0, 2.0, 3.0),
Vector3::new(3.0, 3.0, 3.0)
);
}
#[test]
fn sub_assign() {
let mut v = Vector3::new(4.0, 5.0, 6.0);
v -= Vector3::new(1.0, 2.0, 3.0);
assert_eq!(v, Vector3::new(3.0, 3.0, 3.0));
}
#[test]
fn mul_scalar() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0) * 2.0,
Vector3::new(2.0, 4.0, 6.0)
);
}
#[test]
fn mul_assign_scalar() {
let mut v = Vector3::new(1.0, 2.0, 3.0);
v *= 2.0;
assert_eq!(v, Vector3::new(2.0, 4.0, 6.0));
}
#[test]
fn div_scalar() {
assert_eq!(
Vector3::new(2.0, 4.0, 6.0) / 2.0,
Vector3::new(1.0, 2.0, 3.0)
);
}
#[test]
fn div_assign_scalar() {
let mut v = Vector3::new(2.0, 4.0, 6.0);
v /= 2.0;
assert_eq!(v, Vector3::new(1.0, 2.0, 3.0));
}
#[test]
fn sum_owned() {
let v = [
Vector3::new(1.0, 1.0, 1.0),
Vector3::new(2.0, 2.0, 2.0),
Vector3::new(3.0, 3.0, 3.0),
];
let total: Vector3<f64> = v.iter().copied().sum();
assert_eq!(total, Vector3::new(6.0, 6.0, 6.0));
}
#[test]
fn sum_borrowed() {
let v = [
Vector3::new(1.0, 1.0, 1.0),
Vector3::new(2.0, 2.0, 2.0),
Vector3::new(3.0, 3.0, 3.0),
];
let total: Vector3<f64> = v.iter().sum();
assert_eq!(total, Vector3::new(6.0, 6.0, 6.0));
}
#[test]
fn sum_empty() {
let total: Vector3<f64> = iter::empty::<Vector3<f64>>().sum();
assert_eq!(total, Vector3::new(0.0, 0.0, 0.0));
}
#[test]
fn element_sum() {
assert_eq!(Vector3::new(1.0, 2.0, 3.0).element_sum(), 6.0);
}
#[test]
fn element_product() {
assert_eq!(Vector3::new(2.0, 3.0, 4.0).element_product(), 24.0);
}
#[test]
fn lerp() {
assert_eq!(
Vector3::new(0.0, 0.0, 0.0).lerp(Vector3::new(2.0, 4.0, 6.0), 0.5),
Vector3::new(1.0, 2.0, 3.0)
);
}
#[test]
fn dot() {
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).dot(Vector3::new(4.0, 5.0, 6.0)),
32.0
);
}
#[test]
fn cross() {
assert_eq!(Vector3::<f64>::X.cross(Vector3::Y), Vector3::Z);
assert_eq!(
Vector3::new(1.0, 2.0, 3.0).cross(Vector3::new(4.0, 5.0, 6.0)),
Vector3::new(-3.0, 6.0, -3.0)
);
}
#[test]
fn norm_squared() {
assert_eq!(Vector3::new(1.0, 2.0, 2.0).norm_squared(), 9.0);
}
#[test]
fn norm() {
assert_eq!(Vector3::new(3.0, 4.0, 0.0).norm(), 5.0);
}
#[test]
fn normalize() {
let n = Vector3::new(3.0, 4.0, 0.0).normalize();
assert!((n - Vector3::new(0.6, 0.8, 0.0)).norm() < 1e-12);
}
#[test]
fn try_normalize() {
let n = Vector3::new(3.0, 4.0, 0.0).try_normalize().unwrap();
assert!((n - Vector3::new(0.6, 0.8, 0.0)).norm() < 1e-12);
}
#[test]
fn try_normalize_zero_is_none() {
assert_eq!(Vector3::<f64>::ZERO.try_normalize(), None);
}
#[test]
fn normalize_or_zero() {
let n = Vector3::new(3.0, 4.0, 0.0).normalize_or_zero();
assert!((n - Vector3::new(0.6, 0.8, 0.0)).norm() < 1e-12);
}
#[test]
fn normalize_or_zero_zero_is_zero() {
assert_eq!(Vector3::<f64>::ZERO.normalize_or_zero(), Vector3::ZERO);
}
#[test]
fn is_normalized() {
assert!(Vector3::<f64>::X.is_normalized());
assert!(!Vector3::new(2.0, 0.0, 0.0).is_normalized());
}
#[test]
fn angle_between() {
assert!((Vector3::<f64>::X.angle_between(Vector3::Y) - FRAC_PI_2).abs() < 1e-12);
assert!(Vector3::<f64>::X.angle_between(Vector3::X).abs() < 1e-12);
}
#[test]
fn project_onto() {
assert_eq!(
Vector3::new(2.0, 3.0, 0.0).project_onto(Vector3::X),
Vector3::new(2.0, 0.0, 0.0)
);
}
#[test]
fn reject_from() {
assert_eq!(
Vector3::new(2.0, 3.0, 0.0).reject_from(Vector3::X),
Vector3::new(0.0, 3.0, 0.0)
);
}
#[test]
fn reflect() {
assert_eq!(
Vector3::new(1.0, -1.0, 0.0).reflect(Vector3::Y),
Vector3::new(1.0, 1.0, 0.0)
);
}
#[test]
fn recip() {
assert_eq!(
Vector3::new(2.0, 4.0, 8.0).recip(),
Vector3::new(0.5, 0.25, 0.125)
);
}
#[test]
fn abs() {
assert_eq!(
Vector3::new(-1.0, 2.0, -3.0).abs(),
Vector3::new(1.0, 2.0, 3.0)
);
}
#[test]
fn min() {
assert_eq!(
Vector3::new(1.0, 5.0, 3.0).min(Vector3::new(4.0, 2.0, 6.0)),
Vector3::new(1.0, 2.0, 3.0)
);
}
#[test]
fn max() {
assert_eq!(
Vector3::new(1.0, 5.0, 3.0).max(Vector3::new(4.0, 2.0, 6.0)),
Vector3::new(4.0, 5.0, 6.0)
);
}
#[test]
fn clamp() {
assert_eq!(
Vector3::new(5.0, -1.0, 2.0).clamp(Vector3::splat(0.0), Vector3::splat(3.0)),
Vector3::new(3.0, 0.0, 2.0)
);
}
#[test]
#[should_panic]
fn clamp_panics_when_min_gt_max() {
Vector3::new(1.0, 1.0, 1.0).clamp(Vector3::splat(3.0), Vector3::splat(0.0));
}
#[test]
fn min_element() {
assert_eq!(Vector3::new(3.0, 1.0, 2.0).min_element(), 1.0);
}
#[test]
fn max_element() {
assert_eq!(Vector3::new(3.0, 1.0, 2.0).max_element(), 3.0);
}
#[test]
fn floor() {
assert_eq!(
Vector3::new(1.7, -1.2, 2.0).floor(),
Vector3::new(1.0, -2.0, 2.0)
);
}
#[test]
fn ceil() {
assert_eq!(
Vector3::new(1.2, -1.7, 2.0).ceil(),
Vector3::new(2.0, -1.0, 2.0)
);
}
#[test]
fn round() {
assert_eq!(
Vector3::new(1.5, -1.5, 2.4).round(),
Vector3::new(2.0, -2.0, 2.0)
);
}
#[test]
fn round_ties_even() {
assert_eq!(
Vector3::new(1.5, 2.5, -1.5).round_ties_even(),
Vector3::new(2.0, 2.0, -2.0)
);
}
#[test]
fn trunc() {
assert_eq!(
Vector3::new(1.7, -1.7, 2.0).trunc(),
Vector3::new(1.0, -1.0, 2.0)
);
}
#[test]
fn fract() {
assert_eq!(
Vector3::new(2.5, -1.25, 0.0).fract(),
Vector3::new(0.5, -0.25, 0.0)
);
}
#[test]
fn copysign() {
assert_eq!(
Vector3::new(3.0, -4.0, 5.0).copysign(Vector3::new(-1.0, 1.0, -1.0)),
Vector3::new(-3.0, 4.0, -5.0)
);
}
#[test]
fn signum() {
assert_eq!(
Vector3::new(3.0, -2.0, 5.0).signum(),
Vector3::new(1.0, -1.0, 1.0)
);
}
#[test]
fn rem_euclid() {
assert_eq!(
Vector3::new(-7.0, 7.0, 8.0).rem_euclid(Vector3::splat(3.0)),
Vector3::new(2.0, 1.0, 2.0)
);
}
#[test]
fn is_finite() {
assert!(Vector3::new(1.0, 2.0, 3.0).is_finite());
assert!(!Vector3::new(1.0, f64::INFINITY, 3.0).is_finite());
}
#[test]
fn is_infinite() {
assert!(Vector3::new(1.0, f64::INFINITY, 3.0).is_infinite());
assert!(!Vector3::new(1.0, 2.0, 3.0).is_infinite());
}
#[test]
fn is_nan() {
assert!(Vector3::new(1.0, f64::NAN, 3.0).is_nan());
assert!(!Vector3::new(1.0, 2.0, 3.0).is_nan());
}
#[test]
fn f32_normalize() {
let n = Vector3::<f32>::new(3.0, 4.0, 0.0).normalize();
assert!((n - Vector3::new(0.6, 0.8, 0.0)).norm() < 1e-6);
}
}