use cfg_if::cfg_if;
use vqm::{Vector3d, Vector3df32, Vector3df64, Vector3di16};
cfg_if! {
if #[cfg(feature = "no_align")] {
const _: () = assert!(core::mem::size_of::<Vector3di16>() == 8); const _: () = assert!(core::mem::align_of::<Vector3di16>() == 4);
const _: () = assert!(core::mem::size_of::<Vector3df32>() == 12);
const _: () = assert!(core::mem::align_of::<Vector3df32>() == 4);
const _: () = assert!(core::mem::size_of::<Vector3df64>() == 24);
const _: () = assert!(core::mem::align_of::<Vector3df64>() == 8);
} else {
const _: () = assert!(core::mem::size_of::<Vector3di16>() == 16);
const _: () = assert!(core::mem::align_of::<Vector3di16>() == 16);
const _: () = assert!(core::mem::size_of::<Vector3df32>() == 16);
const _: () = assert!(core::mem::align_of::<Vector3df32>() == 16);
const _: () = assert!(core::mem::size_of::<Vector3df64>() == 32);
const _: () = assert!(core::mem::align_of::<Vector3df64>() == 16);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Vector3df32;
use approx::assert_abs_diff_eq;
use core::mem::{align_of, size_of};
use vqm::Quaternionf32;
#[allow(unused)]
fn is_normal<T: Sized + Send + Sync + Unpin>() {}
fn is_full<T: Sized + Send + Sync + Unpin + Copy + Clone + Default + PartialEq>() {}
#[test]
fn normal_types() {
is_full::<Vector3d<f32>>();
}
#[test]
fn default() {
let a: Vector3df32 = Vector3d::default();
assert_eq!(a, Vector3d { x: 0.0, y: 0.0, z: 0.0 });
}
#[test]
fn zero() {
use num_traits::zero;
let _z: Vector3df32 = zero();
}
#[test]
fn vector_memory_layout() {
#[cfg(feature = "no_align")]
assert_eq!(size_of::<Vector3df32>(), 12);
#[cfg(not(feature = "no_align"))]
assert_eq!(size_of::<Vector3df32>(), 16);
#[cfg(feature = "no_align")]
assert_eq!(align_of::<Vector3df32>(), 4);
#[cfg(not(feature = "no_align"))]
assert_eq!(align_of::<Vector3df32>(), 16);
}
#[test]
fn neg_owned() {
let v = Vector3d { x: 1.0, y: -2.0, z: 3.0 };
let neg_v = -v;
assert_eq!(neg_v.x, -1.0);
assert_eq!(neg_v.y, 2.0);
assert_eq!(neg_v.z, -3.0);
}
#[test]
fn neg() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(-a, Vector3d { x: -2.0, y: -3.0, z: -5.0 });
let b = -a;
assert_eq!(b, Vector3d { x: -2.0, y: -3.0, z: -5.0 });
}
#[test]
fn add() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let b = Vector3d { x: 7.0, y: 11.0, z: 13.0 };
assert_eq!(a + b, Vector3d { x: 9.0, y: 14.0, z: 18.0 });
}
#[test]
fn add_assign() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let b = Vector3d { x: 7.0, y: 11.0, z: 13.0 };
let mut c = a;
c += b;
assert_eq!(c, Vector3d { x: 9.0, y: 14.0, z: 18.0 });
}
#[test]
fn sub() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let b = Vector3d { x: 7.0, y: 11.0, z: 17.0 };
let c = a - b;
assert_eq!(c, Vector3d { x: -5.0, y: -8.0, z: -12.0 });
}
#[test]
fn sub_assign() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let b = Vector3d { x: 7.0, y: 11.0, z: 17.0 };
let mut c = a;
c -= b;
assert_eq!(c, Vector3d { x: -5.0, y: -8.0, z: -12.0 });
}
#[test]
fn mul() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a * 2.0, Vector3d { x: 4.0, y: 6.0, z: 10.0 });
assert_eq!(2.0 * a, Vector3d { x: 4.0, y: 6.0, z: 10.0 });
}
#[test]
fn mul_assign() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let mut b = a;
b *= 2.0;
assert_eq!(b, Vector3d { x: 4.0, y: 6.0, z: 10.0 });
}
#[test]
fn div() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a / 2.0, Vector3d { x: 1.0, y: 1.5, z: 2.5 });
}
#[test]
fn div_assign() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let mut b = a;
b /= 2.0;
assert_eq!(b, Vector3d { x: 1.0, y: 1.5, z: 2.5 });
}
#[test]
fn new() {
let a = Vector3d::new(2.0, 3.0, 5.0);
assert_eq!(a, Vector3d { x: 2.0, y: 3.0, z: 5.0 });
let b = Vector3d::from((2.0, 3.0, 5.0));
assert_eq!(a, b);
use num_traits::zero;
let _z: Vector3df32 = zero();
let c: Vector3df32 = (2.0, 3.0, 5.0).into();
assert_eq!(a, c);
let d = Vector3d::from((2.0, 3.0, 5.0));
assert_eq!(a, d);
let e: Vector3df32 = [2.0, 3.0, 5.0].into();
assert_eq!(a, e);
let f = Vector3df32::from([2.0, 3.0, 5.0]);
assert_eq!(a, f);
let h = <[f32; 3]>::from(a);
assert_eq!([2.0, 3.0, 5.0], h);
let i: [f32; 3] = a.into();
assert_eq!([2.0, 3.0, 5.0], i);
}
#[test]
fn norm_squared() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a.norm_squared(), 38.0);
}
#[test]
fn norm() {
let a = Vector3d { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a.norm(), 38.0_f32.sqrt());
let z = Vector3d { x: 0.0, y: 0.0, z: 0.0 };
assert_eq!(z.norm(), 0.0);
}
#[test]
fn normalized_unchecked() {
let a = Vector3d { x: 2.0, y: 3.0, z: 5.0 };
let b = a / 38.0_f32.sqrt();
assert_eq!(a.normalize_unchecked(), b);
let z = Vector3d { x: 0.0, y: 0.0, z: 0.0 };
assert_eq!(z.normalize(), z);
}
#[test]
fn abs() {
let a = Vector3df32 { x: -2.0, y: -3.0, z: -5.0 };
assert_eq!(a.abs(), Vector3d { x: 2.0, y: 3.0, z: 5.0 });
}
#[test]
fn abs_in_place() {
let a = Vector3df32 { x: -2.0, y: -3.0, z: -5.0 };
let mut b = a;
b.abs_in_place();
assert_eq!(b, a.abs());
}
#[test]
fn clamped() {
let a = Vector3d { x: -2.0, y: 3.0, z: 5.0 };
assert_eq!(a.clamp(-1.0, 4.0), Vector3d { x: -1.0, y: 3.0, z: 4.0 });
}
#[test]
fn clamp() {
let a = Vector3d { x: 2.0, y: 3.0, z: 5.0 };
let mut b = a;
b.clamp_in_place(-1.0, 4.0);
assert_eq!(b, a.clamp(-1.0, 4.0));
}
#[test]
fn degrees_radians() {
use vqm::MathConstants;
let a = Vector3df32 { x: f32::FRAC_PI_2, y: f32::FRAC_PI_4, z: f32::FRAC_PI_6 };
let b = a.to_degrees();
assert_eq!(b, Vector3df32::new(90.0, 45.0, 30.0));
}
#[test]
fn sum() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a.sum(), 10.0);
let a = Vector3di16 { x: 2, y: 3, z: 5 };
assert_eq!(a.sum(), 10);
}
#[test]
fn mean() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a.mean(), 10.0 / 3.0);
}
#[test]
fn product() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
assert_eq!(a.product(), 30.0);
let a = Vector3di16 { x: 2, y: 3, z: 5 };
assert_eq!(a.product(), 30);
}
#[test]
fn dot() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let b = Vector3df32 { x: 7.0, y: 11.0, z: 13.0 };
assert_eq!(a.dot(a), 38.0);
assert_eq!(a.dot(b), 112.0);
assert_eq!(b.dot(a), 112.0);
assert_eq!(b.dot(b), 339.0);
let v1 = Vector3df32::new(1.0, 2.0, 3.0);
let v2 = Vector3df32::new(4.0, 5.0, 6.0);
assert_eq!(v1.dot(v2), 32.0);
let a = Vector3di16 { x: 2, y: 3, z: 5 };
let b = Vector3di16 { x: 7, y: 11, z: 13 };
assert_eq!(a.dot(a), 38);
assert_eq!(a.dot(b), 112);
assert_eq!(b.dot(a), 112);
assert_eq!(b.dot(b), 339);
}
#[test]
fn normalize_unchecked() {
let a = Vector3df32 { x: 2.0, y: 3.0, z: 5.0 };
let a_normalized = a.normalize_unchecked();
let mut b = a;
b.normalize_unchecked_in_place();
assert_eq!(b, a_normalized);
let z = Vector3df32 { x: 0.0, y: 0.0, z: 0.0 };
let mut y = z;
y.normalize_in_place();
assert_eq!(z, y);
}
#[test]
fn is_normalized() {
let a = Vector3df32::new(0.0067734555, 0.016385008, 0.0053294576);
let n = a.normalize();
assert!(n.is_normalized());
}
#[test]
fn quaternion_rotation_90_deg() {
let v = Vector3d::new(1.0, 0.0, 0.0);
let half_angle = core::f32::consts::FRAC_PI_4;
let q = Quaternionf32 { x: 0.0, y: 0.0, z: half_angle.sin(), w: half_angle.cos() };
let result = v.rotate_by(q);
assert_abs_diff_eq!(result.x, 0.0, epsilon = 1e-6);
assert_abs_diff_eq!(result.y, 1.0, epsilon = 1e-6);
assert_abs_diff_eq!(result.z, 0.0, epsilon = 1e-6);
}
#[test]
fn quaternion_rotation_arbitrary() {
let v = Vector3d::new(1.2, -3.4, 5.6);
let q = Quaternionf32 { x: 0.1, y: 0.2, z: 0.3, w: 0.9273618 };
let _result = v.rotate_by(q);
}
#[test]
fn rotation_round_trip() {
use approx::assert_abs_diff_eq;
let original_v = Vector3d::new(10.5, -2.0, 44.1);
let q = Quaternionf32 { x: 0.1, y: 0.2, z: 0.3, w: 0.9273618 };
let world_v = original_v.rotate_by(q);
let body_v = world_v.rotate_back_by(q);
assert_abs_diff_eq!(body_v.x, original_v.x, epsilon = 1e-5);
assert_abs_diff_eq!(body_v.y, original_v.y, epsilon = 1e-5);
assert_abs_diff_eq!(body_v.z, original_v.z, epsilon = 1e-5);
}
#[test]
fn vector3df32_array_i16() {
let v = Vector3df32::from([2.1, 3.8, 5.2]);
let a = <[i16; 3]>::from(v);
let b: [i16; 3] = v.into();
assert_eq!(a, [2, 3, 5]);
assert_eq!(b, [2, 3, 5]);
}
#[test]
fn filter_vector3di16_i32() {
use filters::{Pt1Filter, SignalFilter};
let mut filter = Pt1Filter::<Vector3d<i16>, i32>::new(1);
let output = filter.update(Vector3di16 { x: 2, y: 3, z: 5 });
assert_eq!(Vector3di16 { x: 2, y: 3, z: 5 }, output);
}
#[test]
fn pt1_filter_vector3di16_f32() {
use filters::{Pt1Filter, SignalFilter};
let mut filter = Pt1Filter::<Vector3di16, f32>::new(1.0);
let output = filter.update(Vector3di16 { x: 2, y: 3, z: 5 });
assert_eq!(Vector3di16 { x: 2, y: 3, z: 5 }, output);
}
}